diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..e1d4131 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: node app.js diff --git a/README.md b/README.md new file mode 100644 index 0000000..dd947c2 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Mouse Wheel Data Collector + +Node.js app using mongoose on heroku to collect mouse wheel delta data. diff --git a/app.js b/app.js new file mode 100644 index 0000000..935b675 --- /dev/null +++ b/app.js @@ -0,0 +1,90 @@ +var express = require('express'); +var app = express(); +var stylus = require('stylus'); +var nib = require('nib'); +var useragent = require('useragent'); +var mongoose = require('mongoose'); +mongoose.connect(process.env.mongodburl || 'mongodb://localhost/mousewheeldatacollector'); + +var Schema = mongoose.Schema; + +app.set('port', process.env.PORT || 8080); + +app.use(express.favicon('public/favicon.ico')); +app.use(express.json()); +app.use(express.urlencoded()); +app.use(express.compress()); +app.set('view engine', 'jade'); +app.set('views', __dirname + '/views'); +app.use(stylus.middleware({ src: __dirname + '/public', compile: compile })); +app.use(express.static(__dirname + '/public')); + +app.configure('development', function() { + app.use(express.logger('dev')); + app.use(express.errorHandler({ + dumpExceptions: true, + showStack: true + })); +}); + +app.configure('production', function() { + app.use(express.logger()); + app.use(express.errorHandler()); +}); + +function compile(str, path) { + return stylus(str) + .set('filename', path) + .set('compress', true) + .use(nib()) + .import('nib'); +} + +var CollectorSchema = new Schema({ + useragent: { + family: String, + major: String, + minor: String, + patch: String, + device: { + family: String + }, + os: { + family: String, + major: String, + minor: String, + patch: String + } + }, + delta: { + resolution: Number, + normalized: { + min: Number, + max: Number + }, + raw: { + min: Number, + max: Number + } + } +}); +var Collector = mongoose.model('Collector', CollectorSchema); + +app.get('/', function(req, res) { + var agent = useragent.parse(req.headers['user-agent']); + Collector.find().sort('-_id').limit(15).exec(function(err, docs) { + console.log(docs); + if (err) res.send(500); + else res.render('home', { agent: agent, records: docs }); + }); +}); + +app.post('/', function(req, res) { + var collector = new Collector(req.body); + collector.save(function(err) { + if (err) res.send(431) + else res.send(204) + }); +}); + +app.listen(8080); diff --git a/node_modules/.bin/express b/node_modules/.bin/express new file mode 120000 index 0000000..b741d99 --- /dev/null +++ b/node_modules/.bin/express @@ -0,0 +1 @@ +../express/bin/express \ No newline at end of file diff --git a/node_modules/.bin/jade b/node_modules/.bin/jade new file mode 120000 index 0000000..571fae7 --- /dev/null +++ b/node_modules/.bin/jade @@ -0,0 +1 @@ +../jade/bin/jade \ No newline at end of file diff --git a/node_modules/.bin/stylus b/node_modules/.bin/stylus new file mode 120000 index 0000000..4113f9b --- /dev/null +++ b/node_modules/.bin/stylus @@ -0,0 +1 @@ +../stylus/bin/stylus \ No newline at end of file diff --git a/node_modules/express/.npmignore b/node_modules/express/.npmignore new file mode 100644 index 0000000..caf574d --- /dev/null +++ b/node_modules/express/.npmignore @@ -0,0 +1,9 @@ +.git* +docs/ +examples/ +support/ +test/ +testing.js +.DS_Store +coverage.html +lib-cov diff --git a/node_modules/express/.travis.yml b/node_modules/express/.travis.yml new file mode 100644 index 0000000..cc4dba2 --- /dev/null +++ b/node_modules/express/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - "0.8" + - "0.10" diff --git a/node_modules/express/History.md b/node_modules/express/History.md new file mode 100644 index 0000000..d784c26 --- /dev/null +++ b/node_modules/express/History.md @@ -0,0 +1,1233 @@ +3.4.4 / 2013-10-29 +================== + + * update connect + * update supertest + * update methods + * express(1): replace bodyParser() with urlencoded() and json() #1795 @chirag04 + +3.4.3 / 2013-10-23 +================== + + * update connect + +3.4.2 / 2013-10-18 +================== + + * update connect + * downgrade commander + +3.4.1 / 2013-10-15 +================== + + * update connect + * update commander + * jsonp: check if callback is a function + * router: wrap encodeURIComponent in a try/catch #1735 (@lxe) + * res.format: now includes chraset @1747 (@sorribas) + * res.links: allow multiple calls @1746 (@sorribas) + +3.4.0 / 2013-09-07 +================== + + * add res.vary(). Closes #1682 + * update connect + +3.3.8 / 2013-09-02 +================== + + * update connect + +3.3.7 / 2013-08-28 +================== + + * update connect + +3.3.6 / 2013-08-27 +================== + + * Revert "remove charset from json responses. Closes #1631" (causes issues in some clients) + * add: req.accepts take an argument list + +3.3.4 / 2013-07-08 +================== + + * update send and connect + +3.3.3 / 2013-07-04 +================== + + * update connect + +3.3.2 / 2013-07-03 +================== + + * update connect + * update send + * remove .version export + +3.3.1 / 2013-06-27 +================== + + * update connect + +3.3.0 / 2013-06-26 +================== + + * update connect + * add support for multiple X-Forwarded-Proto values. Closes #1646 + * change: remove charset from json responses. Closes #1631 + * change: return actual booleans from req.accept* functions + * fix jsonp callback array throw + +3.2.6 / 2013-06-02 +================== + + * update connect + +3.2.5 / 2013-05-21 +================== + + * update connect + * update node-cookie + * add: throw a meaningful error when there is no default engine + * change generation of ETags with res.send() to GET requests only. Closes #1619 + +3.2.4 / 2013-05-09 +================== + + * fix `req.subdomains` when no Host is present + * fix `req.host` when no Host is present, return undefined + +3.2.3 / 2013-05-07 +================== + + * update connect / qs + +3.2.2 / 2013-05-03 +================== + + * update qs + +3.2.1 / 2013-04-29 +================== + + * add app.VERB() paths array deprecation warning + * update connect + * update qs and remove all ~ semver crap + * fix: accept number as value of Signed Cookie + +3.2.0 / 2013-04-15 +================== + + * add "view" constructor setting to override view behaviour + * add req.acceptsEncoding(name) + * add req.acceptedEncodings + * revert cookie signature change causing session race conditions + * fix sorting of Accept values of the same quality + +3.1.2 / 2013-04-12 +================== + + * add support for custom Accept parameters + * update cookie-signature + +3.1.1 / 2013-04-01 +================== + + * add X-Forwarded-Host support to `req.host` + * fix relative redirects + * update mkdirp + * update buffer-crc32 + * remove legacy app.configure() method from app template. + +3.1.0 / 2013-01-25 +================== + + * add support for leading "." in "view engine" setting + * add array support to `res.set()` + * add node 0.8.x to travis.yml + * add "subdomain offset" setting for tweaking `req.subdomains` + * add `res.location(url)` implementing `res.redirect()`-like setting of Location + * use app.get() for x-powered-by setting for inheritance + * fix colons in passwords for `req.auth` + +3.0.6 / 2013-01-04 +================== + + * add http verb methods to Router + * update connect + * fix mangling of the `res.cookie()` options object + * fix jsonp whitespace escape. Closes #1132 + +3.0.5 / 2012-12-19 +================== + + * add throwing when a non-function is passed to a route + * fix: explicitly remove Transfer-Encoding header from 204 and 304 responses + * revert "add 'etag' option" + +3.0.4 / 2012-12-05 +================== + + * add 'etag' option to disable `res.send()` Etags + * add escaping of urls in text/plain in `res.redirect()` + for old browsers interpreting as html + * change crc32 module for a more liberal license + * update connect + +3.0.3 / 2012-11-13 +================== + + * update connect + * update cookie module + * fix cookie max-age + +3.0.2 / 2012-11-08 +================== + + * add OPTIONS to cors example. Closes #1398 + * fix route chaining regression. Closes #1397 + +3.0.1 / 2012-11-01 +================== + + * update connect + +3.0.0 / 2012-10-23 +================== + + * add `make clean` + * add "Basic" check to req.auth + * add `req.auth` test coverage + * add cb && cb(payload) to `res.jsonp()`. Closes #1374 + * add backwards compat for `res.redirect()` status. Closes #1336 + * add support for `res.json()` to retain previously defined Content-Types. Closes #1349 + * update connect + * change `res.redirect()` to utilize a pathname-relative Location again. Closes #1382 + * remove non-primitive string support for `res.send()` + * fix view-locals example. Closes #1370 + * fix route-separation example + +3.0.0rc5 / 2012-09-18 +================== + + * update connect + * add redis search example + * add static-files example + * add "x-powered-by" setting (`app.disable('x-powered-by')`) + * add "application/octet-stream" redirect Accept test case. Closes #1317 + +3.0.0rc4 / 2012-08-30 +================== + + * add `res.jsonp()`. Closes #1307 + * add "verbose errors" option to error-pages example + * add another route example to express(1) so people are not so confused + * add redis online user activity tracking example + * update connect dep + * fix etag quoting. Closes #1310 + * fix error-pages 404 status + * fix jsonp callback char restrictions + * remove old OPTIONS default response + +3.0.0rc3 / 2012-08-13 +================== + + * update connect dep + * fix signed cookies to work with `connect.cookieParser()` ("s:" prefix was missing) [tnydwrds] + * fix `res.render()` clobbering of "locals" + +3.0.0rc2 / 2012-08-03 +================== + + * add CORS example + * update connect dep + * deprecate `.createServer()` & remove old stale examples + * fix: escape `res.redirect()` link + * fix vhost example + +3.0.0rc1 / 2012-07-24 +================== + + * add more examples to view-locals + * add scheme-relative redirects (`res.redirect("//foo.com")`) support + * update cookie dep + * update connect dep + * update send dep + * fix `express(1)` -h flag, use -H for hogan. Closes #1245 + * fix `res.sendfile()` socket error handling regression + +3.0.0beta7 / 2012-07-16 +================== + + * update connect dep for `send()` root normalization regression + +3.0.0beta6 / 2012-07-13 +================== + + * add `err.view` property for view errors. Closes #1226 + * add "jsonp callback name" setting + * add support for "/foo/:bar*" non-greedy matches + * change `res.sendfile()` to use `send()` module + * change `res.send` to use "response-send" module + * remove `app.locals.use` and `res.locals.use`, use regular middleware + +3.0.0beta5 / 2012-07-03 +================== + + * add "make check" support + * add route-map example + * add `res.json(obj, status)` support back for BC + * add "methods" dep, remove internal methods module + * update connect dep + * update auth example to utilize cores pbkdf2 + * updated tests to use "supertest" + +3.0.0beta4 / 2012-06-25 +================== + + * Added `req.auth` + * Added `req.range(size)` + * Added `res.links(obj)` + * Added `res.send(body, status)` support back for backwards compat + * Added `.default()` support to `res.format()` + * Added 2xx / 304 check to `req.fresh` + * Revert "Added + support to the router" + * Fixed `res.send()` freshness check, respect res.statusCode + +3.0.0beta3 / 2012-06-15 +================== + + * Added hogan `--hjs` to express(1) [nullfirm] + * Added another example to content-negotiation + * Added `fresh` dep + * Changed: `res.send()` always checks freshness + * Fixed: expose connects mime module. Cloases #1165 + +3.0.0beta2 / 2012-06-06 +================== + + * Added `+` support to the router + * Added `req.host` + * Changed `req.param()` to check route first + * Update connect dep + +3.0.0beta1 / 2012-06-01 +================== + + * Added `res.format()` callback to override default 406 behaviour + * Fixed `res.redirect()` 406. Closes #1154 + +3.0.0alpha5 / 2012-05-30 +================== + + * Added `req.ip` + * Added `{ signed: true }` option to `res.cookie()` + * Removed `res.signedCookie()` + * Changed: dont reverse `req.ips` + * Fixed "trust proxy" setting check for `req.ips` + +3.0.0alpha4 / 2012-05-09 +================== + + * Added: allow `[]` in jsonp callback. Closes #1128 + * Added `PORT` env var support in generated template. Closes #1118 [benatkin] + * Updated: connect 2.2.2 + +3.0.0alpha3 / 2012-05-04 +================== + + * Added public `app.routes`. Closes #887 + * Added _view-locals_ example + * Added _mvc_ example + * Added `res.locals.use()`. Closes #1120 + * Added conditional-GET support to `res.send()` + * Added: coerce `res.set()` values to strings + * Changed: moved `static()` in generated apps below router + * Changed: `res.send()` only set ETag when not previously set + * Changed connect 2.2.1 dep + * Changed: `make test` now runs unit / acceptance tests + * Fixed req/res proto inheritance + +3.0.0alpha2 / 2012-04-26 +================== + + * Added `make benchmark` back + * Added `res.send()` support for `String` objects + * Added client-side data exposing example + * Added `res.header()` and `req.header()` aliases for BC + * Added `express.createServer()` for BC + * Perf: memoize parsed urls + * Perf: connect 2.2.0 dep + * Changed: make `expressInit()` middleware self-aware + * Fixed: use app.get() for all core settings + * Fixed redis session example + * Fixed session example. Closes #1105 + * Fixed generated express dep. Closes #1078 + +3.0.0alpha1 / 2012-04-15 +================== + + * Added `app.locals.use(callback)` + * Added `app.locals` object + * Added `app.locals(obj)` + * Added `res.locals` object + * Added `res.locals(obj)` + * Added `res.format()` for content-negotiation + * Added `app.engine()` + * Added `res.cookie()` JSON cookie support + * Added "trust proxy" setting + * Added `req.subdomains` + * Added `req.protocol` + * Added `req.secure` + * Added `req.path` + * Added `req.ips` + * Added `req.fresh` + * Added `req.stale` + * Added comma-delmited / array support for `req.accepts()` + * Added debug instrumentation + * Added `res.set(obj)` + * Added `res.set(field, value)` + * Added `res.get(field)` + * Added `app.get(setting)`. Closes #842 + * Added `req.acceptsLanguage()` + * Added `req.acceptsCharset()` + * Added `req.accepted` + * Added `req.acceptedLanguages` + * Added `req.acceptedCharsets` + * Added "json replacer" setting + * Added "json spaces" setting + * Added X-Forwarded-Proto support to `res.redirect()`. Closes #92 + * Added `--less` support to express(1) + * Added `express.response` prototype + * Added `express.request` prototype + * Added `express.application` prototype + * Added `app.path()` + * Added `app.render()` + * Added `res.type()` to replace `res.contentType()` + * Changed: `res.redirect()` to add relative support + * Changed: enable "jsonp callback" by default + * Changed: renamed "case sensitive routes" to "case sensitive routing" + * Rewrite of all tests with mocha + * Removed "root" setting + * Removed `res.redirect('home')` support + * Removed `req.notify()` + * Removed `app.register()` + * Removed `app.redirect()` + * Removed `app.is()` + * Removed `app.helpers()` + * Removed `app.dynamicHelpers()` + * Fixed `res.sendfile()` with non-GET. Closes #723 + * Fixed express(1) public dir for windows. Closes #866 + +2.5.9/ 2012-04-02 +================== + + * Added support for PURGE request method [pbuyle] + * Fixed `express(1)` generated app `app.address()` before `listening` [mmalecki] + +2.5.8 / 2012-02-08 +================== + + * Update mkdirp dep. Closes #991 + +2.5.7 / 2012-02-06 +================== + + * Fixed `app.all` duplicate DELETE requests [mscdex] + +2.5.6 / 2012-01-13 +================== + + * Updated hamljs dev dep. Closes #953 + +2.5.5 / 2012-01-08 +================== + + * Fixed: set `filename` on cached templates [matthewleon] + +2.5.4 / 2012-01-02 +================== + + * Fixed `express(1)` eol on 0.4.x. Closes #947 + +2.5.3 / 2011-12-30 +================== + + * Fixed `req.is()` when a charset is present + +2.5.2 / 2011-12-10 +================== + + * Fixed: express(1) LF -> CRLF for windows + +2.5.1 / 2011-11-17 +================== + + * Changed: updated connect to 1.8.x + * Removed sass.js support from express(1) + +2.5.0 / 2011-10-24 +================== + + * Added ./routes dir for generated app by default + * Added npm install reminder to express(1) app gen + * Added 0.5.x support + * Removed `make test-cov` since it wont work with node 0.5.x + * Fixed express(1) public dir for windows. Closes #866 + +2.4.7 / 2011-10-05 +================== + + * Added mkdirp to express(1). Closes #795 + * Added simple _json-config_ example + * Added shorthand for the parsed request's pathname via `req.path` + * Changed connect dep to 1.7.x to fix npm issue... + * Fixed `res.redirect()` __HEAD__ support. [reported by xerox] + * Fixed `req.flash()`, only escape args + * Fixed absolute path checking on windows. Closes #829 [reported by andrewpmckenzie] + +2.4.6 / 2011-08-22 +================== + + * Fixed multiple param callback regression. Closes #824 [reported by TroyGoode] + +2.4.5 / 2011-08-19 +================== + + * Added support for routes to handle errors. Closes #809 + * Added `app.routes.all()`. Closes #803 + * Added "basepath" setting to work in conjunction with reverse proxies etc. + * Refactored `Route` to use a single array of callbacks + * Added support for multiple callbacks for `app.param()`. Closes #801 +Closes #805 + * Changed: removed .call(self) for route callbacks + * Dependency: `qs >= 0.3.1` + * Fixed `res.redirect()` on windows due to `join()` usage. Closes #808 + +2.4.4 / 2011-08-05 +================== + + * Fixed `res.header()` intention of a set, even when `undefined` + * Fixed `*`, value no longer required + * Fixed `res.send(204)` support. Closes #771 + +2.4.3 / 2011-07-14 +================== + + * Added docs for `status` option special-case. Closes #739 + * Fixed `options.filename`, exposing the view path to template engines + +2.4.2. / 2011-07-06 +================== + + * Revert "removed jsonp stripping" for XSS + +2.4.1 / 2011-07-06 +================== + + * Added `res.json()` JSONP support. Closes #737 + * Added _extending-templates_ example. Closes #730 + * Added "strict routing" setting for trailing slashes + * Added support for multiple envs in `app.configure()` calls. Closes #735 + * Changed: `res.send()` using `res.json()` + * Changed: when cookie `path === null` don't default it + * Changed; default cookie path to "home" setting. Closes #731 + * Removed _pids/logs_ creation from express(1) + +2.4.0 / 2011-06-28 +================== + + * Added chainable `res.status(code)` + * Added `res.json()`, an explicit version of `res.send(obj)` + * Added simple web-service example + +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/node_modules/express/LICENSE b/node_modules/express/LICENSE new file mode 100644 index 0000000..d23e93c --- /dev/null +++ b/node_modules/express/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2009-2013 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/node_modules/express/Makefile b/node_modules/express/Makefile new file mode 100644 index 0000000..d0cb2a0 --- /dev/null +++ b/node_modules/express/Makefile @@ -0,0 +1,34 @@ + +MOCHA_OPTS= --check-leaks +REPORTER = dot + +check: test + +test: test-unit test-acceptance + +test-unit: + @NODE_ENV=test ./node_modules/.bin/mocha \ + --reporter $(REPORTER) \ + --globals setImmediate,clearImmediate \ + $(MOCHA_OPTS) + +test-acceptance: + @NODE_ENV=test ./node_modules/.bin/mocha \ + --reporter $(REPORTER) \ + --bail \ + test/acceptance/*.js + +test-cov: lib-cov + @EXPRESS_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html + +lib-cov: + @jscoverage lib lib-cov + +benchmark: + @./support/bench + +clean: + rm -f coverage.html + rm -fr lib-cov + +.PHONY: test test-unit test-acceptance benchmark clean diff --git a/node_modules/express/Readme.md b/node_modules/express/Readme.md new file mode 100644 index 0000000..44d47fe --- /dev/null +++ b/node_modules/express/Readme.md @@ -0,0 +1,126 @@ +[![express logo](http://f.cl.ly/items/0V2S1n0K1i3y1c122g04/Screen%20Shot%202012-04-11%20at%209.59.42%20AM.png)](http://expressjs.com/) + + Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). + + [![Build Status](https://secure.travis-ci.org/visionmedia/express.png)](http://travis-ci.org/visionmedia/express) [![Gittip](http://img.shields.io/gittip/visionmedia.png)](https://www.gittip.com/visionmedia/) + +```js +var express = require('express'); +var app = express(); + +app.get('/', function(req, res){ + res.send('Hello World'); +}); + +app.listen(3000); +``` + +## Installation + + $ 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 + + Start the server: + + $ node app + +## Features + + * Built on [Connect](http://github.com/senchalabs/connect) + * Robust routing + * HTTP helpers (redirection, caching, etc) + * View system supporting 14+ template engines + * Content negotiation + * Focus on high performance + * Environment based configuration + * Executable for generating applications quickly + * High test coverage + +## Philosophy + + The Express philosophy is to provide small, robust tooling for HTTP servers. Making + it a great solution for single page applications, web sites, hybrids, or public + HTTP APIs. + + Built on Connect you can use _only_ what you need, and nothing more, applications + can be as big or as small as you like, even a single file. Express does + not force you to use any specific ORM or template engine. With support for over + 14 template engines via [Consolidate.js](http://github.com/visionmedia/consolidate.js) + you can quickly craft your perfect framework. + +## More Information + + * [Website and Documentation](http://expressjs.com/) stored at [visionmedia/expressjs.com](https://github.com/visionmedia/expressjs.com) + * Join #express on freenode + * [Google Group](http://groups.google.com/group/express-js) for discussion + * Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates + * Visit the [Wiki](http://github.com/visionmedia/express/wiki) + * [Русскоязычная документация](http://jsman.ru/express/) + * Run express examples [online](https://runnable.com/express) + +## Viewing Examples + +Clone the Express repo, then install the dev dependencies to install all the example / test suite deps: + + $ git clone git://github.com/visionmedia/express.git --depth 1 + $ cd express + $ npm install + +then run whichever tests you want: + + $ node examples/content-negotiation + +You can also view live examples here + + + +## 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 + +## Contributors + + https://github.com/visionmedia/express/graphs/contributors + +## License + +(The MIT License) + +Copyright (c) 2009-2012 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/node_modules/express/bin/express b/node_modules/express/bin/express new file mode 100755 index 0000000..69b65d9 --- /dev/null +++ b/node_modules/express/bin/express @@ -0,0 +1,423 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('commander') + , mkdirp = require('mkdirp') + , pkg = require('../package.json') + , version = pkg.version + , os = require('os') + , fs = require('fs'); + +// CLI + +program + .version(version) + .usage('[options] [dir]') + .option('-s, --sessions', 'add session support') + .option('-e, --ejs', 'add ejs engine support (defaults to jade)') + .option('-J, --jshtml', 'add jshtml engine support (defaults to jade)') + .option('-H, --hogan', 'add hogan.js engine support') + .option('-c, --css ', 'add stylesheet support (less|stylus) (defaults to plain css)') + .option('-f, --force', 'force on non-empty directory') + .parse(process.argv); + +// Path + +var path = program.args.shift() || '.'; + +// end-of-line code + +var eol = os.EOL + +// Template engine + +program.template = 'jade'; +if (program.ejs) program.template = 'ejs'; +if (program.jshtml) program.template = 'jshtml'; +if (program.hogan) program.template = 'hjs'; + +/** + * Routes index template. + */ + +var index = [ + '' + , '/*' + , ' * GET home page.' + , ' */' + , '' + , 'exports.index = function(req, res){' + , ' res.render(\'index\', { title: \'Express\' });' + , '};' +].join(eol); + +/** + * Routes users template. + */ + +var users = [ + '' + , '/*' + , ' * GET users listing.' + , ' */' + , '' + , 'exports.list = function(req, res){' + , ' res.send("respond with a resource");' + , '};' +].join(eol); + +/** + * Jade layout template. + */ + +var jadeLayout = [ + 'doctype 5' + , 'html' + , ' head' + , ' title= title' + , ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')' + , ' body' + , ' block content' +].join(eol); + +/** + * Jade index template. + */ + +var jadeIndex = [ + 'extends layout' + , '' + , 'block content' + , ' h1= title' + , ' p Welcome to #{title}' +].join(eol); + +/** + * EJS index template. + */ + +var ejsIndex = [ + '' + , '' + , ' ' + , ' <%= title %>' + , ' ' + , ' ' + , ' ' + , '

<%= title %>

' + , '

Welcome to <%= title %>

' + , ' ' + , '' +].join(eol); + +/** + * JSHTML layout template. + */ + +var jshtmlLayout = [ + '' + , '' + , ' ' + , ' @write(title) ' + , ' ' + , ' ' + , ' ' + , ' @write(body)' + , ' ' + , '' +].join(eol); + +/** + * JSHTML index template. + */ + +var jshtmlIndex = [ + '

@write(title)

' + , '

Welcome to @write(title)

' +].join(eol); + +/** + * Hogan.js index template. + */ +var hoganIndex = [ + '' + , '' + , ' ' + , ' {{ title }}' + , ' ' + , ' ' + , ' ' + , '

{{ title }}

' + , '

Welcome to {{ title }}

' + , ' ' + , '' +].join(eol); + +/** + * Default css template. + */ + +var css = [ + 'body {' + , ' padding: 50px;' + , ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;' + , '}' + , '' + , 'a {' + , ' color: #00B7FF;' + , '}' +].join(eol); + +/** + * Default less template. + */ + +var less = [ + 'body {' + , ' padding: 50px;' + , ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;' + , '}' + , '' + , 'a {' + , ' color: #00B7FF;' + , '}' +].join(eol); + +/** + * Default stylus template. + */ + +var stylus = [ + 'body' + , ' padding: 50px' + , ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif' + , 'a' + , ' color: #00B7FF' +].join(eol); + +/** + * App template. + */ + +var app = [ + '' + , '/**' + , ' * Module dependencies.' + , ' */' + , '' + , 'var express = require(\'express\');' + , 'var routes = require(\'./routes\');' + , 'var user = require(\'./routes/user\');' + , 'var http = require(\'http\');' + , 'var path = require(\'path\');' + , '' + , 'var app = express();' + , '' + , '// all environments' + , 'app.set(\'port\', process.env.PORT || 3000);' + , 'app.set(\'views\', path.join(__dirname, \'views\'));' + , 'app.set(\'view engine\', \':TEMPLATE\');' + , 'app.use(express.favicon());' + , 'app.use(express.logger(\'dev\'));' + , 'app.use(express.json());' + , 'app.use(express.urlencoded());' + , 'app.use(express.methodOverride());{sess}' + , 'app.use(app.router);{css}' + , 'app.use(express.static(path.join(__dirname, \'public\')));' + , '' + , '// development only' + , 'if (\'development\' == app.get(\'env\')) {' + , ' app.use(express.errorHandler());' + , '}' + , '' + , 'app.get(\'/\', routes.index);' + , 'app.get(\'/users\', user.list);' + , '' + , 'http.createServer(app).listen(app.get(\'port\'), function(){' + , ' console.log(\'Express server listening on port \' + app.get(\'port\'));' + , '});' + , '' +].join(eol); + +// Generate application + +(function createApplication(path) { + emptyDirectory(path, function(empty){ + if (empty || program.force) { + createApplicationAt(path); + } else { + program.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) { + console.log(); + process.on('exit', function(){ + console.log(); + console.log(' install dependencies:'); + console.log(' $ cd %s && npm install', path); + console.log(); + console.log(' run the app:'); + console.log(' $ node app'); + console.log(); + }); + + mkdir(path, function(){ + mkdir(path + '/public'); + mkdir(path + '/public/javascripts'); + mkdir(path + '/public/images'); + mkdir(path + '/public/stylesheets', function(){ + switch (program.css) { + case 'less': + write(path + '/public/stylesheets/style.less', less); + break; + case 'stylus': + write(path + '/public/stylesheets/style.styl', stylus); + break; + default: + write(path + '/public/stylesheets/style.css', css); + } + }); + + mkdir(path + '/routes', function(){ + write(path + '/routes/index.js', index); + write(path + '/routes/user.js', users); + }); + + mkdir(path + '/views', function(){ + switch (program.template) { + case 'ejs': + write(path + '/views/index.ejs', ejsIndex); + break; + case 'jade': + write(path + '/views/layout.jade', jadeLayout); + write(path + '/views/index.jade', jadeIndex); + break; + case 'jshtml': + write(path + '/views/layout.jshtml', jshtmlLayout); + write(path + '/views/index.jshtml', jshtmlIndex); + break; + case 'hjs': + write(path + '/views/index.hjs', hoganIndex); + break; + + } + }); + + // CSS Engine support + switch (program.css) { + case 'less': + app = app.replace('{css}', eol + 'app.use(require(\'less-middleware\')({ src: path.join(__dirname, \'public\') }));'); + break; + case 'stylus': + app = app.replace('{css}', eol + 'app.use(require(\'stylus\').middleware(path.join(__dirname, \'public\')));'); + break; + default: + app = app.replace('{css}', ''); + } + + // Session support + app = app.replace('{sess}', program.sessions + ? eol + 'app.use(express.cookieParser(\'your secret here\'));' + eol + 'app.use(express.session());' + : ''); + + // Template support + app = app.replace(':TEMPLATE', program.template); + + // package.json + var pkg = { + name: 'application-name' + , version: '0.0.1' + , private: true + , scripts: { start: 'node app.js' } + , dependencies: { + express: version + } + } + + if (program.template) pkg.dependencies[program.template] = '*'; + + // CSS Engine support + switch (program.css) { + case 'less': + pkg.dependencies['less-middleware'] = '*'; + break; + default: + if (program.css) { + pkg.dependencies[program.css] = '*'; + } + } + + write(path + '/package.json', JSON.stringify(pkg, null, 2)); + 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); +} + +/** + * Mkdir -p. + * + * @param {String} path + * @param {Function} fn + */ + +function mkdir(path, fn) { + mkdirp(path, 0755, function(err){ + if (err) throw err; + console.log(' \033[36mcreate\033[0m : ' + path); + fn && fn(); + }); +} + +/** + * Exit with the given `str`. + * + * @param {String} str + */ + +function abort(str) { + console.error(str); + process.exit(1); +} diff --git a/node_modules/express/index.js b/node_modules/express/index.js new file mode 100644 index 0000000..bfe9934 --- /dev/null +++ b/node_modules/express/index.js @@ -0,0 +1,4 @@ + +module.exports = process.env.EXPRESS_COV + ? require('./lib-cov/express') + : require('./lib/express'); \ No newline at end of file diff --git a/node_modules/express/lib/application.js b/node_modules/express/lib/application.js new file mode 100644 index 0000000..d5806f0 --- /dev/null +++ b/node_modules/express/lib/application.js @@ -0,0 +1,534 @@ +/** + * Module dependencies. + */ + +var connect = require('connect') + , Router = require('./router') + , methods = require('methods') + , middleware = require('./middleware') + , debug = require('debug')('express:application') + , locals = require('./utils').locals + , View = require('./view') + , utils = connect.utils + , http = require('http'); + +/** + * Application prototype. + */ + +var app = exports = module.exports = {}; + +/** + * Initialize the server. + * + * - setup default configuration + * - setup default middleware + * - setup route reflection methods + * + * @api private + */ + +app.init = function(){ + this.cache = {}; + this.settings = {}; + this.engines = {}; + this.defaultConfiguration(); +}; + +/** + * Initialize application configuration. + * + * @api private + */ + +app.defaultConfiguration = function(){ + // default settings + this.enable('x-powered-by'); + this.enable('etag'); + this.set('env', process.env.NODE_ENV || 'development'); + this.set('subdomain offset', 2); + debug('booting in %s mode', this.get('env')); + + // implicit middleware + this.use(connect.query()); + this.use(middleware.init(this)); + + // inherit protos + this.on('mount', function(parent){ + this.request.__proto__ = parent.request; + this.response.__proto__ = parent.response; + this.engines.__proto__ = parent.engines; + this.settings.__proto__ = parent.settings; + }); + + // router + this._router = new Router(this); + this.routes = this._router.map; + this.__defineGetter__('router', function(){ + this._usedRouter = true; + this._router.caseSensitive = this.enabled('case sensitive routing'); + this._router.strict = this.enabled('strict routing'); + return this._router.middleware; + }); + + // setup locals + this.locals = locals(this); + + // default locals + this.locals.settings = this.settings; + + // default configuration + this.set('view', View); + this.set('views', process.cwd() + '/views'); + this.set('jsonp callback name', 'callback'); + + this.configure('development', function(){ + this.set('json spaces', 2); + }); + + this.configure('production', function(){ + this.enable('view cache'); + }); +}; + +/** + * Proxy `connect#use()` to apply settings to + * mounted applications. + * + * @param {String|Function|Server} route + * @param {Function|Server} fn + * @return {app} for chaining + * @api public + */ + +app.use = function(route, fn){ + var app; + + // default route to '/' + if ('string' != typeof route) fn = route, route = '/'; + + // express app + if (fn.handle && fn.set) app = fn; + + // restore .app property on req and res + if (app) { + app.route = route; + fn = function(req, res, next) { + var orig = req.app; + app.handle(req, res, function(err){ + req.__proto__ = orig.request; + res.__proto__ = orig.response; + next(err); + }); + }; + } + + connect.proto.use.call(this, route, fn); + + // mounted an app + if (app) { + app.parent = this; + app.emit('mount', this); + } + + return this; +}; + +/** + * Register the given template engine callback `fn` + * as `ext`. + * + * By default will `require()` the engine based on the + * file extension. For example if you try to render + * a "foo.jade" file Express will invoke the following internally: + * + * app.engine('jade', require('jade').__express); + * + * For engines that do not provide `.__express` out of the box, + * or if you wish to "map" a different extension to the template engine + * you may use this method. For example mapping the EJS template engine to + * ".html" files: + * + * app.engine('html', require('ejs').renderFile); + * + * In this case EJS provides a `.renderFile()` method with + * the same signature that Express expects: `(path, options, callback)`, + * though note that it aliases this method as `ejs.__express` internally + * so if you're using ".ejs" extensions you dont need to do anything. + * + * Some template engines do not follow this convention, the + * [Consolidate.js](https://github.com/visionmedia/consolidate.js) + * library was created to map all of node's popular template + * engines to follow this convention, thus allowing them to + * work seamlessly within Express. + * + * @param {String} ext + * @param {Function} fn + * @return {app} for chaining + * @api public + */ + +app.engine = function(ext, fn){ + if ('function' != typeof fn) throw new Error('callback function required'); + if ('.' != ext[0]) ext = '.' + ext; + this.engines[ext] = fn; + return this; +}; + +/** + * Map the given param placeholder `name`(s) to the given callback(s). + * + * Parameter mapping is used to provide pre-conditions to routes + * which use normalized placeholders. For example a _:user_id_ parameter + * could automatically load a user's information from the database without + * any additional code, + * + * The callback uses the same signature as middleware, the only difference + * being that the value of the placeholder is passed, in this case the _id_ + * of the user. Once the `next()` function is invoked, just like middleware + * it will continue on to execute the route, or subsequent parameter functions. + * + * app.param('user_id', 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} name + * @param {Function} fn + * @return {app} for chaining + * @api public + */ + +app.param = function(name, fn){ + var self = this + , fns = [].slice.call(arguments, 1); + + // array + if (Array.isArray(name)) { + name.forEach(function(name){ + fns.forEach(function(fn){ + self.param(name, fn); + }); + }); + // param logic + } else if ('function' == typeof name) { + this._router.param(name); + // single + } else { + if (':' == name[0]) name = name.substr(1); + fns.forEach(function(fn){ + self._router.param(name, fn); + }); + } + + return this; +}; + +/** + * Assign `setting` to `val`, or return `setting`'s value. + * + * app.set('foo', 'bar'); + * app.get('foo'); + * // => "bar" + * + * Mounted servers inherit their parent server's settings. + * + * @param {String} setting + * @param {String} val + * @return {Server} for chaining + * @api public + */ + +app.set = function(setting, val){ + if (1 == arguments.length) { + return this.settings[setting]; + } else { + this.settings[setting] = val; + return this; + } +}; + +/** + * Return the app's absolute pathname + * based on the parent(s) that have + * mounted it. + * + * For example if the application was + * mounted as "/admin", which itself + * was mounted as "/blog" then the + * return value would be "/blog/admin". + * + * @return {String} + * @api private + */ + +app.path = function(){ + return this.parent + ? this.parent.path() + this.route + : ''; +}; + +/** + * Check if `setting` is enabled (truthy). + * + * app.enabled('foo') + * // => false + * + * app.enable('foo') + * app.enabled('foo') + * // => true + * + * @param {String} setting + * @return {Boolean} + * @api public + */ + +app.enabled = function(setting){ + return !!this.set(setting); +}; + +/** + * Check if `setting` is disabled. + * + * app.disabled('foo') + * // => true + * + * app.enable('foo') + * app.disabled('foo') + * // => false + * + * @param {String} setting + * @return {Boolean} + * @api public + */ + +app.disabled = function(setting){ + return !this.set(setting); +}; + +/** + * Enable `setting`. + * + * @param {String} setting + * @return {app} for chaining + * @api public + */ + +app.enable = function(setting){ + return this.set(setting, true); +}; + +/** + * Disable `setting`. + * + * @param {String} setting + * @return {app} for chaining + * @api public + */ + +app.disable = function(setting){ + return this.set(setting, false); +}; + +/** + * Configure callback for zero or more envs, + * when no `env` is specified that callback will + * be invoked for all environments. Any combination + * can be used multiple times, in any order desired. + * + * Examples: + * + * app.configure(function(){ + * // executed for all envs + * }); + * + * app.configure('stage', function(){ + * // executed staging env + * }); + * + * app.configure('stage', 'production', function(){ + * // executed for stage and production + * }); + * + * Note: + * + * These callbacks are invoked immediately, and + * are effectively sugar for the following: + * + * var env = process.env.NODE_ENV || 'development'; + * + * switch (env) { + * case 'development': + * ... + * break; + * case 'stage': + * ... + * break; + * case 'production': + * ... + * break; + * } + * + * @param {String} env... + * @param {Function} fn + * @return {app} for chaining + * @api public + */ + +app.configure = function(env, fn){ + var envs = 'all' + , args = [].slice.call(arguments); + fn = args.pop(); + if (args.length) envs = args; + if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this); + return this; +}; + +/** + * Delegate `.VERB(...)` calls to `router.VERB(...)`. + */ + +methods.forEach(function(method){ + app[method] = function(path){ + if ('get' == method && 1 == arguments.length) return this.set(path); + + // deprecated + if (Array.isArray(path)) { + console.trace('passing an array to app.VERB() is deprecated and will be removed in 4.0'); + } + + // if no router attached yet, attach the router + if (!this._usedRouter) this.use(this.router); + + // setup route + this._router[method].apply(this._router, arguments); + return this; + }; +}); + +/** + * Special-cased "all" method, applying the given route `path`, + * middleware, and callback to _every_ HTTP method. + * + * @param {String} path + * @param {Function} ... + * @return {app} for chaining + * @api public + */ + +app.all = function(path){ + var args = arguments; + methods.forEach(function(method){ + app[method].apply(this, args); + }, this); + return this; +}; + +// del -> delete alias + +app.del = app.delete; + +/** + * Render the given view `name` name with `options` + * and a callback accepting an error and the + * rendered template string. + * + * Example: + * + * app.render('email', { name: 'Tobi' }, function(err, html){ + * // ... + * }) + * + * @param {String} name + * @param {String|Function} options or fn + * @param {Function} fn + * @api public + */ + +app.render = function(name, options, fn){ + var opts = {} + , cache = this.cache + , engines = this.engines + , view; + + // support callback function as second arg + if ('function' == typeof options) { + fn = options, options = {}; + } + + // merge app.locals + utils.merge(opts, this.locals); + + // merge options._locals + if (options._locals) utils.merge(opts, options._locals); + + // merge options + utils.merge(opts, options); + + // set .cache unless explicitly provided + opts.cache = null == opts.cache + ? this.enabled('view cache') + : opts.cache; + + // primed cache + if (opts.cache) view = cache[name]; + + // view + if (!view) { + view = new (this.get('view'))(name, { + defaultEngine: this.get('view engine'), + root: this.get('views'), + engines: engines + }); + + if (!view.path) { + var err = new Error('Failed to lookup view "' + name + '"'); + err.view = view; + return fn(err); + } + + // prime the cache + if (opts.cache) cache[name] = view; + } + + // render + try { + view.render(opts, fn); + } catch (err) { + fn(err); + } +}; + +/** + * Listen for connections. + * + * A node `http.Server` is returned, with this + * application (which is a `Function`) as its + * callback. If you wish to create both an HTTP + * and HTTPS server you may do so with the "http" + * and "https" modules as shown here: + * + * var http = require('http') + * , https = require('https') + * , express = require('express') + * , app = express(); + * + * http.createServer(app).listen(80); + * https.createServer({ ... }, app).listen(443); + * + * @return {http.Server} + * @api public + */ + +app.listen = function(){ + var server = http.createServer(this); + return server.listen.apply(server, arguments); +}; diff --git a/node_modules/express/lib/express.js b/node_modules/express/lib/express.js new file mode 100644 index 0000000..c204849 --- /dev/null +++ b/node_modules/express/lib/express.js @@ -0,0 +1,86 @@ +/** + * Module dependencies. + */ + +var connect = require('connect') + , proto = require('./application') + , Route = require('./router/route') + , Router = require('./router') + , req = require('./request') + , res = require('./response') + , utils = connect.utils; + +/** + * Expose `createApplication()`. + */ + +exports = module.exports = createApplication; + +/** + * Expose mime. + */ + +exports.mime = connect.mime; + +/** + * Create an express application. + * + * @return {Function} + * @api public + */ + +function createApplication() { + var app = connect(); + utils.merge(app, proto); + app.request = { __proto__: req, app: app }; + app.response = { __proto__: res, app: app }; + app.init(); + return app; +} + +/** + * Expose connect.middleware as express.* + * for example `express.logger` etc. + */ + +for (var key in connect.middleware) { + Object.defineProperty( + exports + , key + , Object.getOwnPropertyDescriptor(connect.middleware, key)); +} + +/** + * Error on createServer(). + */ + +exports.createServer = function(){ + console.warn('Warning: express.createServer() is deprecated, express'); + console.warn('applications no longer inherit from http.Server,'); + console.warn('please use:'); + console.warn(''); + console.warn(' var express = require("express");'); + console.warn(' var app = express();'); + console.warn(''); + return createApplication(); +}; + +/** + * Expose the prototypes. + */ + +exports.application = proto; +exports.request = req; +exports.response = res; + +/** + * Expose constructors. + */ + +exports.Route = Route; +exports.Router = Router; + +// Error handler title + +exports.errorHandler.title = 'Express'; + diff --git a/node_modules/express/lib/middleware.js b/node_modules/express/lib/middleware.js new file mode 100644 index 0000000..e07dd4c --- /dev/null +++ b/node_modules/express/lib/middleware.js @@ -0,0 +1,32 @@ + +/** + * Module dependencies. + */ + +var utils = require('./utils'); + +/** + * Initialization middleware, exposing the + * request and response to eachother, as well + * as defaulting the X-Powered-By header field. + * + * @param {Function} app + * @return {Function} + * @api private + */ + +exports.init = function(app){ + return function expressInit(req, res, next){ + if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express'); + req.res = res; + res.req = req; + req.next = next; + + req.__proto__ = app.request; + res.__proto__ = app.response; + + res.locals = res.locals || utils.locals(res); + + next(); + } +}; diff --git a/node_modules/express/lib/request.js b/node_modules/express/lib/request.js new file mode 100644 index 0000000..3d41617 --- /dev/null +++ b/node_modules/express/lib/request.js @@ -0,0 +1,529 @@ + +/** + * Module dependencies. + */ + +var http = require('http') + , utils = require('./utils') + , connect = require('connect') + , fresh = require('fresh') + , parseRange = require('range-parser') + , parse = connect.utils.parseUrl + , mime = connect.mime; + +/** + * Request prototype. + */ + +var req = exports = module.exports = { + __proto__: http.IncomingMessage.prototype +}; + +/** + * Return request header. + * + * The `Referrer` header field is special-cased, + * both `Referrer` and `Referer` are interchangeable. + * + * Examples: + * + * req.get('Content-Type'); + * // => "text/plain" + * + * req.get('content-type'); + * // => "text/plain" + * + * req.get('Something'); + * // => undefined + * + * Aliased as `req.header()`. + * + * @param {String} name + * @return {String} + * @api public + */ + +req.get = +req.header = function(name){ + switch (name = name.toLowerCase()) { + case 'referer': + case 'referrer': + return this.headers.referrer + || this.headers.referer; + default: + return this.headers[name]; + } +}; + +/** + * Check if the given `type(s)` is acceptable, returning + * the best match when true, otherwise `undefined`, in which + * case you should respond with 406 "Not Acceptable". + * + * The `type` value may be a single mime type string + * such as "application/json", the extension name + * such as "json", a comma-delimted list such as "json, html, text/plain", + * an argument list such as `"json", "html", "text/plain"`, + * or an array `["json", "html", "text/plain"]`. When a list + * or array is given the _best_ match, if any is returned. + * + * Examples: + * + * // Accept: text/html + * req.accepts('html'); + * // => "html" + * + * // Accept: text/*, application/json + * req.accepts('html'); + * // => "html" + * req.accepts('text/html'); + * // => "text/html" + * req.accepts('json, text'); + * // => "json" + * req.accepts('application/json'); + * // => "application/json" + * + * // Accept: text/*, application/json + * req.accepts('image/png'); + * req.accepts('png'); + * // => undefined + * + * // Accept: text/*;q=.5, application/json + * req.accepts(['html', 'json']); + * req.accepts('html', 'json'); + * req.accepts('html, json'); + * // => "json" + * + * @param {String|Array} type(s) + * @return {String} + * @api public + */ + +req.accepts = function(type){ + var args = arguments.length > 1 ? [].slice.apply(arguments) : type; + return utils.accepts(args, this.get('Accept')); +}; + +/** + * Check if the given `encoding` is accepted. + * + * @param {String} encoding + * @return {Boolean} + * @api public + */ + +req.acceptsEncoding = function(encoding){ + return !! ~this.acceptedEncodings.indexOf(encoding); +}; + +/** + * Check if the given `charset` is acceptable, + * otherwise you should respond with 406 "Not Acceptable". + * + * @param {String} charset + * @return {Boolean} + * @api public + */ + +req.acceptsCharset = function(charset){ + var accepted = this.acceptedCharsets; + return accepted.length + ? !! ~accepted.indexOf(charset) + : true; +}; + +/** + * Check if the given `lang` is acceptable, + * otherwise you should respond with 406 "Not Acceptable". + * + * @param {String} lang + * @return {Boolean} + * @api public + */ + +req.acceptsLanguage = function(lang){ + var accepted = this.acceptedLanguages; + return accepted.length + ? !! ~accepted.indexOf(lang) + : true; +}; + +/** + * Parse Range header field, + * capping to the given `size`. + * + * Unspecified ranges such as "0-" require + * knowledge of your resource length. In + * the case of a byte range this is of course + * the total number of bytes. If the Range + * header field is not given `null` is returned, + * `-1` when unsatisfiable, `-2` when syntactically invalid. + * + * NOTE: remember that ranges are inclusive, so + * for example "Range: users=0-3" should respond + * with 4 users when available, not 3. + * + * @param {Number} size + * @return {Array} + * @api public + */ + +req.range = function(size){ + var range = this.get('Range'); + if (!range) return; + return parseRange(size, range); +}; + +/** + * Return an array of encodings. + * + * Examples: + * + * ['gzip', 'deflate'] + * + * @return {Array} + * @api public + */ + +req.__defineGetter__('acceptedEncodings', function(){ + var accept = this.get('Accept-Encoding'); + return accept + ? accept.trim().split(/ *, */) + : []; +}); + +/** + * Return an array of Accepted media types + * ordered from highest quality to lowest. + * + * Examples: + * + * [ { value: 'application/json', + * quality: 1, + * type: 'application', + * subtype: 'json' }, + * { value: 'text/html', + * quality: 0.5, + * type: 'text', + * subtype: 'html' } ] + * + * @return {Array} + * @api public + */ + +req.__defineGetter__('accepted', function(){ + var accept = this.get('Accept'); + return accept + ? utils.parseAccept(accept) + : []; +}); + +/** + * Return an array of Accepted languages + * ordered from highest quality to lowest. + * + * Examples: + * + * Accept-Language: en;q=.5, en-us + * ['en-us', 'en'] + * + * @return {Array} + * @api public + */ + +req.__defineGetter__('acceptedLanguages', function(){ + var accept = this.get('Accept-Language'); + return accept + ? utils + .parseParams(accept) + .map(function(obj){ + return obj.value; + }) + : []; +}); + +/** + * Return an array of Accepted charsets + * ordered from highest quality to lowest. + * + * Examples: + * + * Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8 + * ['unicode-1-1', 'iso-8859-5'] + * + * @return {Array} + * @api public + */ + +req.__defineGetter__('acceptedCharsets', function(){ + var accept = this.get('Accept-Charset'); + return accept + ? utils + .parseParams(accept) + .map(function(obj){ + return obj.value; + }) + : []; +}); + +/** + * Return the value of param `name` when present or `defaultValue`. + * + * - Checks route placeholders, ex: _/user/:id_ + * - Checks body params, ex: id=12, {"id":12} + * - Checks query string params, ex: ?id=12 + * + * To utilize 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){ + var params = this.params || {}; + var body = this.body || {}; + var query = this.query || {}; + if (null != params[name] && params.hasOwnProperty(name)) return params[name]; + if (null != body[name]) return body[name]; + if (null != query[name]) return query[name]; + return defaultValue; +}; + +/** + * 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'); + * req.is('text/*'); + * // => true + * + * // When Content-Type is application/json + * req.is('json'); + * req.is('application/json'); + * req.is('application/*'); + * // => true + * + * req.is('html'); + * // => false + * + * @param {String} type + * @return {Boolean} + * @api public + */ + +req.is = function(type){ + var ct = this.get('Content-Type'); + if (!ct) return false; + ct = ct.split(';')[0]; + if (!~type.indexOf('/')) type = mime.lookup(type); + if (~type.indexOf('*')) { + type = type.split('/'); + ct = ct.split('/'); + if ('*' == type[0] && type[1] == ct[1]) return true; + if ('*' == type[1] && type[0] == ct[0]) return true; + return false; + } + return !! ~ct.indexOf(type); +}; + +/** + * Return the protocol string "http" or "https" + * when requested with TLS. When the "trust proxy" + * setting is enabled the "X-Forwarded-Proto" header + * field will be trusted. If you're running behind + * a reverse proxy that supplies https for you this + * may be enabled. + * + * @return {String} + * @api public + */ + +req.__defineGetter__('protocol', function(){ + var trustProxy = this.app.get('trust proxy'); + if (this.connection.encrypted) return 'https'; + if (!trustProxy) return 'http'; + var proto = this.get('X-Forwarded-Proto') || 'http'; + return proto.split(/\s*,\s*/)[0]; +}); + +/** + * Short-hand for: + * + * req.protocol == 'https' + * + * @return {Boolean} + * @api public + */ + +req.__defineGetter__('secure', function(){ + return 'https' == this.protocol; +}); + +/** + * Return the remote address, or when + * "trust proxy" is `true` return + * the upstream addr. + * + * @return {String} + * @api public + */ + +req.__defineGetter__('ip', function(){ + return this.ips[0] || this.connection.remoteAddress; +}); + +/** + * When "trust proxy" is `true`, parse + * the "X-Forwarded-For" ip address list. + * + * For example if the value were "client, proxy1, proxy2" + * you would receive the array `["client", "proxy1", "proxy2"]` + * where "proxy2" is the furthest down-stream. + * + * @return {Array} + * @api public + */ + +req.__defineGetter__('ips', function(){ + var trustProxy = this.app.get('trust proxy'); + var val = this.get('X-Forwarded-For'); + return trustProxy && val + ? val.split(/ *, */) + : []; +}); + +/** + * Return basic auth credentials. + * + * Examples: + * + * // http://tobi:hello@example.com + * req.auth + * // => { username: 'tobi', password: 'hello' } + * + * @return {Object} or undefined + * @api public + */ + +req.__defineGetter__('auth', function(){ + // missing + var auth = this.get('Authorization'); + if (!auth) return; + + // malformed + var parts = auth.split(' '); + if ('basic' != parts[0].toLowerCase()) return; + if (!parts[1]) return; + auth = parts[1]; + + // credentials + auth = new Buffer(auth, 'base64').toString().match(/^([^:]*):(.*)$/); + if (!auth) return; + return { username: auth[1], password: auth[2] }; +}); + +/** + * Return subdomains as an array. + * + * Subdomains are the dot-separated parts of the host before the main domain of + * the app. By default, the domain of the app is assumed to be the last two + * parts of the host. This can be changed by setting "subdomain offset". + * + * For example, if the domain is "tobi.ferrets.example.com": + * If "subdomain offset" is not set, req.subdomains is `["ferrets", "tobi"]`. + * If "subdomain offset" is 3, req.subdomains is `["tobi"]`. + * + * @return {Array} + * @api public + */ + +req.__defineGetter__('subdomains', function(){ + var offset = this.app.get('subdomain offset'); + return (this.host || '') + .split('.') + .reverse() + .slice(offset); +}); + +/** + * Short-hand for `url.parse(req.url).pathname`. + * + * @return {String} + * @api public + */ + +req.__defineGetter__('path', function(){ + return parse(this).pathname; +}); + +/** + * Parse the "Host" header field hostname. + * + * @return {String} + * @api public + */ + +req.__defineGetter__('host', function(){ + var trustProxy = this.app.get('trust proxy'); + var host = trustProxy && this.get('X-Forwarded-Host'); + host = host || this.get('Host'); + if (!host) return; + return host.split(':')[0]; +}); + +/** + * Check if the request is fresh, aka + * Last-Modified and/or the ETag + * still match. + * + * @return {Boolean} + * @api public + */ + +req.__defineGetter__('fresh', function(){ + var method = this.method; + var s = this.res.statusCode; + + // GET or HEAD for weak freshness validation only + if ('GET' != method && 'HEAD' != method) return false; + + // 2xx or 304 as per rfc2616 14.26 + if ((s >= 200 && s < 300) || 304 == s) { + return fresh(this.headers, this.res._headers); + } + + return false; +}); + +/** + * Check if the request is stale, aka + * "Last-Modified" and / or the "ETag" for the + * resource has changed. + * + * @return {Boolean} + * @api public + */ + +req.__defineGetter__('stale', function(){ + return !this.fresh; +}); + +/** + * Check if the request was an _XMLHttpRequest_. + * + * @return {Boolean} + * @api public + */ + +req.__defineGetter__('xhr', function(){ + var val = this.get('X-Requested-With') || ''; + return 'xmlhttprequest' == val.toLowerCase(); +}); diff --git a/node_modules/express/lib/response.js b/node_modules/express/lib/response.js new file mode 100644 index 0000000..b0816b3 --- /dev/null +++ b/node_modules/express/lib/response.js @@ -0,0 +1,802 @@ +/** + * Module dependencies. + */ + +var http = require('http') + , path = require('path') + , connect = require('connect') + , utils = connect.utils + , sign = require('cookie-signature').sign + , normalizeType = require('./utils').normalizeType + , normalizeTypes = require('./utils').normalizeTypes + , etag = require('./utils').etag + , statusCodes = http.STATUS_CODES + , cookie = require('cookie') + , send = require('send') + , mime = connect.mime + , basename = path.basename + , extname = path.extname; + +/** + * Response prototype. + */ + +var res = module.exports = { + __proto__: http.ServerResponse.prototype +}; + +/** + * Set status `code`. + * + * @param {Number} code + * @return {ServerResponse} + * @api public + */ + +res.status = function(code){ + this.statusCode = code; + return this; +}; + +/** + * Set Link header field with the given `links`. + * + * Examples: + * + * res.links({ + * next: 'http://api.example.com/users?page=2', + * last: 'http://api.example.com/users?page=5' + * }); + * + * @param {Object} links + * @return {ServerResponse} + * @api public + */ + +res.links = function(links){ + var link = this.get('Link') || ''; + if (link) link += ', '; + return this.set('Link', link + Object.keys(links).map(function(rel){ + return '<' + links[rel] + '>; rel="' + rel + '"'; + }).join(', ')); +}; + +/** + * Send a response. + * + * Examples: + * + * res.send(new Buffer('wahoo')); + * res.send({ some: 'json' }); + * res.send('

some html

'); + * res.send(404, 'Sorry, cant find that'); + * res.send(404); + * + * @param {Mixed} body or status + * @param {Mixed} body + * @return {ServerResponse} + * @api public + */ + +res.send = function(body){ + var req = this.req; + var head = 'HEAD' == req.method; + var len; + + // settings + var app = this.app; + + // allow status / body + if (2 == arguments.length) { + // res.send(body, status) backwards compat + if ('number' != typeof body && 'number' == typeof arguments[1]) { + this.statusCode = arguments[1]; + } else { + this.statusCode = body; + body = arguments[1]; + } + } + + switch (typeof body) { + // response status + case 'number': + this.get('Content-Type') || this.type('txt'); + this.statusCode = body; + body = http.STATUS_CODES[body]; + break; + // string defaulting to html + case 'string': + if (!this.get('Content-Type')) { + this.charset = this.charset || 'utf-8'; + this.type('html'); + } + break; + case 'boolean': + case 'object': + if (null == body) { + body = ''; + } else if (Buffer.isBuffer(body)) { + this.get('Content-Type') || this.type('bin'); + } else { + return this.json(body); + } + break; + } + + // populate Content-Length + if (undefined !== body && !this.get('Content-Length')) { + this.set('Content-Length', len = Buffer.isBuffer(body) + ? body.length + : Buffer.byteLength(body)); + } + + // ETag support + // TODO: W/ support + if (app.settings.etag && len > 1024 && 'GET' == req.method) { + if (!this.get('ETag')) { + this.set('ETag', etag(body)); + } + } + + // freshness + if (req.fresh) this.statusCode = 304; + + // strip irrelevant headers + if (204 == this.statusCode || 304 == this.statusCode) { + this.removeHeader('Content-Type'); + this.removeHeader('Content-Length'); + this.removeHeader('Transfer-Encoding'); + body = ''; + } + + // respond + this.end(head ? null : body); + return this; +}; + +/** + * Send JSON response. + * + * Examples: + * + * res.json(null); + * res.json({ user: 'tj' }); + * res.json(500, 'oh noes!'); + * res.json(404, 'I dont have that'); + * + * @param {Mixed} obj or status + * @param {Mixed} obj + * @return {ServerResponse} + * @api public + */ + +res.json = function(obj){ + // allow status / body + if (2 == arguments.length) { + // res.json(body, status) backwards compat + if ('number' == typeof arguments[1]) { + this.statusCode = arguments[1]; + } else { + this.statusCode = obj; + obj = arguments[1]; + } + } + + // settings + var app = this.app; + var replacer = app.get('json replacer'); + var spaces = app.get('json spaces'); + var body = JSON.stringify(obj, replacer, spaces); + + // content-type + this.charset = this.charset || 'utf-8'; + this.get('Content-Type') || this.set('Content-Type', 'application/json'); + + return this.send(body); +}; + +/** + * Send JSON response with JSONP callback support. + * + * Examples: + * + * res.jsonp(null); + * res.jsonp({ user: 'tj' }); + * res.jsonp(500, 'oh noes!'); + * res.jsonp(404, 'I dont have that'); + * + * @param {Mixed} obj or status + * @param {Mixed} obj + * @return {ServerResponse} + * @api public + */ + +res.jsonp = function(obj){ + // allow status / body + if (2 == arguments.length) { + // res.json(body, status) backwards compat + if ('number' == typeof arguments[1]) { + this.statusCode = arguments[1]; + } else { + this.statusCode = obj; + obj = arguments[1]; + } + } + + // settings + var app = this.app; + var replacer = app.get('json replacer'); + var spaces = app.get('json spaces'); + var body = JSON.stringify(obj, replacer, spaces) + .replace(/\u2028/g, '\\u2028') + .replace(/\u2029/g, '\\u2029'); + var callback = this.req.query[app.get('jsonp callback name')]; + + // content-type + this.charset = this.charset || 'utf-8'; + this.set('Content-Type', 'application/json'); + + // jsonp + if (callback) { + if (Array.isArray(callback)) callback = callback[0]; + this.set('Content-Type', 'text/javascript'); + var cb = callback.replace(/[^\[\]\w$.]/g, ''); + body = 'typeof ' + cb + ' === \'function\' && ' + cb + '(' + body + ');'; + } + + return this.send(body); +}; + +/** + * Transfer the file at the given `path`. + * + * Automatically sets the _Content-Type_ response header field. + * The callback `fn(err)` is invoked when the transfer is complete + * or when an error occurs. Be sure to check `res.sentHeader` + * if you wish to attempt responding, as the header and some data + * may have already been transferred. + * + * Options: + * + * - `maxAge` defaulting to 0 + * - `root` root directory for relative filenames + * + * Examples: + * + * The following example illustrates how `res.sendfile()` may + * be used as an alternative for the `static()` middleware for + * dynamic situations. The code backing `res.sendfile()` is actually + * the same code, so HTTP cache support etc is identical. + * + * app.get('/user/:uid/photos/:file', function(req, res){ + * var uid = req.params.uid + * , file = req.params.file; + * + * req.user.mayViewFilesFrom(uid, function(yes){ + * if (yes) { + * res.sendfile('/uploads/' + uid + '/' + file); + * } else { + * res.send(403, 'Sorry! you cant see that.'); + * } + * }); + * }); + * + * @param {String} path + * @param {Object|Function} options or fn + * @param {Function} fn + * @api public + */ + +res.sendfile = function(path, options, fn){ + var self = this + , req = self.req + , next = this.req.next + , options = options || {} + , done; + + // support function as second arg + if ('function' == typeof options) { + fn = options; + options = {}; + } + + // socket errors + req.socket.on('error', error); + + // errors + function error(err) { + if (done) return; + done = true; + + // clean up + cleanup(); + if (!self.headerSent) self.removeHeader('Content-Disposition'); + + // callback available + if (fn) return fn(err); + + // list in limbo if there's no callback + if (self.headerSent) return; + + // delegate + next(err); + } + + // streaming + function stream(stream) { + if (done) return; + cleanup(); + if (fn) stream.on('end', fn); + } + + // cleanup + function cleanup() { + req.socket.removeListener('error', error); + } + + // transfer + var file = send(req, path); + if (options.root) file.root(options.root); + file.maxage(options.maxAge || 0); + file.on('error', error); + file.on('directory', next); + file.on('stream', stream); + file.pipe(this); + this.on('finish', cleanup); +}; + +/** + * Transfer the file at the given `path` as an attachment. + * + * Optionally providing an alternate attachment `filename`, + * and optional callback `fn(err)`. The callback is invoked + * when the data transfer is complete, or when an error has + * ocurred. Be sure to check `res.headerSent` if you plan to respond. + * + * This method uses `res.sendfile()`. + * + * @param {String} path + * @param {String|Function} filename or fn + * @param {Function} fn + * @api public + */ + +res.download = function(path, filename, fn){ + // support function as second arg + if ('function' == typeof filename) { + fn = filename; + filename = null; + } + + filename = filename || path; + this.set('Content-Disposition', 'attachment; filename="' + basename(filename) + '"'); + return this.sendfile(path, fn); +}; + +/** + * Set _Content-Type_ response header with `type` through `mime.lookup()` + * when it does not contain "/", or set the Content-Type to `type` otherwise. + * + * Examples: + * + * res.type('.html'); + * res.type('html'); + * res.type('json'); + * res.type('application/json'); + * res.type('png'); + * + * @param {String} type + * @return {ServerResponse} for chaining + * @api public + */ + +res.contentType = +res.type = function(type){ + return this.set('Content-Type', ~type.indexOf('/') + ? type + : mime.lookup(type)); +}; + +/** + * Respond to the Acceptable formats using an `obj` + * of mime-type callbacks. + * + * This method uses `req.accepted`, an array of + * acceptable types ordered by their quality values. + * When "Accept" is not present the _first_ callback + * is invoked, otherwise the first match is used. When + * no match is performed the server responds with + * 406 "Not Acceptable". + * + * Content-Type is set for you, however if you choose + * you may alter this within the callback using `res.type()` + * or `res.set('Content-Type', ...)`. + * + * res.format({ + * 'text/plain': function(){ + * res.send('hey'); + * }, + * + * 'text/html': function(){ + * res.send('

hey

'); + * }, + * + * 'appliation/json': function(){ + * res.send({ message: 'hey' }); + * } + * }); + * + * In addition to canonicalized MIME types you may + * also use extnames mapped to these types: + * + * res.format({ + * text: function(){ + * res.send('hey'); + * }, + * + * html: function(){ + * res.send('

hey

'); + * }, + * + * json: function(){ + * res.send({ message: 'hey' }); + * } + * }); + * + * By default Express passes an `Error` + * with a `.status` of 406 to `next(err)` + * if a match is not made. If you provide + * a `.default` callback it will be invoked + * instead. + * + * @param {Object} obj + * @return {ServerResponse} for chaining + * @api public + */ + +res.format = function(obj){ + var req = this.req + , next = req.next; + + var fn = obj.default; + if (fn) delete obj.default; + var keys = Object.keys(obj); + + var key = req.accepts(keys); + + this.vary("Accept"); + + if (key) { + var type = normalizeType(key).value; + var charset = mime.charsets.lookup(type); + if (charset) type += '; charset=' + charset; + this.set('Content-Type', type); + obj[key](req, this, next); + } else if (fn) { + fn(); + } else { + var err = new Error('Not Acceptable'); + err.status = 406; + err.types = normalizeTypes(keys).map(function(o){ return o.value }); + next(err); + } + + return this; +}; + +/** + * Set _Content-Disposition_ header to _attachment_ with optional `filename`. + * + * @param {String} filename + * @return {ServerResponse} + * @api public + */ + +res.attachment = function(filename){ + if (filename) this.type(extname(filename)); + this.set('Content-Disposition', filename + ? 'attachment; filename="' + basename(filename) + '"' + : 'attachment'); + return this; +}; + +/** + * Set header `field` to `val`, or pass + * an object of header fields. + * + * Examples: + * + * res.set('Foo', ['bar', 'baz']); + * res.set('Accept', 'application/json'); + * res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' }); + * + * Aliased as `res.header()`. + * + * @param {String|Object|Array} field + * @param {String} val + * @return {ServerResponse} for chaining + * @api public + */ + +res.set = +res.header = function(field, val){ + if (2 == arguments.length) { + if (Array.isArray(val)) val = val.map(String); + else val = String(val); + this.setHeader(field, val); + } else { + for (var key in field) { + this.set(key, field[key]); + } + } + return this; +}; + +/** + * Get value for header `field`. + * + * @param {String} field + * @return {String} + * @api public + */ + +res.get = function(field){ + return this.getHeader(field); +}; + +/** + * Clear cookie `name`. + * + * @param {String} name + * @param {Object} options + * @param {ServerResponse} for chaining + * @api public + */ + +res.clearCookie = function(name, options){ + var opts = { expires: new Date(1), path: '/' }; + return this.cookie(name, '', options + ? utils.merge(opts, options) + : opts); +}; + +/** + * Set cookie `name` to `val`, with the given `options`. + * + * Options: + * + * - `maxAge` max-age in milliseconds, converted to `expires` + * - `signed` sign the cookie + * - `path` defaults to "/" + * + * 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|Object} val + * @param {Options} options + * @api public + */ + +res.cookie = function(name, val, options){ + options = utils.merge({}, options); + var secret = this.req.secret; + var signed = options.signed; + if (signed && !secret) throw new Error('connect.cookieParser("secret") required for signed cookies'); + if ('number' == typeof val) val = val.toString(); + if ('object' == typeof val) val = 'j:' + JSON.stringify(val); + if (signed) val = 's:' + sign(val, secret); + if ('maxAge' in options) { + options.expires = new Date(Date.now() + options.maxAge); + options.maxAge /= 1000; + } + if (null == options.path) options.path = '/'; + this.set('Set-Cookie', cookie.serialize(name, String(val), options)); + return this; +}; + + +/** + * Set the location header to `url`. + * + * 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 "/". + * + * Examples: + * + * res.location('/foo/bar').; + * res.location('http://example.com'); + * res.location('../login'); // /blog/post/1 -> /blog/login + * + * Mounting: + * + * When an application is mounted and `res.location()` + * is given a path that does _not_ lead with "/" it becomes + * relative to the mount-point. For example if the application + * is mounted at "/blog", the following would become "/blog/login". + * + * res.location('login'); + * + * While the leading slash would result in a location of "/login": + * + * res.location('/login'); + * + * @param {String} url + * @api public + */ + +res.location = function(url){ + var app = this.app + , req = this.req; + + // setup redirect map + var map = { back: req.get('Referrer') || '/' }; + + // perform redirect + url = map[url] || url; + + // relative + if (!~url.indexOf('://') && 0 != url.indexOf('//')) { + var path + + // relative to path + if ('.' == url[0]) { + path = req.originalUrl.split('?')[0] + url = path + ('/' == path[path.length - 1] ? '' : '/') + url; + // relative to mount-point + } else if ('/' != url[0]) { + path = app.path(); + url = path + '/' + url; + } + } + + // Respond + this.set('Location', url); + return this; +}; + +/** + * Redirect to the given `url` with optional response `status` + * defaulting to 302. + * + * The resulting `url` is determined by `res.location()`, so + * it will play nicely with mounted apps, relative paths, + * `"back"` etc. + * + * Examples: + * + * res.redirect('/foo/bar'); + * res.redirect('http://example.com'); + * res.redirect(301, 'http://example.com'); + * res.redirect('http://example.com', 301); + * res.redirect('../login'); // /blog/post/1 -> /blog/login + * + * @param {String} url + * @param {Number} code + * @api public + */ + +res.redirect = function(url){ + var head = 'HEAD' == this.req.method + , status = 302 + , body; + + // allow status / url + if (2 == arguments.length) { + if ('number' == typeof url) { + status = url; + url = arguments[1]; + } else { + status = arguments[1]; + } + } + + // Set location header + this.location(url); + url = this.get('Location'); + + // Support text/{plain,html} by default + this.format({ + text: function(){ + body = statusCodes[status] + '. Redirecting to ' + encodeURI(url); + }, + + html: function(){ + var u = utils.escape(url); + body = '

' + statusCodes[status] + '. Redirecting to ' + u + '

'; + }, + + default: function(){ + body = ''; + } + }); + + // Respond + this.statusCode = status; + this.set('Content-Length', Buffer.byteLength(body)); + this.end(head ? null : body); +}; + +/** + * Add `field` to Vary. If already present in the Vary set, then + * this call is simply ignored. + * + * @param {Array|String} field + * @param {ServerResponse} for chaining + * @api public + */ + +res.vary = function(field){ + var self = this; + + // nothing + if (!field) return this; + + // array + if (Array.isArray(field)) { + field.forEach(function(field){ + self.vary(field); + }); + return; + } + + var vary = this.get('Vary'); + + // append + if (vary) { + vary = vary.split(/ *, */); + if (!~vary.indexOf(field)) vary.push(field); + this.set('Vary', vary.join(', ')); + return this; + } + + // set + this.set('Vary', field); + return this; +}; + +/** + * Render `view` with the given `options` and optional callback `fn`. + * When a callback function is given a response will _not_ be made + * automatically, otherwise a response of _200_ and _text/html_ is given. + * + * Options: + * + * - `cache` boolean hinting to the engine it should cache + * - `filename` filename of the view being rendered + * + * @param {String} view + * @param {Object|Function} options or callback function + * @param {Function} fn + * @api public + */ + +res.render = function(view, options, fn){ + var self = this + , options = options || {} + , req = this.req + , app = req.app; + + // support callback function as second arg + if ('function' == typeof options) { + fn = options, options = {}; + } + + // merge res.locals + options._locals = self.locals; + + // default callback to respond + fn = fn || function(err, str){ + if (err) return req.next(err); + self.send(str); + }; + + // render + app.render(view, options, fn); +}; diff --git a/node_modules/express/lib/router/index.js b/node_modules/express/lib/router/index.js new file mode 100644 index 0000000..12f112d --- /dev/null +++ b/node_modules/express/lib/router/index.js @@ -0,0 +1,311 @@ +/** + * Module dependencies. + */ + +var Route = require('./route') + , utils = require('../utils') + , methods = require('methods') + , debug = require('debug')('express:router') + , parse = require('connect').utils.parseUrl; + +/** + * Expose `Router` constructor. + */ + +exports = module.exports = Router; + +/** + * Initialize a new `Router` with the given `options`. + * + * @param {Object} options + * @api private + */ + +function Router(options) { + options = options || {}; + var self = this; + this.map = {}; + this.params = {}; + this._params = []; + this.caseSensitive = options.caseSensitive; + this.strict = options.strict; + this.middleware = function router(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] = this.params[name] || []).push(fn); + return this; +}; + +/** + * 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; + + debug('dispatching %s %s (%s)', req.method, req.url, req.originalUrl); + + // route dispatch + (function pass(i, err){ + var paramCallbacks + , paramIndex = 0 + , paramVal + , route + , keys + , key; + + // match next route + function nextRoute(err) { + pass(req._route_index + 1, err); + } + + // match route + req.route = route = self.matchRequest(req, i); + + // implied OPTIONS + if (!route && 'OPTIONS' == req.method) return self._options(req, res); + + // no route + if (!route) return next(err); + debug('matched %s %s', route.method, route.path); + + // we have a route + // start at param 0 + req.params = route.params; + keys = route.keys; + i = 0; + + // param callbacks + function param(err) { + paramIndex = 0; + key = keys[i++]; + paramVal = key && req.params[key.name]; + paramCallbacks = key && params[key.name]; + + try { + if ('route' == err) { + nextRoute(); + } else if (err) { + i = 0; + callbacks(err); + } else if (paramCallbacks && undefined !== paramVal) { + paramCallback(); + } else if (key) { + param(); + } else { + i = 0; + callbacks(); + } + } catch (err) { + param(err); + } + }; + + param(err); + + // single param callbacks + function paramCallback(err) { + var fn = paramCallbacks[paramIndex++]; + if (err || !fn) return param(err); + fn(req, res, paramCallback, paramVal, key.name); + } + + // invoke route callbacks + function callbacks(err) { + var fn = route.callbacks[i++]; + try { + if ('route' == err) { + nextRoute(); + } else if (err && fn) { + if (fn.length < 4) return callbacks(err); + fn(err, req, res, callbacks); + } else if (fn) { + if (fn.length < 4) return fn(req, res, callbacks); + callbacks(); + } else { + nextRoute(err); + } + } catch (err) { + callbacks(err); + } + } + })(0); +}; + +/** + * Respond to __OPTIONS__ method. + * + * @param {IncomingMessage} req + * @param {ServerResponse} res + * @api private + */ + +Router.prototype._options = function(req, res){ + var path = parse(req).pathname + , body = this._optionsFor(path).join(','); + res.set('Allow', body).send(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.map[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` + * with optional starting index of `i` + * defaulting to 0. + * + * @param {IncomingMessage} req + * @param {Number} i + * @return {Route} + * @api private + */ + +Router.prototype.matchRequest = function(req, i, head){ + var method = req.method.toLowerCase() + , url = parse(req) + , path = url.pathname + , routes = this.map + , i = i || 0 + , route; + + // HEAD support + if (!head && 'head' == method) { + route = this.matchRequest(req, i, true); + if (route) return route; + method = 'get'; + } + + // routes for this method + if (routes = routes[method]) { + + // matching routes + for (var len = routes.length; i < len; ++i) { + route = routes[i]; + if (route.match(path)) { + req._route_index = i; + return route; + } + } + } +}; + +/** + * Attempt to match a route for `method` + * and `url` with optional starting + * index of `i` defaulting to 0. + * + * @param {String} method + * @param {String} url + * @param {Number} i + * @return {Route} + * @api private + */ + +Router.prototype.match = function(method, url, i, head){ + var req = { method: method, url: url }; + return this.matchRequest(req, i, head); +}; + +/** + * Route `method`, `path`, and one or more callbacks. + * + * @param {String} method + * @param {String} path + * @param {Function} callback... + * @return {Router} for chaining + * @api private + */ + +Router.prototype.route = function(method, path, callbacks){ + var method = method.toLowerCase() + , callbacks = utils.flatten([].slice.call(arguments, 2)); + + // ensure path was given + if (!path) throw new Error('Router#' + method + '() requires a path'); + + // ensure all callbacks are functions + callbacks.forEach(function(fn){ + if ('function' == typeof fn) return; + var type = {}.toString.call(fn); + var msg = '.' + method + '() requires callback functions but got a ' + type; + throw new Error(msg); + }); + + // create the route + debug('defined %s %s', method, path); + var route = new Route(method, path, callbacks, { + sensitive: this.caseSensitive, + strict: this.strict + }); + + // add it + (this.map[method] = this.map[method] || []).push(route); + return this; +}; + +methods.forEach(function(method){ + Router.prototype[method] = function(path){ + var args = [method].concat([].slice.call(arguments)); + this.route.apply(this, args); + return this; + }; +}); diff --git a/node_modules/express/lib/router/route.js b/node_modules/express/lib/router/route.js new file mode 100644 index 0000000..4334c88 --- /dev/null +++ b/node_modules/express/lib/router/route.js @@ -0,0 +1,72 @@ + +/** + * Module dependencies. + */ + +var utils = require('../utils'); + +/** + * Expose `Route`. + */ + +module.exports = Route; + +/** + * Initialize `Route` with the given HTTP `method`, `path`, + * and an array of `callbacks` and `options`. + * + * Options: + * + * - `sensitive` enable case-sensitive routes + * - `strict` enable strict matching for trailing slashes + * + * @param {String} method + * @param {String} path + * @param {Array} callbacks + * @param {Object} options. + * @api private + */ + +function Route(method, path, callbacks, options) { + options = options || {}; + this.path = path; + this.method = method; + this.callbacks = callbacks; + this.regexp = utils.pathRegexp(path + , this.keys = [] + , options.sensitive + , options.strict); +} + +/** + * Check if this route matches `path`, if so + * populate `.params`. + * + * @param {String} path + * @return {Boolean} + * @api private + */ + +Route.prototype.match = function(path){ + var keys = this.keys + , params = this.params = [] + , m = this.regexp.exec(path); + + if (!m) return false; + + for (var i = 1, len = m.length; i < len; ++i) { + var key = keys[i - 1]; + + var val = 'string' == typeof m[i] + ? utils.decode(m[i]) + : m[i]; + + if (key) { + params[key.name] = val; + } else { + params.push(val); + } + } + + return true; +}; diff --git a/node_modules/express/lib/utils.js b/node_modules/express/lib/utils.js new file mode 100644 index 0000000..f19061b --- /dev/null +++ b/node_modules/express/lib/utils.js @@ -0,0 +1,333 @@ + +/** + * Module dependencies. + */ + +var mime = require('connect').mime + , crc32 = require('buffer-crc32'); + +/** + * toString ref. + */ + +var toString = {}.toString; + +/** + * Return ETag for `body`. + * + * @param {String|Buffer} body + * @return {String} + * @api private + */ + +exports.etag = function(body){ + return '"' + crc32.signed(body) + '"'; +}; + +/** + * Make `locals()` bound to the given `obj`. + * + * This is used for `app.locals` and `res.locals`. + * + * @param {Object} obj + * @return {Function} + * @api private + */ + +exports.locals = function(){ + function locals(obj){ + for (var key in obj) locals[key] = obj[key]; + return obj; + }; + + return locals; +}; + +/** + * Check if `path` looks absolute. + * + * @param {String} path + * @return {Boolean} + * @api private + */ + +exports.isAbsolute = function(path){ + if ('/' == path[0]) return true; + if (':' == path[1] && '\\' == path[2]) return true; + if ('\\\\' == path.substring(0, 2)) return true; // Microsoft Azure absolute path +}; + +/** + * 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; +}; + +/** + * Normalize the given `type`, for example "html" becomes "text/html". + * + * @param {String} type + * @return {Object} + * @api private + */ + +exports.normalizeType = function(type){ + return ~type.indexOf('/') + ? acceptParams(type) + : { value: mime.lookup(type), params: {} }; +}; + +/** + * Normalize `types`, for example "html" becomes "text/html". + * + * @param {Array} types + * @return {Array} + * @api private + */ + +exports.normalizeTypes = function(types){ + var ret = []; + + for (var i = 0; i < types.length; ++i) { + ret.push(exports.normalizeType(types[i])); + } + + return ret; +}; + +/** + * Return the acceptable type in `types`, if any. + * + * @param {Array} types + * @param {String} str + * @return {String} + * @api private + */ + +exports.acceptsArray = function(types, str){ + // accept anything when Accept is not present + if (!str) return types[0]; + + // parse + var accepted = exports.parseAccept(str) + , normalized = exports.normalizeTypes(types) + , len = accepted.length; + + for (var i = 0; i < len; ++i) { + for (var j = 0, jlen = types.length; j < jlen; ++j) { + if (exports.accept(normalized[j], accepted[i])) { + return types[j]; + } + } + } +}; + +/** + * Check if `type(s)` are acceptable based on + * the given `str`. + * + * @param {String|Array} type(s) + * @param {String} str + * @return {Boolean|String} + * @api private + */ + +exports.accepts = function(type, str){ + if ('string' == typeof type) type = type.split(/ *, */); + return exports.acceptsArray(type, str); +}; + +/** + * Check if `type` array is acceptable for `other`. + * + * @param {Object} type + * @param {Object} other + * @return {Boolean} + * @api private + */ + +exports.accept = function(type, other){ + var t = type.value.split('/'); + return (t[0] == other.type || '*' == other.type) + && (t[1] == other.subtype || '*' == other.subtype) + && paramsEqual(type.params, other.params); +}; + +/** + * Check if accept params are equal. + * + * @param {Object} a + * @param {Object} b + * @return {Boolean} + * @api private + */ + +function paramsEqual(a, b){ + return !Object.keys(a).some(function(k) { + return a[k] != b[k]; + }); +} + +/** + * Parse accept `str`, returning + * an array objects containing + * `.type` and `.subtype` along + * with the values provided by + * `parseQuality()`. + * + * @param {Type} name + * @return {Type} + * @api private + */ + +exports.parseAccept = function(str){ + return exports + .parseParams(str) + .map(function(obj){ + var parts = obj.value.split('/'); + obj.type = parts[0]; + obj.subtype = parts[1]; + return obj; + }); +}; + +/** + * Parse quality `str`, returning an + * array of objects with `.value`, + * `.quality` and optional `.params` + * + * @param {String} str + * @return {Array} + * @api private + */ + +exports.parseParams = function(str){ + return str + .split(/ *, */) + .map(acceptParams) + .filter(function(obj){ + return obj.quality; + }) + .sort(function(a, b){ + if (a.quality === b.quality) { + return a.originalIndex - b.originalIndex; + } else { + return b.quality - a.quality; + } + }); +}; + +/** + * Parse accept params `str` returning an + * object with `.value`, `.quality` and `.params`. + * also includes `.originalIndex` for stable sorting + * + * @param {String} str + * @return {Object} + * @api private + */ + +function acceptParams(str, index) { + var parts = str.split(/ *; */); + var ret = { value: parts[0], quality: 1, params: {}, originalIndex: index }; + + for (var i = 1; i < parts.length; ++i) { + var pms = parts[i].split(/ *= */); + if ('q' == pms[0]) { + ret.quality = parseFloat(pms[1]); + } else { + ret.params[pms[0]] = pms[1]; + } + } + + return ret; +} + +/** + * 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, '>'); +}; + +/** + * 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|Array} path + * @param {Array} keys + * @param {Boolean} sensitive + * @param {Boolean} strict + * @return {RegExp} + * @api private + */ + +exports.pathRegexp = function(path, keys, sensitive, strict) { + if (toString.call(path) == '[object RegExp]') return path; + if (Array.isArray(path)) path = '(' + path.join('|') + ')'; + path = path + .concat(strict ? '' : '/?') + .replace(/\/\(/g, '(?:/') + .replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?(\*)?/g, function(_, slash, format, key, capture, optional, star){ + keys.push({ name: key, optional: !! optional }); + slash = slash || ''; + return '' + + (optional ? '' : slash) + + '(?:' + + (optional ? slash : '') + + (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')' + + (optional || '') + + (star ? '(/*)?' : ''); + }) + .replace(/([\/.])/g, '\\$1') + .replace(/\*/g, '(.*)'); + return new RegExp('^' + path + '$', sensitive ? '' : 'i'); +} + + +/** + * Decodes a URI component. Returns + * the original string if the component + * is malformed. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.decode = function(str) { + try { + return decodeURIComponent(str); + } catch (e) { + return str; + } +} diff --git a/node_modules/express/lib/view.js b/node_modules/express/lib/view.js new file mode 100644 index 0000000..b9dc69e --- /dev/null +++ b/node_modules/express/lib/view.js @@ -0,0 +1,77 @@ +/** + * Module dependencies. + */ + +var path = require('path') + , fs = require('fs') + , utils = require('./utils') + , dirname = path.dirname + , basename = path.basename + , extname = path.extname + , exists = fs.existsSync || path.existsSync + , join = path.join; + +/** + * Expose `View`. + */ + +module.exports = View; + +/** + * Initialize a new `View` with the given `name`. + * + * Options: + * + * - `defaultEngine` the default template engine name + * - `engines` template engine require() cache + * - `root` root path for view lookup + * + * @param {String} name + * @param {Object} options + * @api private + */ + +function View(name, options) { + options = options || {}; + this.name = name; + this.root = options.root; + var engines = options.engines; + this.defaultEngine = options.defaultEngine; + var ext = this.ext = extname(name); + if (!ext && !this.defaultEngine) throw new Error('No default engine was specified and no extension was provided.'); + if (!ext) name += (ext = this.ext = ('.' != this.defaultEngine[0] ? '.' : '') + this.defaultEngine); + this.engine = engines[ext] || (engines[ext] = require(ext.slice(1)).__express); + this.path = this.lookup(name); +} + +/** + * Lookup view by the given `path` + * + * @param {String} path + * @return {String} + * @api private + */ + +View.prototype.lookup = function(path){ + var ext = this.ext; + + // . + if (!utils.isAbsolute(path)) path = join(this.root, path); + if (exists(path)) return path; + + // /index. + path = join(dirname(path), basename(path, ext), 'index' + ext); + if (exists(path)) return path; +}; + +/** + * Render with the given `options` and callback `fn(err, str)`. + * + * @param {Object} options + * @param {Function} fn + * @api private + */ + +View.prototype.render = function(options, fn){ + this.engine(this.path, options, fn); +}; diff --git a/node_modules/express/node_modules/buffer-crc32/.npmignore b/node_modules/express/node_modules/buffer-crc32/.npmignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/node_modules/express/node_modules/buffer-crc32/.npmignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/node_modules/express/node_modules/buffer-crc32/.travis.yml b/node_modules/express/node_modules/buffer-crc32/.travis.yml new file mode 100644 index 0000000..7a902e8 --- /dev/null +++ b/node_modules/express/node_modules/buffer-crc32/.travis.yml @@ -0,0 +1,8 @@ +language: node_js +node_js: + - 0.6 + - 0.8 +notifications: + email: + recipients: + - brianloveswords@gmail.com \ No newline at end of file diff --git a/node_modules/express/node_modules/buffer-crc32/README.md b/node_modules/express/node_modules/buffer-crc32/README.md new file mode 100644 index 0000000..0d9d8b8 --- /dev/null +++ b/node_modules/express/node_modules/buffer-crc32/README.md @@ -0,0 +1,47 @@ +# buffer-crc32 + +[![Build Status](https://secure.travis-ci.org/brianloveswords/buffer-crc32.png?branch=master)](http://travis-ci.org/brianloveswords/buffer-crc32) + +crc32 that works with binary data and fancy character sets, outputs +buffer, signed or unsigned data and has tests. + +Derived from the sample CRC implementation in the PNG specification: http://www.w3.org/TR/PNG/#D-CRCAppendix + +# install +``` +npm install buffer-crc32 +``` + +# example +```js +var crc32 = require('buffer-crc32'); +// works with buffers +var buf = Buffer([0x00, 0x73, 0x75, 0x70, 0x20, 0x62, 0x72, 0x6f, 0x00]) +crc32(buf) // -> + +// has convenience methods for getting signed or unsigned ints +crc32.signed(buf) // -> -1805997238 +crc32.unsigned(buf) // -> 2488970058 + +// will cast to buffer if given a string, so you can +// directly use foreign characters safely +crc32('自動販売機') // -> + +// and works in append mode too +var partialCrc = crc32('hey'); +var partialCrc = crc32(' ', partialCrc); +var partialCrc = crc32('sup', partialCrc); +var partialCrc = crc32(' ', partialCrc); +var finalCrc = crc32('bros', partialCrc); // -> +``` + +# tests +This was tested against the output of zlib's crc32 method. You can run +the tests with`npm test` (requires tap) + +# see also +https://github.com/alexgorbatchev/node-crc, `crc.buffer.crc32` also +supports buffer inputs and return unsigned ints (thanks @tjholowaychuk). + +# license +MIT/X11 diff --git a/node_modules/express/node_modules/buffer-crc32/index.js b/node_modules/express/node_modules/buffer-crc32/index.js new file mode 100644 index 0000000..e29ce3e --- /dev/null +++ b/node_modules/express/node_modules/buffer-crc32/index.js @@ -0,0 +1,88 @@ +var Buffer = require('buffer').Buffer; + +var CRC_TABLE = [ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d +]; + +function bufferizeInt(num) { + var tmp = Buffer(4); + tmp.writeInt32BE(num, 0); + return tmp; +} + +function _crc32(buf, previous) { + if (!Buffer.isBuffer(buf)) { + buf = Buffer(buf); + } + if (Buffer.isBuffer(previous)) { + previous = previous.readUInt32BE(0); + } + var crc = ~~previous ^ -1; + for (var n = 0; n < buf.length; n++) { + crc = CRC_TABLE[(crc ^ buf[n]) & 0xff] ^ (crc >>> 8); + } + return (crc ^ -1); +} + +function crc32() { + return bufferizeInt(_crc32.apply(null, arguments)); +} +crc32.signed = function () { + return _crc32.apply(null, arguments); +}; +crc32.unsigned = function () { + return _crc32.apply(null, arguments) >>> 0; +}; + +module.exports = crc32; diff --git a/node_modules/express/node_modules/buffer-crc32/package.json b/node_modules/express/node_modules/buffer-crc32/package.json new file mode 100644 index 0000000..c702600 --- /dev/null +++ b/node_modules/express/node_modules/buffer-crc32/package.json @@ -0,0 +1,43 @@ +{ + "author": { + "name": "Brian J. Brennan", + "email": "brianloveswords@gmail.com", + "url": "http://bjb.io" + }, + "name": "buffer-crc32", + "description": "A pure javascript CRC32 algorithm that plays nice with binary data", + "version": "0.2.1", + "contributors": [ + { + "name": "Vladimir Kuznetsov" + } + ], + "homepage": "https://github.com/brianloveswords/buffer-crc32", + "repository": { + "type": "git", + "url": "git://github.com/brianloveswords/buffer-crc32.git" + }, + "main": "index.js", + "scripts": { + "test": "./node_modules/.bin/tap tests/*.test.js" + }, + "dependencies": {}, + "devDependencies": { + "tap": "~0.2.5" + }, + "optionalDependencies": {}, + "engines": { + "node": "*" + }, + "readme": "# buffer-crc32\n\n[![Build Status](https://secure.travis-ci.org/brianloveswords/buffer-crc32.png?branch=master)](http://travis-ci.org/brianloveswords/buffer-crc32)\n\ncrc32 that works with binary data and fancy character sets, outputs\nbuffer, signed or unsigned data and has tests.\n\nDerived from the sample CRC implementation in the PNG specification: http://www.w3.org/TR/PNG/#D-CRCAppendix\n\n# install\n```\nnpm install buffer-crc32\n```\n\n# example\n```js\nvar crc32 = require('buffer-crc32');\n// works with buffers\nvar buf = Buffer([0x00, 0x73, 0x75, 0x70, 0x20, 0x62, 0x72, 0x6f, 0x00])\ncrc32(buf) // -> \n\n// has convenience methods for getting signed or unsigned ints\ncrc32.signed(buf) // -> -1805997238\ncrc32.unsigned(buf) // -> 2488970058\n\n// will cast to buffer if given a string, so you can\n// directly use foreign characters safely\ncrc32('自動販売機') // -> \n\n// and works in append mode too\nvar partialCrc = crc32('hey');\nvar partialCrc = crc32(' ', partialCrc);\nvar partialCrc = crc32('sup', partialCrc);\nvar partialCrc = crc32(' ', partialCrc);\nvar finalCrc = crc32('bros', partialCrc); // -> \n```\n\n# tests\nThis was tested against the output of zlib's crc32 method. You can run\nthe tests with`npm test` (requires tap)\n\n# see also\nhttps://github.com/alexgorbatchev/node-crc, `crc.buffer.crc32` also\nsupports buffer inputs and return unsigned ints (thanks @tjholowaychuk).\n\n# license\nMIT/X11\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/brianloveswords/buffer-crc32/issues" + }, + "_id": "buffer-crc32@0.2.1", + "dist": { + "shasum": "be3e5382fc02b6d6324956ac1af98aa98b08534c" + }, + "_from": "buffer-crc32@0.2.1", + "_resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz" +} diff --git a/node_modules/express/node_modules/buffer-crc32/tests/crc.test.js b/node_modules/express/node_modules/buffer-crc32/tests/crc.test.js new file mode 100644 index 0000000..bb0f9ef --- /dev/null +++ b/node_modules/express/node_modules/buffer-crc32/tests/crc.test.js @@ -0,0 +1,89 @@ +var crc32 = require('..'); +var test = require('tap').test; + +test('simple crc32 is no problem', function (t) { + var input = Buffer('hey sup bros'); + var expected = Buffer([0x47, 0xfa, 0x55, 0x70]); + t.same(crc32(input), expected); + t.end(); +}); + +test('another simple one', function (t) { + var input = Buffer('IEND'); + var expected = Buffer([0xae, 0x42, 0x60, 0x82]); + t.same(crc32(input), expected); + t.end(); +}); + +test('slightly more complex', function (t) { + var input = Buffer([0x00, 0x00, 0x00]); + var expected = Buffer([0xff, 0x41, 0xd9, 0x12]); + t.same(crc32(input), expected); + t.end(); +}); + +test('complex crc32 gets calculated like a champ', function (t) { + var input = Buffer('शीर्षक'); + var expected = Buffer([0x17, 0xb8, 0xaf, 0xf1]); + t.same(crc32(input), expected); + t.end(); +}); + +test('casts to buffer if necessary', function (t) { + var input = 'शीर्षक'; + var expected = Buffer([0x17, 0xb8, 0xaf, 0xf1]); + t.same(crc32(input), expected); + t.end(); +}); + +test('can do signed', function (t) { + var input = 'ham sandwich'; + var expected = -1891873021; + t.same(crc32.signed(input), expected); + t.end(); +}); + +test('can do unsigned', function (t) { + var input = 'bear sandwich'; + var expected = 3711466352; + t.same(crc32.unsigned(input), expected); + t.end(); +}); + + +test('simple crc32 in append mode', function (t) { + var input = [Buffer('hey'), Buffer(' '), Buffer('sup'), Buffer(' '), Buffer('bros')]; + var expected = Buffer([0x47, 0xfa, 0x55, 0x70]); + for (var crc = 0, i = 0; i < input.length; i++) { + crc = crc32(input[i], crc); + } + t.same(crc, expected); + t.end(); +}); + + +test('can do signed in append mode', function (t) { + var input1 = 'ham'; + var input2 = ' '; + var input3 = 'sandwich'; + var expected = -1891873021; + + var crc = crc32.signed(input1); + crc = crc32.signed(input2, crc); + crc = crc32.signed(input3, crc); + + t.same(crc, expected); + t.end(); +}); + +test('can do unsigned in append mode', function (t) { + var input1 = 'bear san'; + var input2 = 'dwich'; + var expected = 3711466352; + + var crc = crc32.unsigned(input1); + crc = crc32.unsigned(input2, crc); + t.same(crc, expected); + t.end(); +}); + diff --git a/node_modules/express/node_modules/commander/History.md b/node_modules/express/node_modules/commander/History.md new file mode 100644 index 0000000..ce046f6 --- /dev/null +++ b/node_modules/express/node_modules/commander/History.md @@ -0,0 +1,174 @@ + +1.3.2 / 2013-07-18 +================== + + * add support for sub-commands to co-exist with the original command + +1.3.1 / 2013-07-18 +================== + + * add quick .runningCommand hack so you can opt-out of other logic when running a sub command + +1.3.0 / 2013-07-09 +================== + + * add EACCES error handling + * fix sub-command --help + +1.2.0 / 2013-06-13 +================== + + * allow "-" hyphen as an option argument + * support for RegExp coercion + +1.1.1 / 2012-11-20 +================== + + * add more sub-command padding + * fix .usage() when args are present. Closes #106 + +1.1.0 / 2012-11-16 +================== + + * add git-style executable subcommand support. Closes #94 + +1.0.5 / 2012-10-09 +================== + + * fix `--name` clobbering. Closes #92 + * fix examples/help. Closes #89 + +1.0.4 / 2012-09-03 +================== + + * add `outputHelp()` method. + +1.0.3 / 2012-08-30 +================== + + * remove invalid .version() defaulting + +1.0.2 / 2012-08-24 +================== + + * add `--foo=bar` support [arv] + * fix password on node 0.8.8. Make backward compatible with 0.6 [focusaurus] + +1.0.1 / 2012-08-03 +================== + + * fix issue #56 + * fix tty.setRawMode(mode) was moved to tty.ReadStream#setRawMode() (i.e. process.stdin.setRawMode()) + +1.0.0 / 2012-07-05 +================== + + * add support for optional option descriptions + * add defaulting of `.version()` to package.json's version + +0.6.1 / 2012-06-01 +================== + + * Added: append (yes or no) on confirmation + * Added: allow node.js v0.7.x + +0.6.0 / 2012-04-10 +================== + + * Added `.prompt(obj, callback)` support. Closes #49 + * Added default support to .choose(). Closes #41 + * Fixed the choice example + +0.5.1 / 2011-12-20 +================== + + * Fixed `password()` for recent nodes. Closes #36 + +0.5.0 / 2011-12-04 +================== + + * Added sub-command option support [itay] + +0.4.3 / 2011-12-04 +================== + + * Fixed custom help ordering. Closes #32 + +0.4.2 / 2011-11-24 +================== + + * Added travis support + * Fixed: line-buffered input automatically trimmed. Closes #31 + +0.4.1 / 2011-11-18 +================== + + * Removed listening for "close" on --help + +0.4.0 / 2011-11-15 +================== + + * Added support for `--`. Closes #24 + +0.3.3 / 2011-11-14 +================== + + * Fixed: wait for close event when writing help info [Jerry Hamlet] + +0.3.2 / 2011-11-01 +================== + + * Fixed long flag definitions with values [felixge] + +0.3.1 / 2011-10-31 +================== + + * Changed `--version` short flag to `-V` from `-v` + * Changed `.version()` so it's configurable [felixge] + +0.3.0 / 2011-10-31 +================== + + * Added support for long flags only. Closes #18 + +0.2.1 / 2011-10-24 +================== + + * "node": ">= 0.4.x < 0.7.0". Closes #20 + +0.2.0 / 2011-09-26 +================== + + * Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs] + +0.1.0 / 2011-08-24 +================== + + * Added support for custom `--help` output + +0.0.5 / 2011-08-18 +================== + + * Changed: when the user enters nothing prompt for password again + * Fixed issue with passwords beginning with numbers [NuckChorris] + +0.0.4 / 2011-08-15 +================== + + * Fixed `Commander#args` + +0.0.3 / 2011-08-15 +================== + + * Added default option value support + +0.0.2 / 2011-08-15 +================== + + * Added mask support to `Command#password(str[, mask], fn)` + * Added `Command#password(str, fn)` + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/express/node_modules/commander/Readme.md b/node_modules/express/node_modules/commander/Readme.md new file mode 100644 index 0000000..ed0aeb2 --- /dev/null +++ b/node_modules/express/node_modules/commander/Readme.md @@ -0,0 +1,276 @@ +# Commander.js + + The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander). + + [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js) + +## Installation + + $ npm install commander + +## Option parsing + + Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options. + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('commander'); + +program + .version('0.0.1') + .option('-p, --peppers', 'Add peppers') + .option('-P, --pineapple', 'Add pineapple') + .option('-b, --bbq', 'Add bbq sauce') + .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble') + .parse(process.argv); + +console.log('you ordered a pizza with:'); +if (program.peppers) console.log(' - peppers'); +if (program.pineapple) console.log(' - pineapple'); +if (program.bbq) console.log(' - bbq'); +console.log(' - %s cheese', program.cheese); +``` + + Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc. + +## Automated --help + + The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free: + +``` + $ ./examples/pizza --help + + Usage: pizza [options] + + Options: + + -V, --version output the version number + -p, --peppers Add peppers + -P, --pineapple Add pineapple + -b, --bbq Add bbq sauce + -c, --cheese Add the specified type of cheese [marble] + -h, --help output usage information + +``` + +## Coercion + +```js +function range(val) { + return val.split('..').map(Number); +} + +function list(val) { + return val.split(','); +} + +program + .version('0.0.1') + .usage('[options] ') + .option('-i, --integer ', 'An integer argument', parseInt) + .option('-f, --float ', 'A float argument', parseFloat) + .option('-r, --range ..', 'A range', range) + .option('-l, --list ', 'A list', list) + .option('-o, --optional [value]', 'An optional value') + .parse(process.argv); + +console.log(' int: %j', program.integer); +console.log(' float: %j', program.float); +console.log(' optional: %j', program.optional); +program.range = program.range || []; +console.log(' range: %j..%j', program.range[0], program.range[1]); +console.log(' list: %j', program.list); +console.log(' args: %j', program.args); +``` + +## Custom help + + You can display arbitrary `-h, --help` information + by listening for "--help". Commander will automatically + exit once you are done so that the remainder of your program + does not execute causing undesired behaviours, for example + in the following executable "stuff" will not output when + `--help` is used. + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('../'); + +function list(val) { + return val.split(',').map(Number); +} + +program + .version('0.0.1') + .option('-f, --foo', 'enable some foo') + .option('-b, --bar', 'enable some bar') + .option('-B, --baz', 'enable some baz'); + +// must be before .parse() since +// node's emit() is immediate + +program.on('--help', function(){ + console.log(' Examples:'); + console.log(''); + console.log(' $ custom-help --help'); + console.log(' $ custom-help -h'); + console.log(''); +}); + +program.parse(process.argv); + +console.log('stuff'); +``` + +yielding the following help output: + +``` + +Usage: custom-help [options] + +Options: + + -h, --help output usage information + -V, --version output the version number + -f, --foo enable some foo + -b, --bar enable some bar + -B, --baz enable some baz + +Examples: + + $ custom-help --help + $ custom-help -h + +``` + +## .prompt(msg, fn) + + Single-line prompt: + +```js +program.prompt('name: ', function(name){ + console.log('hi %s', name); +}); +``` + + Multi-line prompt: + +```js +program.prompt('description:', function(name){ + console.log('hi %s', name); +}); +``` + + Coercion: + +```js +program.prompt('Age: ', Number, function(age){ + console.log('age: %j', age); +}); +``` + +```js +program.prompt('Birthdate: ', Date, function(date){ + console.log('date: %s', date); +}); +``` + +```js +program.prompt('Email: ', /^.+@.+\..+$/, function(email){ + console.log('email: %j', email); +}); +``` + +## .password(msg[, mask], fn) + +Prompt for password without echoing: + +```js +program.password('Password: ', function(pass){ + console.log('got "%s"', pass); + process.stdin.destroy(); +}); +``` + +Prompt for password with mask char "*": + +```js +program.password('Password: ', '*', function(pass){ + console.log('got "%s"', pass); + process.stdin.destroy(); +}); +``` + +## .confirm(msg, fn) + + Confirm with the given `msg`: + +```js +program.confirm('continue? ', function(ok){ + console.log(' got %j', ok); +}); +``` + +## .choose(list, fn) + + Let the user choose from a `list`: + +```js +var list = ['tobi', 'loki', 'jane', 'manny', 'luna']; + +console.log('Choose the coolest pet:'); +program.choose(list, function(i){ + console.log('you chose %d "%s"', i, list[i]); +}); +``` + +## .outputHelp() + + Output help information without exiting. + +## .help() + + Output help information and exit immediately. + +## Links + + - [API documentation](http://visionmedia.github.com/commander.js/) + - [ascii tables](https://github.com/LearnBoost/cli-table) + - [progress bars](https://github.com/visionmedia/node-progress) + - [more progress bars](https://github.com/substack/node-multimeter) + - [examples](https://github.com/visionmedia/commander.js/tree/master/examples) + +## License + +(The MIT License) + +Copyright (c) 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/node_modules/express/node_modules/commander/index.js b/node_modules/express/node_modules/commander/index.js new file mode 100644 index 0000000..d9634e3 --- /dev/null +++ b/node_modules/express/node_modules/commander/index.js @@ -0,0 +1,1160 @@ +/*! + * commander + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , spawn = require('child_process').spawn + , keypress = require('keypress') + , fs = require('fs') + , exists = fs.existsSync + , path = require('path') + , tty = require('tty') + , dirname = path.dirname + , basename = path.basename; + +/** + * Expose the root command. + */ + +exports = module.exports = new Command; + +/** + * Expose `Command`. + */ + +exports.Command = Command; + +/** + * Expose `Option`. + */ + +exports.Option = Option; + +/** + * Initialize a new `Option` with the given `flags` and `description`. + * + * @param {String} flags + * @param {String} description + * @api public + */ + +function Option(flags, description) { + this.flags = flags; + this.required = ~flags.indexOf('<'); + this.optional = ~flags.indexOf('['); + this.bool = !~flags.indexOf('-no-'); + flags = flags.split(/[ ,|]+/); + if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift(); + this.long = flags.shift(); + this.description = description || ''; +} + +/** + * Return option name. + * + * @return {String} + * @api private + */ + +Option.prototype.name = function(){ + return this.long + .replace('--', '') + .replace('no-', ''); +}; + +/** + * Check if `arg` matches the short or long flag. + * + * @param {String} arg + * @return {Boolean} + * @api private + */ + +Option.prototype.is = function(arg){ + return arg == this.short + || arg == this.long; +}; + +/** + * Initialize a new `Command`. + * + * @param {String} name + * @api public + */ + +function Command(name) { + this.commands = []; + this.options = []; + this._execs = []; + this._args = []; + this._name = name; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Command.prototype.__proto__ = EventEmitter.prototype; + +/** + * Add command `name`. + * + * The `.action()` callback is invoked when the + * command `name` is specified via __ARGV__, + * and the remaining arguments are applied to the + * function for access. + * + * When the `name` is "*" an un-matched command + * will be passed as the first arg, followed by + * the rest of __ARGV__ remaining. + * + * Examples: + * + * program + * .version('0.0.1') + * .option('-C, --chdir ', 'change the working directory') + * .option('-c, --config ', 'set config path. defaults to ./deploy.conf') + * .option('-T, --no-tests', 'ignore test hook') + * + * program + * .command('setup') + * .description('run remote setup commands') + * .action(function(){ + * console.log('setup'); + * }); + * + * program + * .command('exec ') + * .description('run the given remote command') + * .action(function(cmd){ + * console.log('exec "%s"', cmd); + * }); + * + * program + * .command('*') + * .description('deploy the given env') + * .action(function(env){ + * console.log('deploying "%s"', env); + * }); + * + * program.parse(process.argv); + * + * @param {String} name + * @param {String} [desc] + * @return {Command} the new command + * @api public + */ + +Command.prototype.command = function(name, desc){ + var args = name.split(/ +/); + var cmd = new Command(args.shift()); + if (desc) cmd.description(desc); + if (desc) this.executables = true; + if (desc) this._execs[cmd._name] = true; + this.commands.push(cmd); + cmd.parseExpectedArgs(args); + cmd.parent = this; + if (desc) return this; + return cmd; +}; + +/** + * Add an implicit `help [cmd]` subcommand + * which invokes `--help` for the given command. + * + * @api private + */ + +Command.prototype.addImplicitHelpCommand = function() { + this.command('help [cmd]', 'display help for [cmd]'); +}; + +/** + * Parse expected `args`. + * + * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`. + * + * @param {Array} args + * @return {Command} for chaining + * @api public + */ + +Command.prototype.parseExpectedArgs = function(args){ + if (!args.length) return; + var self = this; + args.forEach(function(arg){ + switch (arg[0]) { + case '<': + self._args.push({ required: true, name: arg.slice(1, -1) }); + break; + case '[': + self._args.push({ required: false, name: arg.slice(1, -1) }); + break; + } + }); + return this; +}; + +/** + * Register callback `fn` for the command. + * + * Examples: + * + * program + * .command('help') + * .description('display verbose help') + * .action(function(){ + * // output help here + * }); + * + * @param {Function} fn + * @return {Command} for chaining + * @api public + */ + +Command.prototype.action = function(fn){ + var self = this; + this.parent.on(this._name, function(args, unknown){ + // Parse any so-far unknown options + unknown = unknown || []; + var parsed = self.parseOptions(unknown); + + // Output help if necessary + outputHelpIfNecessary(self, parsed.unknown); + + // If there are still any unknown options, then we simply + // die, unless someone asked for help, in which case we give it + // to them, and then we die. + if (parsed.unknown.length > 0) { + self.unknownOption(parsed.unknown[0]); + } + + // Leftover arguments need to be pushed back. Fixes issue #56 + if (parsed.args.length) args = parsed.args.concat(args); + + self._args.forEach(function(arg, i){ + if (arg.required && null == args[i]) { + self.missingArgument(arg.name); + } + }); + + // Always append ourselves to the end of the arguments, + // to make sure we match the number of arguments the user + // expects + if (self._args.length) { + args[self._args.length] = self; + } else { + args.push(self); + } + + fn.apply(this, args); + }); + return this; +}; + +/** + * Define option with `flags`, `description` and optional + * coercion `fn`. + * + * The `flags` string should contain both the short and long flags, + * separated by comma, a pipe or space. The following are all valid + * all will output this way when `--help` is used. + * + * "-p, --pepper" + * "-p|--pepper" + * "-p --pepper" + * + * Examples: + * + * // simple boolean defaulting to false + * program.option('-p, --pepper', 'add pepper'); + * + * --pepper + * program.pepper + * // => Boolean + * + * // simple boolean defaulting to false + * program.option('-C, --no-cheese', 'remove cheese'); + * + * program.cheese + * // => true + * + * --no-cheese + * program.cheese + * // => true + * + * // required argument + * program.option('-C, --chdir ', 'change the working directory'); + * + * --chdir /tmp + * program.chdir + * // => "/tmp" + * + * // optional argument + * program.option('-c, --cheese [type]', 'add cheese [marble]'); + * + * @param {String} flags + * @param {String} description + * @param {Function|Mixed} fn or default + * @param {Mixed} defaultValue + * @return {Command} for chaining + * @api public + */ + +Command.prototype.option = function(flags, description, fn, defaultValue){ + var self = this + , option = new Option(flags, description) + , oname = option.name() + , name = camelcase(oname); + + // default as 3rd arg + if ('function' != typeof fn) defaultValue = fn, fn = null; + + // preassign default value only for --no-*, [optional], or + if (false == option.bool || option.optional || option.required) { + // when --no-* we make sure default is true + if (false == option.bool) defaultValue = true; + // preassign only if we have a default + if (undefined !== defaultValue) self[name] = defaultValue; + } + + // register the option + this.options.push(option); + + // when it's passed assign the value + // and conditionally invoke the callback + this.on(oname, function(val){ + // coercion + if (null != val && fn) val = fn(val); + + // unassigned or bool + if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) { + // if no value, bool true, and we have a default, then use it! + if (null == val) { + self[name] = option.bool + ? defaultValue || true + : false; + } else { + self[name] = val; + } + } else if (null !== val) { + // reassign + self[name] = val; + } + }); + + return this; +}; + +/** + * Parse `argv`, settings options and invoking commands when defined. + * + * @param {Array} argv + * @return {Command} for chaining + * @api public + */ + +Command.prototype.parse = function(argv){ + // implicit help + if (this.executables) this.addImplicitHelpCommand(); + + // store raw args + this.rawArgs = argv; + + // guess name + this._name = this._name || basename(argv[1]); + + // process argv + var parsed = this.parseOptions(this.normalize(argv.slice(2))); + var args = this.args = parsed.args; + + var result = this.parseArgs(this.args, parsed.unknown); + + // executable sub-commands + var name = result.args[0]; + if (this._execs[name]) return this.executeSubCommand(argv, args, parsed.unknown); + + return result; +}; + +/** + * Execute a sub-command executable. + * + * @param {Array} argv + * @param {Array} args + * @param {Array} unknown + * @api private + */ + +Command.prototype.executeSubCommand = function(argv, args, unknown) { + args = args.concat(unknown); + + if (!args.length) this.help(); + if ('help' == args[0] && 1 == args.length) this.help(); + + // --help + if ('help' == args[0]) { + args[0] = args[1]; + args[1] = '--help'; + } + + // executable + var dir = dirname(argv[1]); + var bin = basename(argv[1]) + '-' + args[0]; + + // check for ./ first + var local = path.join(dir, bin); + + // run it + args = args.slice(1); + var proc = spawn(local, args, { stdio: 'inherit', customFds: [0, 1, 2] }); + proc.on('error', function(err){ + if (err.code == "ENOENT") { + console.error('\n %s(1) does not exist, try --help\n', bin); + } else if (err.code == "EACCES") { + console.error('\n %s(1) not executable. try chmod or run with root\n', bin); + } + }); + + this.runningCommand = proc; +}; + +/** + * Normalize `args`, splitting joined short flags. For example + * the arg "-abc" is equivalent to "-a -b -c". + * This also normalizes equal sign and splits "--abc=def" into "--abc def". + * + * @param {Array} args + * @return {Array} + * @api private + */ + +Command.prototype.normalize = function(args){ + var ret = [] + , arg + , index; + + for (var i = 0, len = args.length; i < len; ++i) { + arg = args[i]; + if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) { + arg.slice(1).split('').forEach(function(c){ + ret.push('-' + c); + }); + } else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) { + ret.push(arg.slice(0, index), arg.slice(index + 1)); + } else { + ret.push(arg); + } + } + + return ret; +}; + +/** + * Parse command `args`. + * + * When listener(s) are available those + * callbacks are invoked, otherwise the "*" + * event is emitted and those actions are invoked. + * + * @param {Array} args + * @return {Command} for chaining + * @api private + */ + +Command.prototype.parseArgs = function(args, unknown){ + var cmds = this.commands + , len = cmds.length + , name; + + if (args.length) { + name = args[0]; + if (this.listeners(name).length) { + this.emit(args.shift(), args, unknown); + } else { + this.emit('*', args); + } + } else { + outputHelpIfNecessary(this, unknown); + + // If there were no args and we have unknown options, + // then they are extraneous and we need to error. + if (unknown.length > 0) { + this.unknownOption(unknown[0]); + } + } + + return this; +}; + +/** + * Return an option matching `arg` if any. + * + * @param {String} arg + * @return {Option} + * @api private + */ + +Command.prototype.optionFor = function(arg){ + for (var i = 0, len = this.options.length; i < len; ++i) { + if (this.options[i].is(arg)) { + return this.options[i]; + } + } +}; + +/** + * Parse options from `argv` returning `argv` + * void of these options. + * + * @param {Array} argv + * @return {Array} + * @api public + */ + +Command.prototype.parseOptions = function(argv){ + var args = [] + , len = argv.length + , literal + , option + , arg; + + var unknownOptions = []; + + // parse options + for (var i = 0; i < len; ++i) { + arg = argv[i]; + + // literal args after -- + if ('--' == arg) { + literal = true; + continue; + } + + if (literal) { + args.push(arg); + continue; + } + + // find matching Option + option = this.optionFor(arg); + + // option is defined + if (option) { + // requires arg + if (option.required) { + arg = argv[++i]; + if (null == arg) return this.optionMissingArgument(option); + if ('-' == arg[0] && '-' != arg) return this.optionMissingArgument(option, arg); + this.emit(option.name(), arg); + // optional arg + } else if (option.optional) { + arg = argv[i+1]; + if (null == arg || ('-' == arg[0] && '-' != arg)) { + arg = null; + } else { + ++i; + } + this.emit(option.name(), arg); + // bool + } else { + this.emit(option.name()); + } + continue; + } + + // looks like an option + if (arg.length > 1 && '-' == arg[0]) { + unknownOptions.push(arg); + + // If the next argument looks like it might be + // an argument for this option, we pass it on. + // If it isn't, then it'll simply be ignored + if (argv[i+1] && '-' != argv[i+1][0]) { + unknownOptions.push(argv[++i]); + } + continue; + } + + // arg + args.push(arg); + } + + return { args: args, unknown: unknownOptions }; +}; + +/** + * Argument `name` is missing. + * + * @param {String} name + * @api private + */ + +Command.prototype.missingArgument = function(name){ + console.error(); + console.error(" error: missing required argument `%s'", name); + console.error(); + process.exit(1); +}; + +/** + * `Option` is missing an argument, but received `flag` or nothing. + * + * @param {String} option + * @param {String} flag + * @api private + */ + +Command.prototype.optionMissingArgument = function(option, flag){ + console.error(); + if (flag) { + console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag); + } else { + console.error(" error: option `%s' argument missing", option.flags); + } + console.error(); + process.exit(1); +}; + +/** + * Unknown option `flag`. + * + * @param {String} flag + * @api private + */ + +Command.prototype.unknownOption = function(flag){ + console.error(); + console.error(" error: unknown option `%s'", flag); + console.error(); + process.exit(1); +}; + + +/** + * Set the program version to `str`. + * + * This method auto-registers the "-V, --version" flag + * which will print the version number when passed. + * + * @param {String} str + * @param {String} flags + * @return {Command} for chaining + * @api public + */ + +Command.prototype.version = function(str, flags){ + if (0 == arguments.length) return this._version; + this._version = str; + flags = flags || '-V, --version'; + this.option(flags, 'output the version number'); + this.on('version', function(){ + console.log(str); + process.exit(0); + }); + return this; +}; + +/** + * Set the description `str`. + * + * @param {String} str + * @return {String|Command} + * @api public + */ + +Command.prototype.description = function(str){ + if (0 == arguments.length) return this._description; + this._description = str; + return this; +}; + +/** + * Set / get the command usage `str`. + * + * @param {String} str + * @return {String|Command} + * @api public + */ + +Command.prototype.usage = function(str){ + var args = this._args.map(function(arg){ + return arg.required + ? '<' + arg.name + '>' + : '[' + arg.name + ']'; + }); + + var usage = '[options' + + (this.commands.length ? '] [command' : '') + + ']' + + (this._args.length ? ' ' + args : ''); + + if (0 == arguments.length) return this._usage || usage; + this._usage = str; + + return this; +}; + +/** + * Return the largest option length. + * + * @return {Number} + * @api private + */ + +Command.prototype.largestOptionLength = function(){ + return this.options.reduce(function(max, option){ + return Math.max(max, option.flags.length); + }, 0); +}; + +/** + * Return help for options. + * + * @return {String} + * @api private + */ + +Command.prototype.optionHelp = function(){ + var width = this.largestOptionLength(); + + // Prepend the help information + return [pad('-h, --help', width) + ' ' + 'output usage information'] + .concat(this.options.map(function(option){ + return pad(option.flags, width) + + ' ' + option.description; + })) + .join('\n'); +}; + +/** + * Return command help documentation. + * + * @return {String} + * @api private + */ + +Command.prototype.commandHelp = function(){ + if (!this.commands.length) return ''; + return [ + '' + , ' Commands:' + , '' + , this.commands.map(function(cmd){ + var args = cmd._args.map(function(arg){ + return arg.required + ? '<' + arg.name + '>' + : '[' + arg.name + ']'; + }).join(' '); + + return pad(cmd._name + + (cmd.options.length + ? ' [options]' + : '') + ' ' + args, 22) + + (cmd.description() + ? ' ' + cmd.description() + : ''); + }).join('\n').replace(/^/gm, ' ') + , '' + ].join('\n'); +}; + +/** + * Return program help documentation. + * + * @return {String} + * @api private + */ + +Command.prototype.helpInformation = function(){ + return [ + '' + , ' Usage: ' + this._name + ' ' + this.usage() + , '' + this.commandHelp() + , ' Options:' + , '' + , '' + this.optionHelp().replace(/^/gm, ' ') + , '' + , '' + ].join('\n'); +}; + +/** + * Prompt for a `Number`. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptForNumber = function(str, fn){ + var self = this; + this.promptSingleLine(str, function parseNumber(val){ + val = Number(val); + if (isNaN(val)) return self.promptSingleLine(str + '(must be a number) ', parseNumber); + fn(val); + }); +}; + +/** + * Prompt for a `Date`. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptForDate = function(str, fn){ + var self = this; + this.promptSingleLine(str, function parseDate(val){ + val = new Date(val); + if (isNaN(val.getTime())) return self.promptSingleLine(str + '(must be a date) ', parseDate); + fn(val); + }); +}; + + +/** + * Prompt for a `Regular Expression`. + * + * @param {String} str + * @param {Object} pattern regular expression object to test + * @param {Function} fn + * @api private + */ + +Command.prototype.promptForRegexp = function(str, pattern, fn){ + var self = this; + this.promptSingleLine(str, function parseRegexp(val){ + if(!pattern.test(val)) return self.promptSingleLine(str + '(regular expression mismatch) ', parseRegexp); + fn(val); + }); +}; + + +/** + * Single-line prompt. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptSingleLine = function(str, fn){ + // determine if the 2nd argument is a regular expression + if (arguments[1].global !== undefined && arguments[1].multiline !== undefined) { + return this.promptForRegexp(str, arguments[1], arguments[2]); + } else if ('function' == typeof arguments[2]) { + return this['promptFor' + (fn.name || fn)](str, arguments[2]); + } + + process.stdout.write(str); + process.stdin.setEncoding('utf8'); + process.stdin.once('data', function(val){ + fn(val.trim()); + }).resume(); +}; + +/** + * Multi-line prompt. + * + * @param {String} str + * @param {Function} fn + * @api private + */ + +Command.prototype.promptMultiLine = function(str, fn){ + var buf = []; + console.log(str); + process.stdin.setEncoding('utf8'); + process.stdin.on('data', function(val){ + if ('\n' == val || '\r\n' == val) { + process.stdin.removeAllListeners('data'); + fn(buf.join('\n')); + } else { + buf.push(val.trimRight()); + } + }).resume(); +}; + +/** + * Prompt `str` and callback `fn(val)` + * + * Commander supports single-line and multi-line prompts. + * To issue a single-line prompt simply add white-space + * to the end of `str`, something like "name: ", whereas + * for a multi-line prompt omit this "description:". + * + * + * Examples: + * + * program.prompt('Username: ', function(name){ + * console.log('hi %s', name); + * }); + * + * program.prompt('Description:', function(desc){ + * console.log('description was "%s"', desc.trim()); + * }); + * + * @param {String|Object} str + * @param {Function} fn + * @api public + */ + +Command.prototype.prompt = function(str, fn){ + var self = this; + if ('string' == typeof str) { + if (/ $/.test(str)) return this.promptSingleLine.apply(this, arguments); + this.promptMultiLine(str, fn); + } else { + var keys = Object.keys(str) + , obj = {}; + + function next() { + var key = keys.shift() + , label = str[key]; + + if (!key) return fn(obj); + self.prompt(label, function(val){ + obj[key] = val; + next(); + }); + } + + next(); + } +}; + +/** + * Prompt for password with `str`, `mask` char and callback `fn(val)`. + * + * The mask string defaults to '', aka no output is + * written while typing, you may want to use "*" etc. + * + * Examples: + * + * program.password('Password: ', function(pass){ + * console.log('got "%s"', pass); + * process.stdin.destroy(); + * }); + * + * program.password('Password: ', '*', function(pass){ + * console.log('got "%s"', pass); + * process.stdin.destroy(); + * }); + * + * @param {String} str + * @param {String} mask + * @param {Function} fn + * @api public + */ + +Command.prototype.password = function(str, mask, fn){ + var self = this + , buf = ''; + + // default mask + if ('function' == typeof mask) { + fn = mask; + mask = ''; + } + + keypress(process.stdin); + + function setRawMode(mode) { + if (process.stdin.setRawMode) { + process.stdin.setRawMode(mode); + } else { + tty.setRawMode(mode); + } + }; + setRawMode(true); + process.stdout.write(str); + + // keypress + process.stdin.on('keypress', function(c, key){ + if (key && 'enter' == key.name) { + console.log(); + process.stdin.pause(); + process.stdin.removeAllListeners('keypress'); + setRawMode(false); + if (!buf.trim().length) return self.password(str, mask, fn); + fn(buf); + return; + } + + if (key && key.ctrl && 'c' == key.name) { + console.log('%s', buf); + process.exit(); + } + + process.stdout.write(mask); + buf += c; + }).resume(); +}; + +/** + * Confirmation prompt with `str` and callback `fn(bool)` + * + * Examples: + * + * program.confirm('continue? ', function(ok){ + * console.log(' got %j', ok); + * process.stdin.destroy(); + * }); + * + * @param {String} str + * @param {Function} fn + * @api public + */ + + +Command.prototype.confirm = function(str, fn, verbose){ + var self = this; + this.prompt(str, function(ok){ + if (!ok.trim()) { + if (!verbose) str += '(yes or no) '; + return self.confirm(str, fn, true); + } + fn(parseBool(ok)); + }); +}; + +/** + * Choice prompt with `list` of items and callback `fn(index, item)` + * + * Examples: + * + * var list = ['tobi', 'loki', 'jane', 'manny', 'luna']; + * + * console.log('Choose the coolest pet:'); + * program.choose(list, function(i){ + * console.log('you chose %d "%s"', i, list[i]); + * process.stdin.destroy(); + * }); + * + * @param {Array} list + * @param {Number|Function} index or fn + * @param {Function} fn + * @api public + */ + +Command.prototype.choose = function(list, index, fn){ + var self = this + , hasDefault = 'number' == typeof index; + + if (!hasDefault) { + fn = index; + index = null; + } + + list.forEach(function(item, i){ + if (hasDefault && i == index) { + console.log('* %d) %s', i + 1, item); + } else { + console.log(' %d) %s', i + 1, item); + } + }); + + function again() { + self.prompt(' : ', function(val){ + val = parseInt(val, 10) - 1; + if (hasDefault && isNaN(val)) val = index; + + if (null == list[val]) { + again(); + } else { + fn(val, list[val]); + } + }); + } + + again(); +}; + + +/** + * Output help information for this command + * + * @api public + */ + +Command.prototype.outputHelp = function(){ + process.stdout.write(this.helpInformation()); + this.emit('--help'); +}; + +/** + * Output help information and exit. + * + * @api public + */ + +Command.prototype.help = function(){ + this.outputHelp(); + process.exit(); +}; + +/** + * Camel-case the given `flag` + * + * @param {String} flag + * @return {String} + * @api private + */ + +function camelcase(flag) { + return flag.split('-').reduce(function(str, word){ + return str + word[0].toUpperCase() + word.slice(1); + }); +} + +/** + * Parse a boolean `str`. + * + * @param {String} str + * @return {Boolean} + * @api private + */ + +function parseBool(str) { + return /^y|yes|ok|true$/i.test(str); +} + +/** + * Pad `str` to `width`. + * + * @param {String} str + * @param {Number} width + * @return {String} + * @api private + */ + +function pad(str, width) { + var len = Math.max(0, width - str.length); + return str + Array(len + 1).join(' '); +} + +/** + * Output help information if necessary + * + * @param {Command} command to output help for + * @param {Array} array of options to search for -h or --help + * @api private + */ + +function outputHelpIfNecessary(cmd, options) { + options = options || []; + for (var i = 0; i < options.length; i++) { + if (options[i] == '--help' || options[i] == '-h') { + cmd.outputHelp(); + process.exit(0); + } + } +} diff --git a/node_modules/express/node_modules/commander/node_modules/keypress/README.md b/node_modules/express/node_modules/commander/node_modules/keypress/README.md new file mode 100644 index 0000000..a768e8f --- /dev/null +++ b/node_modules/express/node_modules/commander/node_modules/keypress/README.md @@ -0,0 +1,101 @@ +keypress +======== +### Make any Node ReadableStream emit "keypress" events + + +Previous to Node `v0.8.x`, there was an undocumented `"keypress"` event that +`process.stdin` would emit when it was a TTY. Some people discovered this hidden +gem, and started using it in their own code. + +Now in Node `v0.8.x`, this `"keypress"` event does not get emitted by default, +but rather only when it is being used in conjuction with the `readline` (or by +extension, the `repl`) module. + +This module is the exact logic from the node `v0.8.x` releases ripped out into its +own module. + +__Bonus:__ Now with mouse support! + +Installation +------------ + +Install with `npm`: + +``` bash +$ npm install keypress +``` + +Or add it to the `"dependencies"` section of your _package.json_ file. + + +Example +------- + +#### Listening for "keypress" events + +``` js +var keypress = require('keypress'); + +// make `process.stdin` begin emitting "keypress" events +keypress(process.stdin); + +// listen for the "keypress" event +process.stdin.on('keypress', function (ch, key) { + console.log('got "keypress"', key); + if (key && key.ctrl && key.name == 'c') { + process.stdin.pause(); + } +}); + +process.stdin.setRawMode(true); +process.stdin.resume(); +``` + +#### Listening for "mousepress" events + +``` js +var keypress = require('keypress'); + +// make `process.stdin` begin emitting "mousepress" (and "keypress") events +keypress(process.stdin); + +// you must enable the mouse events before they will begin firing +keypress.enableMouse(process.stdout); + +process.stdin.on('mousepress', function (info) { + console.log('got "mousepress" event at %d x %d', info.x, info.y); +}); + +process.on('exit', function () { + // disable mouse on exit, so that the state + // is back to normal for the terminal + keypress.disableMouse(process.stdout); +}); +``` + + +License +------- + +(The MIT License) + +Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/express/node_modules/commander/node_modules/keypress/index.js b/node_modules/express/node_modules/commander/node_modules/keypress/index.js new file mode 100644 index 0000000..c2ba488 --- /dev/null +++ b/node_modules/express/node_modules/commander/node_modules/keypress/index.js @@ -0,0 +1,346 @@ + +/** + * This module offers the internal "keypress" functionality from node-core's + * `readline` module, for your own programs and modules to use. + * + * Usage: + * + * require('keypress')(process.stdin); + * + * process.stdin.on('keypress', function (ch, key) { + * console.log(ch, key); + * if (key.ctrl && key.name == 'c') { + * process.stdin.pause(); + * } + * }); + * proces.stdin.resume(); + */ +var exports = module.exports = keypress; + +exports.enableMouse = function (stream) { + stream.write('\x1b' +'[?1000h') +} + +exports.disableMouse = function (stream) { + stream.write('\x1b' +'[?1000l') +} + + +/** + * accepts a readable Stream instance and makes it emit "keypress" events + */ + +function keypress(stream) { + if (isEmittingKeypress(stream)) return; + stream._emitKeypress = true; + + function onData(b) { + if (stream.listeners('keypress').length > 0) { + emitKey(stream, b); + } else { + // Nobody's watching anyway + stream.removeListener('data', onData); + stream.on('newListener', onNewListener); + } + } + + function onNewListener(event) { + if (event == 'keypress') { + stream.on('data', onData); + stream.removeListener('newListener', onNewListener); + } + } + + if (stream.listeners('keypress').length > 0) { + stream.on('data', onData); + } else { + stream.on('newListener', onNewListener); + } +} + +/** + * Returns `true` if the stream is already emitting "keypress" events. + * `false` otherwise. + */ + +function isEmittingKeypress(stream) { + var rtn = stream._emitKeypress; + if (!rtn) { + // hack: check for the v0.6.x "data" event + stream.listeners('data').forEach(function (l) { + if (l.name == 'onData' && /emitKey/.test(l.toString())) { + rtn = true; + stream._emitKeypress = true; + } + }); + } + if (!rtn) { + // hack: check for the v0.6.x "newListener" event + stream.listeners('newListener').forEach(function (l) { + if (l.name == 'onNewListener' && /keypress/.test(l.toString())) { + rtn = true; + stream._emitKeypress = true; + } + }); + } + return rtn; +} + + +/* + Some patterns seen in terminal key escape codes, derived from combos seen + at http://www.midnight-commander.org/browser/lib/tty/key.c + + ESC letter + ESC [ letter + ESC [ modifier letter + ESC [ 1 ; modifier letter + ESC [ num char + ESC [ num ; modifier char + ESC O letter + ESC O modifier letter + ESC O 1 ; modifier letter + ESC N letter + ESC [ [ num ; modifier char + ESC [ [ 1 ; modifier letter + ESC ESC [ num char + ESC ESC O letter + + - char is usually ~ but $ and ^ also happen with rxvt + - modifier is 1 + + (shift * 1) + + (left_alt * 2) + + (ctrl * 4) + + (right_alt * 8) + - two leading ESCs apparently mean the same as one leading ESC +*/ + +// Regexes used for ansi escape code splitting +var metaKeyCodeRe = /^(?:\x1b)([a-zA-Z0-9])$/; +var functionKeyCodeRe = + /^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/; + +function emitKey(stream, s) { + var ch, + key = { + name: undefined, + ctrl: false, + meta: false, + shift: false + }, + parts; + + if (Buffer.isBuffer(s)) { + if (s[0] > 127 && s[1] === undefined) { + s[0] -= 128; + s = '\x1b' + s.toString(stream.encoding || 'utf-8'); + } else { + s = s.toString(stream.encoding || 'utf-8'); + } + } + + key.sequence = s; + + if (s === '\r' || s === '\n') { + // enter + key.name = 'enter'; + + } else if (s === '\t') { + // tab + key.name = 'tab'; + + } else if (s === '\b' || s === '\x7f' || + s === '\x1b\x7f' || s === '\x1b\b') { + // backspace or ctrl+h + key.name = 'backspace'; + key.meta = (s.charAt(0) === '\x1b'); + + } else if (s === '\x1b' || s === '\x1b\x1b') { + // escape key + key.name = 'escape'; + key.meta = (s.length === 2); + + } else if (s === ' ' || s === '\x1b ') { + key.name = 'space'; + key.meta = (s.length === 2); + + } else if (s <= '\x1a') { + // ctrl+letter + key.name = String.fromCharCode(s.charCodeAt(0) + 'a'.charCodeAt(0) - 1); + key.ctrl = true; + + } else if (s.length === 1 && s >= 'a' && s <= 'z') { + // lowercase letter + key.name = s; + + } else if (s.length === 1 && s >= 'A' && s <= 'Z') { + // shift+letter + key.name = s.toLowerCase(); + key.shift = true; + + } else if (parts = metaKeyCodeRe.exec(s)) { + // meta+character key + key.name = parts[1].toLowerCase(); + key.meta = true; + key.shift = /^[A-Z]$/.test(parts[1]); + + } else if (parts = functionKeyCodeRe.exec(s)) { + // ansi escape sequence + + // reassemble the key code leaving out leading \x1b's, + // the modifier key bitflag and any meaningless "1;" sequence + var code = (parts[1] || '') + (parts[2] || '') + + (parts[4] || '') + (parts[6] || ''), + modifier = (parts[3] || parts[5] || 1) - 1; + + // Parse the key modifier + key.ctrl = !!(modifier & 4); + key.meta = !!(modifier & 10); + key.shift = !!(modifier & 1); + key.code = code; + + // Parse the key itself + switch (code) { + /* xterm/gnome ESC O letter */ + case 'OP': key.name = 'f1'; break; + case 'OQ': key.name = 'f2'; break; + case 'OR': key.name = 'f3'; break; + case 'OS': key.name = 'f4'; break; + + /* xterm/rxvt ESC [ number ~ */ + case '[11~': key.name = 'f1'; break; + case '[12~': key.name = 'f2'; break; + case '[13~': key.name = 'f3'; break; + case '[14~': key.name = 'f4'; break; + + /* from Cygwin and used in libuv */ + case '[[A': key.name = 'f1'; break; + case '[[B': key.name = 'f2'; break; + case '[[C': key.name = 'f3'; break; + case '[[D': key.name = 'f4'; break; + case '[[E': key.name = 'f5'; break; + + /* common */ + case '[15~': key.name = 'f5'; break; + case '[17~': key.name = 'f6'; break; + case '[18~': key.name = 'f7'; break; + case '[19~': key.name = 'f8'; break; + case '[20~': key.name = 'f9'; break; + case '[21~': key.name = 'f10'; break; + case '[23~': key.name = 'f11'; break; + case '[24~': key.name = 'f12'; break; + + /* xterm ESC [ letter */ + case '[A': key.name = 'up'; break; + case '[B': key.name = 'down'; break; + case '[C': key.name = 'right'; break; + case '[D': key.name = 'left'; break; + case '[E': key.name = 'clear'; break; + case '[F': key.name = 'end'; break; + case '[H': key.name = 'home'; break; + + /* xterm/gnome ESC O letter */ + case 'OA': key.name = 'up'; break; + case 'OB': key.name = 'down'; break; + case 'OC': key.name = 'right'; break; + case 'OD': key.name = 'left'; break; + case 'OE': key.name = 'clear'; break; + case 'OF': key.name = 'end'; break; + case 'OH': key.name = 'home'; break; + + /* xterm/rxvt ESC [ number ~ */ + case '[1~': key.name = 'home'; break; + case '[2~': key.name = 'insert'; break; + case '[3~': key.name = 'delete'; break; + case '[4~': key.name = 'end'; break; + case '[5~': key.name = 'pageup'; break; + case '[6~': key.name = 'pagedown'; break; + + /* putty */ + case '[[5~': key.name = 'pageup'; break; + case '[[6~': key.name = 'pagedown'; break; + + /* rxvt */ + case '[7~': key.name = 'home'; break; + case '[8~': key.name = 'end'; break; + + /* rxvt keys with modifiers */ + case '[a': key.name = 'up'; key.shift = true; break; + case '[b': key.name = 'down'; key.shift = true; break; + case '[c': key.name = 'right'; key.shift = true; break; + case '[d': key.name = 'left'; key.shift = true; break; + case '[e': key.name = 'clear'; key.shift = true; break; + + case '[2$': key.name = 'insert'; key.shift = true; break; + case '[3$': key.name = 'delete'; key.shift = true; break; + case '[5$': key.name = 'pageup'; key.shift = true; break; + case '[6$': key.name = 'pagedown'; key.shift = true; break; + case '[7$': key.name = 'home'; key.shift = true; break; + case '[8$': key.name = 'end'; key.shift = true; break; + + case 'Oa': key.name = 'up'; key.ctrl = true; break; + case 'Ob': key.name = 'down'; key.ctrl = true; break; + case 'Oc': key.name = 'right'; key.ctrl = true; break; + case 'Od': key.name = 'left'; key.ctrl = true; break; + case 'Oe': key.name = 'clear'; key.ctrl = true; break; + + case '[2^': key.name = 'insert'; key.ctrl = true; break; + case '[3^': key.name = 'delete'; key.ctrl = true; break; + case '[5^': key.name = 'pageup'; key.ctrl = true; break; + case '[6^': key.name = 'pagedown'; key.ctrl = true; break; + case '[7^': key.name = 'home'; key.ctrl = true; break; + case '[8^': key.name = 'end'; key.ctrl = true; break; + + /* misc. */ + case '[Z': key.name = 'tab'; key.shift = true; break; + default: key.name = 'undefined'; break; + + } + } else if (s.length > 1 && s[0] !== '\x1b') { + // Got a longer-than-one string of characters. + // Probably a paste, since it wasn't a control sequence. + Array.prototype.forEach.call(s, function(c) { + emitKey(stream, c); + }); + return; + } + + if (key.code == '[M') { + key.name = 'mouse'; + var s = key.sequence; + var b = s.charCodeAt(3); + key.x = s.charCodeAt(4) - 040; + key.y = s.charCodeAt(5) - 040; + + key.scroll = 0; + + key.ctrl = !!(1<<4 & b); + key.meta = !!(1<<3 & b); + key.shift = !!(1<<2 & b); + + key.release = (3 & b) === 3; + + if (1<<6 & b) { //scroll + key.scroll = 1 & b ? 1 : -1; + } + + if (!key.release && !key.scroll) { + key.button = b & 3; + } + } + + // Don't emit a key if no name was found + if (key.name === undefined) { + key = undefined; + } + + if (s.length === 1) { + ch = s; + } + + if (key && key.name == 'mouse') { + stream.emit('mousepress', key) + } else if (key || ch) { + stream.emit('keypress', ch, key); + } +} diff --git a/node_modules/express/node_modules/commander/node_modules/keypress/package.json b/node_modules/express/node_modules/commander/node_modules/keypress/package.json new file mode 100644 index 0000000..19c0214 --- /dev/null +++ b/node_modules/express/node_modules/commander/node_modules/keypress/package.json @@ -0,0 +1,35 @@ +{ + "name": "keypress", + "version": "0.1.0", + "description": "Make any Node ReadableStream emit \"keypress\" events", + "author": { + "name": "Nathan Rajlich", + "email": "nathan@tootallnate.net", + "url": "http://tootallnate.net" + }, + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git://github.com/TooTallNate/keypress.git" + }, + "keywords": [ + "keypress", + "readline", + "core" + ], + "license": "MIT", + "readme": "keypress\n========\n### Make any Node ReadableStream emit \"keypress\" events\n\n\nPrevious to Node `v0.8.x`, there was an undocumented `\"keypress\"` event that\n`process.stdin` would emit when it was a TTY. Some people discovered this hidden\ngem, and started using it in their own code.\n\nNow in Node `v0.8.x`, this `\"keypress\"` event does not get emitted by default,\nbut rather only when it is being used in conjuction with the `readline` (or by\nextension, the `repl`) module.\n\nThis module is the exact logic from the node `v0.8.x` releases ripped out into its\nown module.\n\n__Bonus:__ Now with mouse support!\n\nInstallation\n------------\n\nInstall with `npm`:\n\n``` bash\n$ npm install keypress\n```\n\nOr add it to the `\"dependencies\"` section of your _package.json_ file.\n\n\nExample\n-------\n\n#### Listening for \"keypress\" events\n\n``` js\nvar keypress = require('keypress');\n\n// make `process.stdin` begin emitting \"keypress\" events\nkeypress(process.stdin);\n\n// listen for the \"keypress\" event\nprocess.stdin.on('keypress', function (ch, key) {\n console.log('got \"keypress\"', key);\n if (key && key.ctrl && key.name == 'c') {\n process.stdin.pause();\n }\n});\n\nprocess.stdin.setRawMode(true);\nprocess.stdin.resume();\n```\n\n#### Listening for \"mousepress\" events\n\n``` js\nvar keypress = require('keypress');\n\n// make `process.stdin` begin emitting \"mousepress\" (and \"keypress\") events\nkeypress(process.stdin);\n\n// you must enable the mouse events before they will begin firing\nkeypress.enableMouse(process.stdout);\n\nprocess.stdin.on('mousepress', function (info) {\n console.log('got \"mousepress\" event at %d x %d', info.x, info.y);\n});\n\nprocess.on('exit', function () {\n // disable mouse on exit, so that the state\n // is back to normal for the terminal\n keypress.disableMouse(process.stdout);\n});\n```\n\n\nLicense\n-------\n\n(The MIT License)\n\nCopyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/TooTallNate/keypress/issues" + }, + "_id": "keypress@0.1.0", + "dist": { + "shasum": "4a3188d4291b66b4f65edb99f806aa9ae293592a" + }, + "_from": "keypress@0.1.x", + "_resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz" +} diff --git a/node_modules/express/node_modules/commander/node_modules/keypress/test.js b/node_modules/express/node_modules/commander/node_modules/keypress/test.js new file mode 100644 index 0000000..c3f61d7 --- /dev/null +++ b/node_modules/express/node_modules/commander/node_modules/keypress/test.js @@ -0,0 +1,28 @@ + +var keypress = require('./') +keypress(process.stdin) + +if (process.stdin.setRawMode) + process.stdin.setRawMode(true) +else + require('tty').setRawMode(true) + +process.stdin.on('keypress', function (c, key) { + console.log(0, c, key) + if (key && key.ctrl && key.name == 'c') { + process.stdin.pause() + } +}) +process.stdin.on('mousepress', function (mouse) { + console.log(mouse) +}) + +keypress.enableMouse(process.stdout) +process.on('exit', function () { + //disable mouse on exit, so that the state is back to normal + //for the terminal. + keypress.disableMouse(process.stdout) +}) + +process.stdin.resume() + diff --git a/node_modules/express/node_modules/commander/package.json b/node_modules/express/node_modules/commander/package.json new file mode 100644 index 0000000..19b66e6 --- /dev/null +++ b/node_modules/express/node_modules/commander/package.json @@ -0,0 +1,44 @@ +{ + "name": "commander", + "version": "1.3.2", + "description": "the complete solution for node.js command-line programs", + "keywords": [ + "command", + "option", + "parser", + "prompt", + "stdin" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "repository": { + "type": "git", + "url": "https://github.com/visionmedia/commander.js.git" + }, + "dependencies": { + "keypress": "0.1.x" + }, + "devDependencies": { + "should": ">= 0.0.1" + }, + "scripts": { + "test": "make test" + }, + "main": "index", + "engines": { + "node": ">= 0.6.x" + }, + "readme": "# Commander.js\n\n The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander).\n\n [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js)\n\n## Installation\n\n $ npm install commander\n\n## Option parsing\n\n Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('commander');\n\nprogram\n .version('0.0.1')\n .option('-p, --peppers', 'Add peppers')\n .option('-P, --pineapple', 'Add pineapple')\n .option('-b, --bbq', 'Add bbq sauce')\n .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')\n .parse(process.argv);\n\nconsole.log('you ordered a pizza with:');\nif (program.peppers) console.log(' - peppers');\nif (program.pineapple) console.log(' - pineapple');\nif (program.bbq) console.log(' - bbq');\nconsole.log(' - %s cheese', program.cheese);\n```\n\n Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as \"--template-engine\" are camel-cased, becoming `program.templateEngine` etc.\n\n## Automated --help\n\n The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:\n\n``` \n $ ./examples/pizza --help\n\n Usage: pizza [options]\n\n Options:\n\n -V, --version output the version number\n -p, --peppers Add peppers\n -P, --pineapple Add pineapple\n -b, --bbq Add bbq sauce\n -c, --cheese Add the specified type of cheese [marble]\n -h, --help output usage information\n\n```\n\n## Coercion\n\n```js\nfunction range(val) {\n return val.split('..').map(Number);\n}\n\nfunction list(val) {\n return val.split(',');\n}\n\nprogram\n .version('0.0.1')\n .usage('[options] ')\n .option('-i, --integer ', 'An integer argument', parseInt)\n .option('-f, --float ', 'A float argument', parseFloat)\n .option('-r, --range ..', 'A range', range)\n .option('-l, --list ', 'A list', list)\n .option('-o, --optional [value]', 'An optional value')\n .parse(process.argv);\n\nconsole.log(' int: %j', program.integer);\nconsole.log(' float: %j', program.float);\nconsole.log(' optional: %j', program.optional);\nprogram.range = program.range || [];\nconsole.log(' range: %j..%j', program.range[0], program.range[1]);\nconsole.log(' list: %j', program.list);\nconsole.log(' args: %j', program.args);\n```\n\n## Custom help\n\n You can display arbitrary `-h, --help` information\n by listening for \"--help\". Commander will automatically\n exit once you are done so that the remainder of your program\n does not execute causing undesired behaviours, for example\n in the following executable \"stuff\" will not output when\n `--help` is used.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('../');\n\nfunction list(val) {\n return val.split(',').map(Number);\n}\n\nprogram\n .version('0.0.1')\n .option('-f, --foo', 'enable some foo')\n .option('-b, --bar', 'enable some bar')\n .option('-B, --baz', 'enable some baz');\n\n// must be before .parse() since\n// node's emit() is immediate\n\nprogram.on('--help', function(){\n console.log(' Examples:');\n console.log('');\n console.log(' $ custom-help --help');\n console.log(' $ custom-help -h');\n console.log('');\n});\n\nprogram.parse(process.argv);\n\nconsole.log('stuff');\n```\n\nyielding the following help output:\n\n```\n\nUsage: custom-help [options]\n\nOptions:\n\n -h, --help output usage information\n -V, --version output the version number\n -f, --foo enable some foo\n -b, --bar enable some bar\n -B, --baz enable some baz\n\nExamples:\n\n $ custom-help --help\n $ custom-help -h\n\n```\n\n## .prompt(msg, fn)\n\n Single-line prompt:\n\n```js\nprogram.prompt('name: ', function(name){\n console.log('hi %s', name);\n});\n```\n\n Multi-line prompt:\n\n```js\nprogram.prompt('description:', function(name){\n console.log('hi %s', name);\n});\n```\n\n Coercion:\n\n```js\nprogram.prompt('Age: ', Number, function(age){\n console.log('age: %j', age);\n});\n```\n\n```js\nprogram.prompt('Birthdate: ', Date, function(date){\n console.log('date: %s', date);\n});\n```\n\n```js\nprogram.prompt('Email: ', /^.+@.+\\..+$/, function(email){\n console.log('email: %j', email);\n});\n```\n\n## .password(msg[, mask], fn)\n\nPrompt for password without echoing:\n\n```js\nprogram.password('Password: ', function(pass){\n console.log('got \"%s\"', pass);\n process.stdin.destroy();\n});\n```\n\nPrompt for password with mask char \"*\":\n\n```js\nprogram.password('Password: ', '*', function(pass){\n console.log('got \"%s\"', pass);\n process.stdin.destroy();\n});\n```\n\n## .confirm(msg, fn)\n\n Confirm with the given `msg`:\n\n```js\nprogram.confirm('continue? ', function(ok){\n console.log(' got %j', ok);\n});\n```\n\n## .choose(list, fn)\n\n Let the user choose from a `list`:\n\n```js\nvar list = ['tobi', 'loki', 'jane', 'manny', 'luna'];\n\nconsole.log('Choose the coolest pet:');\nprogram.choose(list, function(i){\n console.log('you chose %d \"%s\"', i, list[i]);\n});\n```\n\n## .outputHelp()\n\n Output help information without exiting.\n\n## .help()\n\n Output help information and exit immediately.\n\n## Links\n\n - [API documentation](http://visionmedia.github.com/commander.js/)\n - [ascii tables](https://github.com/LearnBoost/cli-table)\n - [progress bars](https://github.com/visionmedia/node-progress)\n - [more progress bars](https://github.com/substack/node-multimeter)\n - [examples](https://github.com/visionmedia/commander.js/tree/master/examples)\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/commander.js/issues" + }, + "_id": "commander@1.3.2", + "dist": { + "shasum": "8a8f30ec670a6fdd64af52f1914b907d79ead5b5" + }, + "_from": "commander@1.3.2", + "_resolved": "https://registry.npmjs.org/commander/-/commander-1.3.2.tgz" +} diff --git a/node_modules/express/node_modules/connect/.npmignore b/node_modules/express/node_modules/connect/.npmignore new file mode 100644 index 0000000..9046dde --- /dev/null +++ b/node_modules/express/node_modules/connect/.npmignore @@ -0,0 +1,12 @@ +*.markdown +*.md +.git* +Makefile +benchmarks/ +docs/ +examples/ +install.sh +support/ +test/ +.DS_Store +coverage.html diff --git a/node_modules/express/node_modules/connect/.travis.yml b/node_modules/express/node_modules/connect/.travis.yml new file mode 100644 index 0000000..a12e3f0 --- /dev/null +++ b/node_modules/express/node_modules/connect/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - "0.8" + - "0.10" \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/LICENSE b/node_modules/express/node_modules/connect/LICENSE new file mode 100644 index 0000000..0c5d22d --- /dev/null +++ b/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/node_modules/express/node_modules/connect/Readme.md b/node_modules/express/node_modules/connect/Readme.md new file mode 100644 index 0000000..e38a326 --- /dev/null +++ b/node_modules/express/node_modules/connect/Readme.md @@ -0,0 +1,84 @@ +# Connect [![build status](https://secure.travis-ci.org/senchalabs/connect.png)](http://travis-ci.org/senchalabs/connect) + + Connect is an extensible HTTP server framework for [node](http://nodejs.org), providing high performance "plugins" known as _middleware_. + + Connect is bundled with over _20_ commonly used middleware, including + a logger, session support, cookie parser, and [more](http://senchalabs.github.com/connect). Be sure to view the 2.x [documentation](http://senchalabs.github.com/connect/). + +```js +var connect = require('connect') + , http = require('http'); + +var app = connect() + .use(connect.favicon()) + .use(connect.logger('dev')) + .use(connect.static('public')) + .use(connect.directory('public')) + .use(connect.cookieParser()) + .use(connect.session({ secret: 'my secret here' })) + .use(function(req, res){ + res.end('Hello from Connect!\n'); + }); + +http.createServer(app).listen(3000); +``` + +## Middleware + + - [basicAuth](http://www.senchalabs.org/connect/basicAuth.html) + - [bodyParser](http://www.senchalabs.org/connect/bodyParser.html) + - [compress](http://www.senchalabs.org/connect/compress.html) + - [cookieParser](http://www.senchalabs.org/connect/cookieParser.html) + - [cookieSession](http://www.senchalabs.org/connect/cookieSession.html) + - [csrf](http://www.senchalabs.org/connect/csrf.html) + - [directory](http://www.senchalabs.org/connect/directory.html) + - [errorHandler](http://www.senchalabs.org/connect/errorHandler.html) + - [favicon](http://www.senchalabs.org/connect/favicon.html) + - [json](http://www.senchalabs.org/connect/json.html) + - [limit](http://www.senchalabs.org/connect/limit.html) + - [logger](http://www.senchalabs.org/connect/logger.html) + - [methodOverride](http://www.senchalabs.org/connect/methodOverride.html) + - [multipart](http://www.senchalabs.org/connect/multipart.html) + - [urlencoded](http://www.senchalabs.org/connect/urlencoded.html) + - [query](http://www.senchalabs.org/connect/query.html) + - [responseTime](http://www.senchalabs.org/connect/responseTime.html) + - [session](http://www.senchalabs.org/connect/session.html) + - [static](http://www.senchalabs.org/connect/static.html) + - [staticCache](http://www.senchalabs.org/connect/staticCache.html) + - [subdomains](http://www.senchalabs.org/connect/subdomains.html) + - [vhost](http://www.senchalabs.org/connect/vhost.html) + +## Running Tests + +first: + + $ npm install -d + +then: + + $ make test + +## Contributors + + https://github.com/senchalabs/connect/graphs/contributors + +## Node Compatibility + + Connect `< 1.x` is compatible with node 0.2.x + + + Connect `1.x` is compatible with node 0.4.x + + + Connect `2.x` is compatible with node 0.6.x + + + Connect (_master_) is compatible with node 0.8.x + +## CLA + + [http://sencha.com/cla](http://sencha.com/cla) + +## License + +View the [LICENSE](https://github.com/senchalabs/connect/blob/master/LICENSE) file. The [Silk](http://www.famfamfam.com/lab/icons/silk/) icons used by the `directory` middleware created by/copyright of [FAMFAMFAM](http://www.famfamfam.com/). diff --git a/node_modules/express/node_modules/connect/index.js b/node_modules/express/node_modules/connect/index.js new file mode 100644 index 0000000..23240ee --- /dev/null +++ b/node_modules/express/node_modules/connect/index.js @@ -0,0 +1,4 @@ + +module.exports = process.env.CONNECT_COV + ? require('./lib-cov/connect') + : require('./lib/connect'); \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/lib/cache.js b/node_modules/express/node_modules/connect/lib/cache.js new file mode 100644 index 0000000..052fcdb --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/cache.js @@ -0,0 +1,81 @@ + +/*! + * Connect - Cache + * Copyright(c) 2011 Sencha Inc. + * MIT Licensed + */ + +/** + * Expose `Cache`. + */ + +module.exports = Cache; + +/** + * LRU cache store. + * + * @param {Number} limit + * @api private + */ + +function Cache(limit) { + this.store = {}; + this.keys = []; + this.limit = limit; +} + +/** + * Touch `key`, promoting the object. + * + * @param {String} key + * @param {Number} i + * @api private + */ + +Cache.prototype.touch = function(key, i){ + this.keys.splice(i,1); + this.keys.push(key); +}; + +/** + * Remove `key`. + * + * @param {String} key + * @api private + */ + +Cache.prototype.remove = function(key){ + delete this.store[key]; +}; + +/** + * Get the object stored for `key`. + * + * @param {String} key + * @return {Array} + * @api private + */ + +Cache.prototype.get = function(key){ + return this.store[key]; +}; + +/** + * Add a cache `key`. + * + * @param {String} key + * @return {Array} + * @api private + */ + +Cache.prototype.add = function(key){ + // initialize store + var len = this.keys.push(key); + + // limit reached, invalidate LRU + if (len > this.limit) this.remove(this.keys.shift()); + + var arr = this.store[key] = []; + arr.createdAt = new Date; + return arr; +}; diff --git a/node_modules/express/node_modules/connect/lib/connect.js b/node_modules/express/node_modules/connect/lib/connect.js new file mode 100644 index 0000000..72961dc --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/connect.js @@ -0,0 +1,92 @@ +/*! + * Connect + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , proto = require('./proto') + , utils = require('./utils') + , path = require('path') + , basename = path.basename + , fs = require('fs'); + +// node patches + +require('./patch'); + +// expose createServer() as the module + +exports = module.exports = createServer; + +/** + * Framework version. + */ + +exports.version = '2.7.11'; + +/** + * Expose mime module. + */ + +exports.mime = require('./middleware/static').mime; + +/** + * Expose the prototype. + */ + +exports.proto = proto; + +/** + * Auto-load middleware getters. + */ + +exports.middleware = {}; + +/** + * Expose utilities. + */ + +exports.utils = utils; + +/** + * Create a new connect server. + * + * @return {Function} + * @api public + */ + +function createServer() { + function app(req, res, next){ app.handle(req, res, next); } + utils.merge(app, proto); + utils.merge(app, EventEmitter.prototype); + app.route = '/'; + app.stack = []; + for (var i = 0; i < arguments.length; ++i) { + app.use(arguments[i]); + } + return app; +}; + +/** + * Support old `.createServer()` method. + */ + +createServer.createServer = createServer; + +/** + * Auto-load bundled middleware with getters. + */ + +fs.readdirSync(__dirname + '/middleware').forEach(function(filename){ + if (!/\.js$/.test(filename)) return; + var name = basename(filename, '.js'); + function load(){ return require('./middleware/' + name); } + exports.middleware.__defineGetter__(name, load); + exports.__defineGetter__(name, load); +}); diff --git a/node_modules/express/node_modules/connect/lib/index.js b/node_modules/express/node_modules/connect/lib/index.js new file mode 100644 index 0000000..2618ddc --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/index.js @@ -0,0 +1,50 @@ + +/** + * Connect is a middleware framework for node, + * shipping with over 18 bundled middleware and a rich selection of + * 3rd-party middleware. + * + * var app = connect() + * .use(connect.logger('dev')) + * .use(connect.static('public')) + * .use(function(req, res){ + * res.end('hello world\n'); + * }) + * .listen(3000); + * + * Installation: + * + * $ npm install connect + * + * Middleware: + * + * - [logger](logger.html) request logger with custom format support + * - [csrf](csrf.html) Cross-site request forgery protection + * - [compress](compress.html) Gzip compression middleware + * - [basicAuth](basicAuth.html) basic http authentication + * - [bodyParser](bodyParser.html) extensible request body parser + * - [json](json.html) application/json parser + * - [urlencoded](urlencoded.html) application/x-www-form-urlencoded parser + * - [multipart](multipart.html) multipart/form-data parser + * - [timeout](timeout.html) request timeouts + * - [cookieParser](cookieParser.html) cookie parser + * - [session](session.html) session management support with bundled MemoryStore + * - [cookieSession](cookieSession.html) cookie-based session support + * - [methodOverride](methodOverride.html) faux HTTP method support + * - [responseTime](responseTime.html) calculates response-time and exposes via X-Response-Time + * - [staticCache](staticCache.html) memory cache layer for the static() middleware + * - [static](static.html) streaming static file server supporting `Range` and more + * - [directory](directory.html) directory listing middleware + * - [vhost](vhost.html) virtual host sub-domain mapping middleware + * - [favicon](favicon.html) efficient favicon server (with default icon) + * - [limit](limit.html) limit the bytesize of request bodies + * - [query](query.html) automatic querystring parser, populating `req.query` + * - [errorHandler](errorHandler.html) flexible error handler + * + * Links: + * + * - list of [3rd-party](https://github.com/senchalabs/connect/wiki) middleware + * - GitHub [repository](http://github.com/senchalabs/connect) + * - [test documentation](https://github.com/senchalabs/connect/blob/gh-pages/tests.md) + * + */ \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/lib/middleware/basicAuth.js b/node_modules/express/node_modules/connect/lib/middleware/basicAuth.js new file mode 100644 index 0000000..59527e6 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/basicAuth.js @@ -0,0 +1,102 @@ +/*! + * Connect - basicAuth + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils') + , unauthorized = utils.unauthorized; + +/** + * Basic Auth: + * + * 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.user`. The final alternative is simply passing username / password + * strings. + * + * Simple username and password + * + * connect(connect.basicAuth('username', 'password')); + * + * Callback verification + * + * connect() + * .use(connect.basicAuth(function(user, pass){ + * return 'tj' == user && 'wahoo' == pass; + * })) + * + * Async callback verification, accepting `fn(err, user)`. + * + * connect() + * .use(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.user) return next(); + if (!authorization) return unauthorized(res, realm); + + var parts = authorization.split(' '); + + if (parts.length !== 2) return next(utils.error(400)); + + var scheme = parts[0] + , credentials = new Buffer(parts[1], 'base64').toString() + , index = credentials.indexOf(':'); + + if ('Basic' != scheme || index < 0) return next(utils.error(400)); + + var user = credentials.slice(0, index) + , pass = credentials.slice(index + 1); + + // async + if (callback.length >= 3) { + var pause = utils.pause(req); + callback(user, pass, function(err, user){ + if (err || !user) return unauthorized(res, realm); + req.user = req.remoteUser = user; + next(); + pause.resume(); + }); + // sync + } else { + if (callback(user, pass)) { + req.user = req.remoteUser = user; + next(); + } else { + unauthorized(res, realm); + } + } + } +}; + diff --git a/node_modules/express/node_modules/connect/lib/middleware/bodyParser.js b/node_modules/express/node_modules/connect/lib/middleware/bodyParser.js new file mode 100644 index 0000000..9f692cd --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/bodyParser.js @@ -0,0 +1,61 @@ + +/*! + * Connect - bodyParser + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var multipart = require('./multipart') + , urlencoded = require('./urlencoded') + , json = require('./json'); + +/** + * Body parser: + * + * Parse request bodies, supports _application/json_, + * _application/x-www-form-urlencoded_, and _multipart/form-data_. + * + * This is equivalent to: + * + * app.use(connect.json()); + * app.use(connect.urlencoded()); + * app.use(connect.multipart()); + * + * Examples: + * + * connect() + * .use(connect.bodyParser()) + * .use(function(req, res) { + * res.end('viewing user ' + req.body.user.name); + * }); + * + * $ curl -d 'user[name]=tj' http://local/ + * $ curl -d '{"user":{"name":"tj"}}' -H "Content-Type: application/json" http://local/ + * + * View [json](json.html), [urlencoded](urlencoded.html), and [multipart](multipart.html) for more info. + * + * @param {Object} options + * @return {Function} + * @api public + */ + +exports = module.exports = function bodyParser(options){ + var _urlencoded = urlencoded(options) + , _multipart = multipart(options) + , _json = json(options); + + return function bodyParser(req, res, next) { + _json(req, res, function(err){ + if (err) return next(err); + _urlencoded(req, res, function(err){ + if (err) return next(err); + _multipart(req, res, next); + }); + }); + } +}; \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/lib/middleware/compress.js b/node_modules/express/node_modules/connect/lib/middleware/compress.js new file mode 100644 index 0000000..a300e53 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/compress.js @@ -0,0 +1,192 @@ +/*! + * Connect - compress + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var zlib = require('zlib'); +var utils = require('../utils'); +var Negotiator = require('negotiator'); + +/** + * Supported content-encoding methods. + */ + +exports.methods = { + gzip: zlib.createGzip + , deflate: zlib.createDeflate +}; + +/** + * Default filter function. + */ + +exports.filter = function(req, res){ + return /json|text|javascript|dart|image\/svg\+xml|application\/x-font-ttf|application\/vnd\.ms-opentype|application\/vnd\.ms-fontobject/.test(res.getHeader('Content-Type')); +}; + +/** + * Compress: + * + * Compress response data with gzip/deflate. + * + * Filter: + * + * A `filter` callback function may be passed to + * replace the default logic of: + * + * exports.filter = function(req, res){ + * return /json|text|javascript/.test(res.getHeader('Content-Type')); + * }; + * + * Threshold: + * + * Only compress the response if the byte size is at or above a threshold. + * Always compress while streaming. + * + * - `threshold` - string representation of size or bytes as an integer. + * + * Options: + * + * All remaining options are passed to the gzip/deflate + * creation functions. Consult node's docs for additional details. + * + * - `chunkSize` (default: 16*1024) + * - `windowBits` + * - `level`: 0-9 where 0 is no compression, and 9 is slow but best compression + * - `memLevel`: 1-9 low is slower but uses less memory, high is fast but uses more + * - `strategy`: compression strategy + * + * @param {Object} options + * @return {Function} + * @api public + */ + +module.exports = function compress(options) { + options = options || {}; + var filter = options.filter || exports.filter; + var threshold; + + if (false === options.threshold || 0 === options.threshold) { + threshold = 0 + } else if ('string' === typeof options.threshold) { + threshold = utils.parseBytes(options.threshold) + } else { + threshold = options.threshold || 1024 + } + + return function compress(req, res, next){ + var accept = req.headers['accept-encoding'] + , write = res.write + , end = res.end + , compress = true + , stream; + + // see #724 + req.on('close', function(){ + res.write = res.end = function(){}; + }); + + // flush is noop by default + res.flush = noop; + + // proxy + + res.write = function(chunk, encoding){ + if (!this.headerSent) { + // if content-length is set and is lower + // than the threshold, don't compress + var length = res.getHeader('content-length'); + if (!isNaN(length) && length < threshold) compress = false; + this._implicitHeader(); + } + return stream + ? stream.write(new Buffer(chunk, encoding)) + : write.call(res, chunk, encoding); + }; + + res.end = function(chunk, encoding){ + if (chunk) { + if (!this.headerSent && getSize(chunk) < threshold) compress = false; + this.write(chunk, encoding); + } else if (!this.headerSent) { + // response size === 0 + compress = false; + } + return stream + ? stream.end() + : end.call(res); + }; + + res.on('header', function(){ + // default request filter + if (!filter(req, res)) return; + + // vary + var vary = res.getHeader('Vary'); + if (!vary) { + res.setHeader('Vary', 'Accept-Encoding'); + } else if (!~vary.indexOf('Accept-Encoding')) { + res.setHeader('Vary', vary + ', Accept-Encoding'); + } + + if (!compress) return; + + var encoding = res.getHeader('Content-Encoding') || 'identity'; + + // already encoded + if ('identity' != encoding) return; + + // SHOULD use identity + if (!accept) return; + + // head + if ('HEAD' == req.method) return; + + // compression method + var method = new Negotiator(req).preferredEncoding(['gzip', 'deflate', 'identity']); + // negotiation failed + if (method === 'identity') return; + + // compression stream + stream = exports.methods[method](options); + + // overwrite the flush method + res.flush = function(){ + stream.flush(); + } + + // header fields + res.setHeader('Content-Encoding', method); + res.removeHeader('Content-Length'); + + // compression + stream.on('data', function(chunk){ + write.call(res, chunk); + }); + + stream.on('end', function(){ + end.call(res); + }); + + stream.on('drain', function() { + res.emit('drain'); + }); + }); + + next(); + }; +}; + +function getSize(chunk) { + return Buffer.isBuffer(chunk) + ? chunk.length + : Buffer.byteLength(chunk); +} + +function noop(){} diff --git a/node_modules/express/node_modules/connect/lib/middleware/cookieParser.js b/node_modules/express/node_modules/connect/lib/middleware/cookieParser.js new file mode 100644 index 0000000..1dfa25f --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/cookieParser.js @@ -0,0 +1,62 @@ + +/*! + * Connect - cookieParser + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('./../utils') + , cookie = require('cookie'); + +/** + * Cookie parser: + * + * Parse _Cookie_ header and populate `req.cookies` + * with an object keyed by the cookie names. Optionally + * you may enabled signed cookie support by passing + * a `secret` string, which assigns `req.secret` so + * it may be used by other middleware. + * + * Examples: + * + * connect() + * .use(connect.cookieParser('optional secret string')) + * .use(function(req, res, next){ + * res.end(JSON.stringify(req.cookies)); + * }) + * + * @param {String} secret + * @return {Function} + * @api public + */ + +module.exports = function cookieParser(secret, opt){ + return function cookieParser(req, res, next) { + if (req.cookies) return next(); + var cookies = req.headers.cookie; + + req.secret = secret; + req.cookies = {}; + req.signedCookies = {}; + + if (cookies) { + try { + req.cookies = cookie.parse(cookies, opt); + if (secret) { + req.signedCookies = utils.parseSignedCookies(req.cookies, secret); + req.signedCookies = utils.parseJSONCookies(req.signedCookies); + } + req.cookies = utils.parseJSONCookies(req.cookies); + } catch (err) { + err.status = 400; + return next(err); + } + } + next(); + }; +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/cookieSession.js b/node_modules/express/node_modules/connect/lib/middleware/cookieSession.js new file mode 100644 index 0000000..bcf5aed --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/cookieSession.js @@ -0,0 +1,117 @@ +/*! + * Connect - cookieSession + * Copyright(c) 2011 Sencha Inc. + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('./../utils') + , Cookie = require('./session/cookie') + , debug = require('debug')('connect:cookieSession') + , signature = require('cookie-signature') + , crc32 = require('buffer-crc32') + , url = require('url'); + +/** + * Cookie Session: + * + * Cookie session middleware. + * + * var app = connect(); + * app.use(connect.cookieParser()); + * app.use(connect.cookieSession({ secret: 'tobo!', cookie: { maxAge: 60 * 60 * 1000 }})); + * + * Options: + * + * - `key` cookie name defaulting to `connect.sess` + * - `secret` prevents cookie tampering + * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }` + * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto") + * + * Clearing sessions: + * + * To clear the session simply set its value to `null`, + * `cookieSession()` will then respond with a 1970 Set-Cookie. + * + * req.session = null; + * + * @param {Object} options + * @return {Function} + * @api public + */ + +module.exports = function cookieSession(options){ + // TODO: utilize Session/Cookie to unify API + options = options || {}; + var key = options.key || 'connect.sess' + , trustProxy = options.proxy; + + return function cookieSession(req, res, next) { + + // req.secret is for backwards compatibility + var secret = options.secret || req.secret; + if (!secret) throw new Error('`secret` option required for cookie sessions'); + + // default session + req.session = {}; + var cookie = req.session.cookie = new Cookie(options.cookie); + + // pathname mismatch + var originalPath = url.parse(req.originalUrl).pathname; + if (0 != originalPath.indexOf(cookie.path)) return next(); + + // cookieParser secret + if (!options.secret && req.secret) { + req.session = req.signedCookies[key] || {}; + req.session.cookie = cookie; + } else { + // TODO: refactor + var rawCookie = req.cookies[key]; + if (rawCookie) { + var unsigned = utils.parseSignedCookie(rawCookie, secret); + if (unsigned) { + var originalHash = crc32.signed(unsigned); + req.session = utils.parseJSONCookie(unsigned) || {}; + req.session.cookie = cookie; + } + } + } + + res.on('header', function(){ + // removed + if (!req.session) { + debug('clear session'); + cookie.expires = new Date(0); + res.setHeader('Set-Cookie', cookie.serialize(key, '')); + return; + } + + delete req.session.cookie; + + // check security + var proto = (req.headers['x-forwarded-proto'] || '').toLowerCase() + , tls = req.connection.encrypted || (trustProxy && 'https' == proto.split(/\s*,\s*/)[0]); + + // only send secure cookies via https + if (cookie.secure && !tls) return debug('not secured'); + + // serialize + debug('serializing %j', req.session); + var val = 'j:' + JSON.stringify(req.session); + + // compare hashes, no need to set-cookie if unchanged + if (originalHash == crc32.signed(val)) return debug('unmodified session'); + + // set-cookie + val = 's:' + signature.sign(val, secret); + val = cookie.serialize(key, val); + debug('set-cookie %j', cookie); + res.setHeader('Set-Cookie', val); + }); + + next(); + }; +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/csrf.js b/node_modules/express/node_modules/connect/lib/middleware/csrf.js new file mode 100644 index 0000000..1c3854b --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/csrf.js @@ -0,0 +1,163 @@ +/*! + * Connect - csrf + * Copyright(c) 2011 Sencha Inc. + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils'); +var uid = require('uid2'); +var crypto = require('crypto'); + +/** + * Anti CSRF: + * + * CSRF protection middleware. + * + * This middleware adds a `req.csrfToken()` function to make a token + * 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 session. + * + * 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()`. + * + * Options: + * + * - `value` a function accepting the request, returning the token + * + * @param {Object} options + * @api public + */ + +module.exports = function csrf(options) { + options = options || {}; + var value = options.value || defaultValue; + + return function(req, res, next){ + + // already have one + var secret = req.session._csrfSecret; + if (secret) return createToken(secret); + + // generate secret + uid(24, function(err, secret){ + if (err) return next(err); + req.session._csrfSecret = secret; + createToken(secret); + }); + + // generate the token + function createToken(secret) { + var token; + + // lazy-load token + req.csrfToken = function csrfToken() { + return token || (token = saltedToken(secret)); + }; + + // compatibility with old middleware + Object.defineProperty(req.session, '_csrf', { + configurable: true, + get: function() { + console.warn('req.session._csrf is deprecated, use req.csrfToken() instead'); + return req.csrfToken(); + } + }); + + // ignore these methods + if ('GET' == req.method || 'HEAD' == req.method || 'OPTIONS' == req.method) return next(); + + // determine user-submitted value + var val = value(req); + + // check + if (!checkToken(val, secret)) return next(utils.error(403)); + + 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']) + || (req.headers['x-xsrf-token']); +} + +/** + * Return salted token. + * + * @param {String} secret + * @return {String} + * @api private + */ + +function saltedToken(secret) { + return createToken(generateSalt(10), secret); +} + +/** + * Creates a CSRF token from a given salt and secret. + * + * @param {String} salt (should be 10 characters) + * @param {String} secret + * @return {String} + * @api private + */ + +function createToken(salt, secret) { + return salt + crypto + .createHash('sha1') + .update(salt + secret) + .digest('base64'); +} + +/** + * Checks if a given CSRF token matches the given secret. + * + * @param {String} token + * @param {String} secret + * @return {Boolean} + * @api private + */ + +function checkToken(token, secret) { + if ('string' != typeof token) return false; + return token === createToken(token.slice(0, 10), secret); +} + +/** + * Generates a random salt, using a fast non-blocking PRNG (Math.random()). + * + * @param {Number} length + * @return {String} + * @api private + */ + +function generateSalt(length) { + var i, r = []; + for (i = 0; i < length; ++i) { + r.push(SALTCHARS[Math.floor(Math.random() * SALTCHARS.length)]); + } + return r.join(''); +} + +var SALTCHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; diff --git a/node_modules/express/node_modules/connect/lib/middleware/directory.js b/node_modules/express/node_modules/connect/lib/middleware/directory.js new file mode 100644 index 0000000..1d253dc --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/directory.js @@ -0,0 +1,245 @@ + +/*! + * 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 + , sep = path.sep + , extname = path.extname + , join = path.join; +var Negotiator = require('negotiator'); + +/*! + * Icon cache. + */ + +var cache = {}; + +/** + * Media types and the map for content negotiation. + */ + +var mediaTypes = [ + 'text/html', + 'text/plain', + 'application/json' +]; + +var mediaType = { + 'text/html': 'html', + 'text/plain': 'plain', + 'application/json': 'json' +}; + +/** + * Directory: + * + * 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 + sep); + + return function directory(req, res, next) { + if ('GET' != req.method && 'HEAD' != req.method) return next(); + + var url = parse(req.url) + , dir = decodeURIComponent(url.pathname) + , path = normalize(join(root, dir)) + , originalUrl = parse(req.originalUrl) + , originalDir = decodeURIComponent(originalUrl.pathname) + , showUp = path != root; + + // null byte(s), bad request + if (~path.indexOf('\0')) return next(utils.error(400)); + + // malicious path, forbidden + if (0 != path.indexOf(root)) return next(utils.error(403)); + + // 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 + var type = new Negotiator(req).preferredMediaType(mediaTypes); + + // not acceptable + if (!type) return next(utils.error(406)); + exports[mediaType[type]](req, res, files, next, originalDir, showUp, icons); + }); + }); + }; +}; + +/** + * 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(encodeURIComponent(part)); + return part ? '' + part + '' : ''; + }).join(' / '); +} + +/** + * Map html `files`, returning an html unordered list. + */ + +function html(files, dir, useIcons) { + return '
    ' + files.map(function(file){ + var icon = '' + , classes = [] + , path = dir.split('/').map(function (c) { return encodeURIComponent(c); }); + + if (useIcons && '..' != file) { + icon = icons[extname(file)] || icons.default; + icon = ''; + classes.push('icon'); + } + + path.push(encodeURIComponent(file)); + + 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/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js b/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js new file mode 100644 index 0000000..07ec9e4 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js @@ -0,0 +1,86 @@ +/*! + * Connect - errorHandler + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils') + , fs = require('fs'); + +// environment + +var env = process.env.NODE_ENV || 'development'; + +/** + * Error handler: + * + * Development error handler, providing stack traces + * and error message responses for requests accepting text, html, + * or json. + * + * 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. + * + * @return {Function} + * @api public + */ + +exports = module.exports = function errorHandler(){ + return function errorHandler(err, req, res, next){ + if (err.status) res.statusCode = err.status; + if (res.statusCode < 400) res.statusCode = 500; + if ('test' != env) console.error(err.stack); + 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('{statusCode}', res.statusCode) + .replace(/\{error\}/g, utils.escape(err.toString().replace(/\n/g, '
    '))); + res.setHeader('Content-Type', 'text/html; charset=utf-8'); + res.end(html); + }); + }); + // json + } else if (~accept.indexOf('json')) { + var error = { message: err.message, stack: err.stack }; + for (var prop in err) error[prop] = err[prop]; + var json = JSON.stringify({ error: error }); + res.setHeader('Content-Type', 'application/json'); + res.end(json); + // plain text + } else { + res.writeHead(res.statusCode, { 'Content-Type': 'text/plain' }); + res.end(err.stack); + } + }; +}; + +/** + * Template title, framework authors may override this value. + */ + +exports.title = 'Connect'; diff --git a/node_modules/express/node_modules/connect/lib/middleware/favicon.js b/node_modules/express/node_modules/connect/lib/middleware/favicon.js new file mode 100644 index 0000000..ef54354 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/favicon.js @@ -0,0 +1,80 @@ +/*! + * Connect - favicon + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var fs = require('fs') + , utils = require('../utils'); + +/** + * Favicon: + * + * 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: + * + * Serve default favicon: + * + * connect() + * .use(connect.favicon()) + * + * Serve favicon before logging for brevity: + * + * connect() + * .use(connect.favicon()) + * .use(connect.logger('dev')) + * + * Serve custom favicon: + * + * connect() + * .use(connect.favicon('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 + , icon; // favicon cache + + 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(); + } + }; +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/json.js b/node_modules/express/node_modules/connect/lib/middleware/json.js new file mode 100644 index 0000000..d3e948e --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/json.js @@ -0,0 +1,97 @@ + +/*! + * Connect - json + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils'); +var getBody = require('raw-body'); +var bytes = require('bytes'); + +/** + * JSON: + * + * Parse JSON request bodies, providing the + * parsed object as `req.body`. + * + * Options: + * + * - `strict` when `false` anything `JSON.parse()` accepts will be parsed + * - `reviver` used as the second "reviver" argument for JSON.parse + * - `limit` byte limit [1mb] + * - `verify` synchronous verification function. + * should have signature (req, res, buffer). + * should throw an error on failure. + * + * @param {Object} options + * @return {Function} + * @api public + */ + +exports = module.exports = function(options){ + options = options || {}; + var strict = options.strict !== false; + var verify = typeof options.verify === 'function' && options.verify; + + var limit = !options.limit ? bytes('1mb') + : typeof options.limit === 'number' ? options.limit + : typeof options.limit === 'string' ? bytes(options.limit) + : null; + + return function json(req, res, next) { + if (req._body) return next(); + req.body = req.body || {}; + + if (!utils.hasBody(req)) return next(); + + // check Content-Type + if (!exports.regexp.test(utils.mime(req))) return next(); + + // flag as parsed + req._body = true; + + // parse + getBody(req, { + limit: limit, + expected: req.headers['content-length'] + }, function (err, buf) { + if (err) return next(err); + + if (verify) { + try { + verify(req, res, buf) + } catch (err) { + if (!err.status) err.status = 403; + return next(err); + } + } + + buf = buf.toString('utf8').trim(); + + var first = buf[0]; + + if (0 == buf.length) { + return next(utils.error(400, 'invalid json, empty body')); + } + + if (strict && '{' != first && '[' != first) return next(utils.error(400, 'invalid json')); + try { + req.body = JSON.parse(buf, options.reviver); + } catch (err){ + err.body = buf; + err.status = 400; + return next(err); + } + next(); + }) + }; +}; + +exports.regexp = /^application\/([\w!#\$%&\*`\-\.\^~]*\+)?json$/i; + diff --git a/node_modules/express/node_modules/connect/lib/middleware/limit.js b/node_modules/express/node_modules/connect/lib/middleware/limit.js new file mode 100644 index 0000000..f16439c --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/limit.js @@ -0,0 +1,83 @@ + +/*! + * Connect - limit + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils'), + brokenPause = utils.brokenPause; + +/** + * Limit: + * + * 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. + * + * connect() + * .use(connect.limit('5.5mb')) + * .use(handleImageUpload) + * + * @param {Number|String} bytes + * @return {Function} + * @api public + */ + +module.exports = function limit(bytes){ + if ('string' == typeof bytes) bytes = utils.parseBytes(bytes); + if ('number' != typeof bytes) throw new Error('limit() bytes required'); + + if (process.env.NODE_ENV !== 'test') { + console.warn('connect.limit() will be removed in connect 3.0'); + } + + return function limit(req, res, next){ + var received = 0 + , len = req.headers['content-length'] + ? parseInt(req.headers['content-length'], 10) + : null; + + // self-awareness + if (req._limit) return next(); + req._limit = true; + + // limit by content-length + if (len && len > bytes) return next(utils.error(413)); + + // limit + if (brokenPause) { + listen(); + } else { + req.on('newListener', function handler(event) { + if (event !== 'data') return; + + req.removeListener('newListener', handler); + // Start listening at the end of the current loop + // otherwise the request will be consumed too early. + // Sideaffect is `limit` will miss the first chunk, + // but that's not a big deal. + // Unfortunately, the tests don't have large enough + // request bodies to test this. + process.nextTick(listen); + }); + }; + + next(); + + function listen() { + req.on('data', function(chunk) { + received += Buffer.isBuffer(chunk) + ? chunk.length : + Buffer.byteLength(chunk); + + if (received > bytes) req.destroy(); + }); + }; + }; +}; \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/lib/middleware/logger.js b/node_modules/express/node_modules/connect/lib/middleware/logger.js new file mode 100644 index 0000000..fba43e4 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/logger.js @@ -0,0 +1,342 @@ +/*! + * Connect - logger + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var bytes = require('bytes'); + +/*! + * Log buffer. + */ + +var buf = []; + +/*! + * Default log buffer duration. + */ + +var defaultBufferDuration = 1000; + +/** + * Logger: + * + * 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({ immediate: true, format: 'dev' }) + * connect.logger(':method :url - :referrer') + * connect.logger(':req[content-type] -> :res[content-type]') + * connect.logger(function(tokens, 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('')); + buf.length = 0; + } + }, interval); + + // swap the stream + stream = { + write: function(str){ + buf.push(str); + } + }; + } + + return function logger(req, res, next) { + var sock = req.socket; + req._startTime = new Date; + req._remoteAddress = sock.socket ? sock.socket.remoteAddress : sock.remoteAddress; + + function logRequest(){ + res.removeListener('finish', logRequest); + res.removeListener('close', logRequest); + var line = fmt(exports, req, res); + if (null == line) return; + stream.write(line + '\n'); + }; + + // immediate + if (immediate) { + logRequest(); + // proxy end to output logging + } else { + res.on('finish', logRequest); + res.on('close', logRequest); + } + + + 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 + , len = parseInt(res.getHeader('Content-Length'), 10) + , color = 32; + + if (status >= 500) color = 31 + else if (status >= 400) color = 33 + else if (status >= 300) color = 36; + + len = isNaN(len) + ? '' + : len = ' - ' + bytes(len); + + return '\x1b[90m' + req.method + + ' ' + req.originalUrl + ' ' + + '\x1b[' + color + 'm' + res.statusCode + + ' \x1b[90m' + + (new Date - req._startTime) + + 'ms' + len + + '\x1b[0m'; +}); + +/** + * request url + */ + +exports.token('url', function(req){ + return req.originalUrl || req.url; +}); + +/** + * request method + */ + +exports.token('method', function(req){ + return req.method; +}); + +/** + * response time in milliseconds + */ + +exports.token('response-time', function(req){ + return String(Date.now() - req._startTime); +}); + +/** + * UTC date + */ + +exports.token('date', function(){ + return new Date().toUTCString(); +}); + +/** + * response status code + */ + +exports.token('status', function(req, res){ + return res.headerSent ? res.statusCode : null; +}); + +/** + * normalized referrer + */ + +exports.token('referrer', function(req){ + return req.headers['referer'] || req.headers['referrer']; +}); + +/** + * remote address + */ + +exports.token('remote-addr', function(req){ + if (req.ip) return req.ip; + if (req._remoteAddress) return req._remoteAddress; + var sock = req.socket; + if (sock.socket) return sock.socket.remoteAddress; + return sock.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/node_modules/express/node_modules/connect/lib/middleware/methodOverride.js b/node_modules/express/node_modules/connect/lib/middleware/methodOverride.js new file mode 100644 index 0000000..a729d13 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/methodOverride.js @@ -0,0 +1,58 @@ +/*! + * Connect - methodOverride + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var methods = require('methods'); + +/** + * Method Override: + * + * Provides faux HTTP method support. + * + * Pass an optional `key` to use when checking for + * a method override, otherwise 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) { + var method; + req.originalMethod = req.originalMethod || req.method; + + // req.body + if (req.body && typeof req.body === 'object' && key in req.body) { + method = req.body[key].toLowerCase(); + delete req.body[key]; + } + + // check X-HTTP-Method-Override + if (req.headers['x-http-method-override']) { + method = req.headers['x-http-method-override'].toLowerCase(); + } + + // replace + if (supports(method)) req.method = method.toUpperCase(); + + next(); + }; +}; + +/** + * Check if node supports `method`. + */ + +function supports(method) { + return ~methods.indexOf(method); +} diff --git a/node_modules/express/node_modules/connect/lib/middleware/multipart.js b/node_modules/express/node_modules/connect/lib/middleware/multipart.js new file mode 100644 index 0000000..b985d2c --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/multipart.js @@ -0,0 +1,164 @@ +/*! + * Connect - multipart + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var multiparty = require('multiparty') + , _limit = require('./limit') + , utils = require('../utils') + , qs = require('qs'); + +/** + * Multipart: + * + * Parse multipart/form-data request bodies, + * providing the parsed object as `req.body` + * and `req.files`. + * + * Configuration: + * + * The options passed are merged with [multiparty](https://github.com/superjoe30/node-multiparty)'s + * `Form` object, allowing you to configure the upload directory, + * size limits, etc. For example if you wish to change the upload dir do the following. + * + * app.use(connect.multipart({ uploadDir: path })); + * + * Options: + * + * - `limit` byte limit defaulting to [100mb] + * - `defer` defers processing and exposes the multiparty form object as `req.form`. + * `next()` is called without waiting for the form's "end" event. + * This option is useful if you need to bind to the "progress" or "part" events, for example. + * + * Temporary Files: + * + * By default temporary files are used, stored in `os.tmpDir()`. These + * are not automatically garbage collected, you are in charge of moving them + * or deleting them. When `defer` is not used and these files are created you + * may refernce them via the `req.files` object. + * + * req.files.images.forEach(function(file){ + * console.log(' uploaded : %s %skb : %s', file.originalFilename, file.size / 1024 | 0, file.path); + * }); + * + * It is highly recommended to monitor and clean up tempfiles in any production + * environment, you may use tools like [reap](https://github.com/visionmedia/reap) + * to do so. + * + * Streaming: + * + * When `defer` is used files are _not_ streamed to tmpfiles, you may + * access them via the "part" events and stream them accordingly: + * + * req.form.on('part', function(part){ + * // transfer to s3 etc + * console.log('upload %s %s', part.name, part.filename); + * var out = fs.createWriteStream('/tmp/' + part.filename); + * part.pipe(out); + * }); + * + * req.form.on('close', function(){ + * res.end('uploaded!'); + * }); + * + * @param {Object} options + * @return {Function} + * @api public + */ + +exports = module.exports = function(options){ + options = options || {}; + + if (process.env.NODE_ENV !== 'test') { + console.warn('connect.multipart() will be removed in connect 3.0'); + console.warn('visit https://github.com/senchalabs/connect/wiki/Connect-3.0 for alternatives'); + } + + var limit = _limit(options.limit || '100mb'); + + return function multipart(req, res, next) { + if (req._body) return next(); + req.body = req.body || {}; + req.files = req.files || {}; + + if (!utils.hasBody(req)) return next(); + + // ignore GET + if ('GET' == req.method || 'HEAD' == req.method) return next(); + + // check Content-Type + if ('multipart/form-data' != utils.mime(req)) return next(); + + // flag as parsed + req._body = true; + + // parse + limit(req, res, function(err){ + if (err) return next(err); + + var form = new multiparty.Form(options) + , data = {} + , files = {} + , done; + + Object.keys(options).forEach(function(key){ + form[key] = options[key]; + }); + + function ondata(name, val, data){ + if (Array.isArray(data[name])) { + data[name].push(val); + } else if (data[name]) { + data[name] = [data[name], val]; + } else { + data[name] = val; + } + } + + form.on('field', function(name, val){ + ondata(name, val, data); + }); + + if (!options.defer) { + form.on('file', function(name, val){ + val.name = val.originalFilename; + val.type = val.headers['content-type'] || null; + ondata(name, val, files); + }); + } + + form.on('error', function(err){ + if (!options.defer) { + err.status = 400; + next(err); + } + done = true; + }); + + form.on('close', function(){ + if (done) return; + try { + req.body = qs.parse(data); + req.files = qs.parse(files); + } catch (err) { + form.emit('error', err); + return; + } + if (!options.defer) next(); + }); + + form.parse(req); + + if (options.defer) { + req.form = form; + next(); + } + }); + } +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/query.js b/node_modules/express/node_modules/connect/lib/middleware/query.js new file mode 100644 index 0000000..93fc5d3 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/query.js @@ -0,0 +1,46 @@ +/*! + * Connect - query + * Copyright(c) 2011 TJ Holowaychuk + * Copyright(c) 2011 Sencha Inc. + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var qs = require('qs') + , parse = require('../utils').parseUrl; + +/** + * Query: + * + * Automatically parse the query-string when available, + * populating the `req.query` object. + * + * Examples: + * + * connect() + * .use(connect.query()) + * .use(function(req, res){ + * res.end(JSON.stringify(req.query)); + * }); + * + * The `options` passed are provided to qs.parse function. + * + * @param {Object} options + * @return {Function} + * @api public + */ + +module.exports = function query(options){ + return function query(req, res, next){ + if (!req.query) { + req.query = ~req.url.indexOf('?') + ? qs.parse(parse(req).query, options) + : {}; + } + + next(); + }; +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/responseTime.js b/node_modules/express/node_modules/connect/lib/middleware/responseTime.js new file mode 100644 index 0000000..62abc04 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/responseTime.js @@ -0,0 +1,32 @@ + +/*! + * Connect - responseTime + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Reponse time: + * + * 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 start = new Date; + + if (res._responseTime) return next(); + res._responseTime = true; + + res.on('header', function(){ + var duration = new Date - start; + res.setHeader('X-Response-Time', duration + 'ms'); + }); + + next(); + }; +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/session.js b/node_modules/express/node_modules/connect/lib/middleware/session.js new file mode 100644 index 0000000..d918d30 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/session.js @@ -0,0 +1,361 @@ +/*! + * Connect - session + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Session = require('./session/session') + , debug = require('debug')('connect:session') + , MemoryStore = require('./session/memory') + , signature = require('cookie-signature') + , Cookie = require('./session/cookie') + , Store = require('./session/store') + , utils = require('./../utils') + , uid = require('uid2') + , crc32 = require('buffer-crc32') + , parse = require('url').parse; + +// 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 will not scale past a single process.'; + +/** + * Session: + * + * 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()](cookieParser.html) + * middleware _before_ `session()`. + * + * Examples: + * + * connect() + * .use(connect.cookieParser()) + * .use(connect.session({ secret: 'keyboard cat', key: 'sid', cookie: { secure: true }})) + * + * Options: + * + * - `key` cookie name defaulting to `connect.sid` + * - `store` session store instance + * - `secret` session cookie is signed with this secret to prevent tampering + * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }` + * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto") + * + * Cookie option: + * + * By default `cookie.maxAge` is `null`, meaning no "expires" parameter is set + * so the cookie becomes a browser-session cookie. When the user closes the + * browser the cookie (and session) will be removed. + * + * ## 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() + * .use(connect.favicon()) + * .use(connect.cookieParser()) + * .use(connect.session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }})) + * .use(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` property. 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 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' + , store = options.store || new MemoryStore + , cookie = options.cookie || {} + , trustProxy = options.proxy + , storeReady = true + , rollingSessions = options.rolling || false; + + // notify user that this store is not + // meant for a production environment + if ('production' == env && store instanceof MemoryStore) { + console.warn(warning); + } + + // generates the new session + store.generate = function(req){ + req.sessionID = uid(24); + req.session = new Session(req); + req.session.cookie = new Cookie(cookie); + }; + + store.on('disconnect', function(){ storeReady = false; }); + store.on('connect', function(){ storeReady = true; }); + + return function session(req, res, next) { + // self-awareness + if (req.session) return next(); + + // Handle connection as if there is no session if + // the store has temporarily disconnected etc + if (!storeReady) return debug('store is disconnected'), next(); + + // pathname mismatch + var originalPath = parse(req.originalUrl).pathname; + if (0 != originalPath.indexOf(cookie.path || '/')) return next(); + + // backwards compatibility for signed cookies + // req.secret is passed from the cookie parser middleware + var secret = options.secret || req.secret; + + // ensure secret is available or bail + if (!secret) throw new Error('`secret` option required for sessions'); + + var originalHash + , originalId; + + // expose store + req.sessionStore = store; + + // grab the session cookie value and check the signature + var rawCookie = req.cookies[key]; + + // get signedCookies for backwards compat with signed cookies + var unsignedCookie = req.signedCookies[key]; + + if (!unsignedCookie && rawCookie) { + unsignedCookie = utils.parseSignedCookie(rawCookie, secret); + } + + // set-cookie + res.on('header', function(){ + if (!req.session) return; + var cookie = req.session.cookie + , proto = (req.headers['x-forwarded-proto'] || '').split(',')[0].toLowerCase().trim() + , tls = req.connection.encrypted || (trustProxy && 'https' == proto) + , isNew = unsignedCookie != req.sessionID; + + // only send secure cookies via https + if (cookie.secure && !tls) return debug('not secured'); + + // in case of rolling session, always reset the cookie + if (!rollingSessions) { + + // long expires, handle expiry server-side + if (!isNew && cookie.hasLongExpires) return debug('already set cookie'); + + // browser-session length cookie + if (null == cookie.expires) { + if (!isNew) return debug('already set browser-session cookie'); + // compare hashes and ids + } else if (originalHash == hash(req.session) && originalId == req.session.id) { + return debug('unmodified session'); + } + + } + + var val = 's:' + signature.sign(req.sessionID, secret); + val = cookie.serialize(key, val); + debug('set-cookie %s', val); + res.setHeader('Set-Cookie', val); + }); + + // proxy end() to commit the session + var end = res.end; + res.end = function(data, encoding){ + res.end = end; + if (!req.session) return res.end(data, encoding); + debug('saving'); + req.session.resetMaxAge(); + req.session.save(function(err){ + if (err) console.error(err.stack); + debug('saved'); + res.end(data, encoding); + }); + }; + + // generate the session + function generate() { + store.generate(req); + } + + // get the sessionID from the cookie + req.sessionID = unsignedCookie; + + // generate a session if the browser doesn't send a sessionID + if (!req.sessionID) { + debug('no SID sent, generating session'); + generate(); + next(); + return; + } + + // generate the session object + var pause = utils.pause(req); + debug('fetching %s', req.sessionID); + 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) { + debug('error %j', err); + if ('ENOENT' == err.code) { + generate(); + next(); + } else { + next(err); + } + // no session + } else if (!sess) { + debug('no session found'); + generate(); + next(); + // populate req.session + } else { + debug('session found'); + store.createSession(req, sess); + originalId = req.sessionID; + originalHash = hash(sess); + next(); + } + }); + }; +}; + +/** + * Hash the given `sess` object omitting changes + * to `.cookie`. + * + * @param {Object} sess + * @return {String} + * @api private + */ + +function hash(sess) { + return crc32.signed(JSON.stringify(sess, function(key, val){ + if ('cookie' != key) return val; + })); +} diff --git a/node_modules/express/node_modules/connect/lib/middleware/session/cookie.js b/node_modules/express/node_modules/connect/lib/middleware/session/cookie.js new file mode 100644 index 0000000..cdce2a5 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/session/cookie.js @@ -0,0 +1,140 @@ + +/*! + * Connect - session - Cookie + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../../utils') + , cookie = require('cookie'); + +/** + * Initialize a new `Cookie` with the given `options`. + * + * @param {IncomingMessage} req + * @param {Object} options + * @api private + */ + +var Cookie = module.exports = function Cookie(options) { + this.path = '/'; + this.maxAge = null; + this.httpOnly = true; + 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 + } + }, + + /** + * Check if the cookie has a reasonably large max-age. + * + * @return {Boolean} + * @api private + */ + + get hasLongExpires() { + var week = 604800000; + return this.maxAge > (4 * week); + }, + + /** + * Return a serialized cookie string. + * + * @return {String} + * @api public + */ + + serialize: function(name, val){ + return cookie.serialize(name, val, this.data); + }, + + /** + * Return JSON representation of this cookie. + * + * @return {Object} + * @api private + */ + + toJSON: function(){ + return this.data; + } +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/session/memory.js b/node_modules/express/node_modules/connect/lib/middleware/session/memory.js new file mode 100644 index 0000000..fb93939 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/session/memory.js @@ -0,0 +1,129 @@ + +/*! + * Connect - session - MemoryStore + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Store = require('./store'); + +/** + * 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/node_modules/express/node_modules/connect/lib/middleware/session/session.js b/node_modules/express/node_modules/connect/lib/middleware/session/session.js new file mode 100644 index 0000000..0dd4b40 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/session/session.js @@ -0,0 +1,116 @@ + +/*! + * Connect - session - Session + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../../utils'); + +/** + * 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); +}; + +/** + * Update 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.resetMaxAge(); +}; + +/** + * 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 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/node_modules/express/node_modules/connect/lib/middleware/session/store.js b/node_modules/express/node_modules/connect/lib/middleware/session/store.js new file mode 100644 index 0000000..54294cb --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/session/store.js @@ -0,0 +1,84 @@ + +/*! + * Connect - session - Store + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , Session = require('./session') + , Cookie = require('./cookie'); + +/** + * Initialize abstract `Store`. + * + * @api private + */ + +var Store = module.exports = function Store(options){}; + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Store.prototype.__proto__ = EventEmitter.prototype; + +/** + * 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); + }); +}; + +/** + * Load a `Session` instance via the given `sid` + * and invoke the callback `fn(err, sess)`. + * + * @param {String} sid + * @param {Function} fn + * @api public + */ + +Store.prototype.load = function(sid, fn){ + var self = this; + this.get(sid, function(err, sess){ + if (err) return fn(err); + if (!sess) return fn(); + var req = { sessionID: sid, sessionStore: self }; + sess = self.createSession(req, sess); + fn(null, sess); + }); +}; + +/** + * 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); + return req.session; +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/static.js b/node_modules/express/node_modules/connect/lib/middleware/static.js new file mode 100644 index 0000000..67970da --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/static.js @@ -0,0 +1,102 @@ +/*! + * Connect - static + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var send = require('send') + , utils = require('../utils') + , parse = utils.parseUrl + , url = require('url'); + +/** + * Static: + * + * Static file server with the given `root` path. + * + * Examples: + * + * var oneDay = 86400000; + * + * connect() + * .use(connect.static(__dirname + '/public')) + * + * connect() + * .use(connect.static(__dirname + '/public', { maxAge: oneDay })) + * + * Options: + * + * - `maxAge` Browser cache maxAge in milliseconds. defaults to 0 + * - `hidden` Allow transfer of hidden files. defaults to false + * - `redirect` Redirect to trailing "/" when the pathname is a dir. defaults to true + * - `index` Default file name, defaults to 'index.html' + * + * @param {String} root + * @param {Object} options + * @return {Function} + * @api public + */ + +exports = module.exports = function(root, options){ + options = options || {}; + + // root required + if (!root) throw new Error('static() root path required'); + + // default redirect + var redirect = false !== options.redirect; + + return function staticMiddleware(req, res, next) { + if ('GET' != req.method && 'HEAD' != req.method) return next(); + var originalUrl = url.parse(req.originalUrl); + var path = parse(req).pathname; + var pause = utils.pause(req); + + if (path == '/' && originalUrl.pathname[originalUrl.pathname.length - 1] != '/') { + return directory(); + } + + function resume() { + next(); + pause.resume(); + } + + function directory() { + if (!redirect) return resume(); + var target; + originalUrl.pathname += '/'; + target = url.format(originalUrl); + res.statusCode = 303; + res.setHeader('Location', target); + res.end('Redirecting to ' + utils.escape(target)); + } + + function error(err) { + if (404 == err.status) return resume(); + next(err); + } + + send(req, path) + .maxage(options.maxAge || 0) + .root(root) + .index(options.index || 'index.html') + .hidden(options.hidden) + .on('error', error) + .on('directory', directory) + .pipe(res); + }; +}; + +/** + * Expose mime module. + * + * If you wish to extend the mime table use this + * reference to the "mime" module in the npm registry. + */ + +exports.mime = send.mime; diff --git a/node_modules/express/node_modules/connect/lib/middleware/staticCache.js b/node_modules/express/node_modules/connect/lib/middleware/staticCache.js new file mode 100644 index 0000000..cc4c3a2 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/staticCache.js @@ -0,0 +1,233 @@ + +/*! + * Connect - staticCache + * Copyright(c) 2011 Sencha Inc. + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils') + , Cache = require('../cache') + , fresh = require('fresh'); + +/** + * Static cache: + * + * Enables a memory cache layer on top of + * the `static()` middleware, serving popular + * static files. + * + * By default a maximum of 128 objects are + * held in cache, with a max of 256k each, + * totalling ~32mb. + * + * A Least-Recently-Used (LRU) cache algo + * is implemented through the `Cache` object, + * simply rotating cache objects as they are + * hit. This means that increasingly popular + * objects maintain their positions while + * others get shoved out of the stack and + * garbage collected. + * + * Benchmarks: + * + * static(): 2700 rps + * node-static: 5300 rps + * static() + staticCache(): 7500 rps + * + * Options: + * + * - `maxObjects` max cache objects [128] + * - `maxLength` max cache object length 256kb + * + * @param {Object} options + * @return {Function} + * @api public + */ + +module.exports = function staticCache(options){ + var options = options || {} + , cache = new Cache(options.maxObjects || 128) + , maxlen = options.maxLength || 1024 * 256; + + if (process.env.NODE_ENV !== 'test') { + console.warn('connect.staticCache() is deprecated and will be removed in 3.0'); + console.warn('use varnish or similar reverse proxy caches.'); + } + + return function staticCache(req, res, next){ + var key = cacheKey(req) + , ranges = req.headers.range + , hasCookies = req.headers.cookie + , hit = cache.get(key); + + // cache static + // TODO: change from staticCache() -> cache() + // and make this work for any request + req.on('static', function(stream){ + var headers = res._headers + , cc = utils.parseCacheControl(headers['cache-control'] || '') + , contentLength = headers['content-length'] + , hit; + + // dont cache set-cookie responses + if (headers['set-cookie']) return hasCookies = true; + + // dont cache when cookies are present + if (hasCookies) return; + + // ignore larger files + if (!contentLength || contentLength > maxlen) return; + + // don't cache partial files + if (headers['content-range']) return; + + // dont cache items we shouldn't be + // TODO: real support for must-revalidate / no-cache + if ( cc['no-cache'] + || cc['no-store'] + || cc['private'] + || cc['must-revalidate']) return; + + // if already in cache then validate + if (hit = cache.get(key)){ + if (headers.etag == hit[0].etag) { + hit[0].date = new Date; + return; + } else { + cache.remove(key); + } + } + + // validation notifiactions don't contain a steam + if (null == stream) return; + + // add the cache object + var arr = []; + + // store the chunks + stream.on('data', function(chunk){ + arr.push(chunk); + }); + + // flag it as complete + stream.on('end', function(){ + var cacheEntry = cache.add(key); + delete headers['x-cache']; // Clean up (TODO: others) + cacheEntry.push(200); + cacheEntry.push(headers); + cacheEntry.push.apply(cacheEntry, arr); + }); + }); + + if (req.method == 'GET' || req.method == 'HEAD') { + if (ranges) { + next(); + } else if (!hasCookies && hit && !mustRevalidate(req, hit)) { + res.setHeader('X-Cache', 'HIT'); + respondFromCache(req, res, hit); + } else { + res.setHeader('X-Cache', 'MISS'); + next(); + } + } else { + next(); + } + } +}; + +/** + * Respond with the provided cached value. + * TODO: Assume 200 code, that's iffy. + * + * @param {Object} req + * @param {Object} res + * @param {Object} cacheEntry + * @return {String} + * @api private + */ + +function respondFromCache(req, res, cacheEntry) { + var status = cacheEntry[0] + , headers = utils.merge({}, cacheEntry[1]) + , content = cacheEntry.slice(2); + + headers.age = (new Date - new Date(headers.date)) / 1000 || 0; + + switch (req.method) { + case 'HEAD': + res.writeHead(status, headers); + res.end(); + break; + case 'GET': + if (utils.conditionalGET(req) && fresh(req.headers, headers)) { + headers['content-length'] = 0; + res.writeHead(304, headers); + res.end(); + } else { + res.writeHead(status, headers); + + function write() { + while (content.length) { + if (false === res.write(content.shift())) { + res.once('drain', write); + return; + } + } + res.end(); + } + + write(); + } + break; + default: + // This should never happen. + res.writeHead(500, ''); + res.end(); + } +} + +/** + * Determine whether or not a cached value must be revalidated. + * + * @param {Object} req + * @param {Object} cacheEntry + * @return {String} + * @api private + */ + +function mustRevalidate(req, cacheEntry) { + var cacheHeaders = cacheEntry[1] + , reqCC = utils.parseCacheControl(req.headers['cache-control'] || '') + , cacheCC = utils.parseCacheControl(cacheHeaders['cache-control'] || '') + , cacheAge = (new Date - new Date(cacheHeaders.date)) / 1000 || 0; + + if ( cacheCC['no-cache'] + || cacheCC['must-revalidate'] + || cacheCC['proxy-revalidate']) return true; + + if (reqCC['no-cache']) return true; + + if (null != reqCC['max-age']) return reqCC['max-age'] < cacheAge; + + if (null != cacheCC['max-age']) return cacheCC['max-age'] < cacheAge; + + return false; +} + +/** + * The key to use in the cache. For now, this is the URL path and query. + * + * 'http://example.com?key=value' -> '/?key=value' + * + * @param {Object} req + * @return {String} + * @api private + */ + +function cacheKey(req) { + return utils.parseUrl(req).path; +} diff --git a/node_modules/express/node_modules/connect/lib/middleware/timeout.js b/node_modules/express/node_modules/connect/lib/middleware/timeout.js new file mode 100644 index 0000000..5496c02 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/timeout.js @@ -0,0 +1,55 @@ +/*! + * Connect - timeout + * Ported from https://github.com/LearnBoost/connect-timeout + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var debug = require('debug')('connect:timeout'); + +/** + * Timeout: + * + * Times out the request in `ms`, defaulting to `5000`. The + * method `req.clearTimeout()` is added to revert this behaviour + * programmatically within your application's middleware, routes, etc. + * + * The timeout error is passed to `next()` so that you may customize + * the response behaviour. This error has the `.timeout` property as + * well as `.status == 503`. + * + * @param {Number} ms + * @return {Function} + * @api public + */ + +module.exports = function timeout(ms) { + ms = ms || 5000; + + return function(req, res, next) { + var id = setTimeout(function(){ + req.emit('timeout', ms); + }, ms); + + req.on('timeout', function(){ + if (res.headerSent) return debug('response started, cannot timeout'); + var err = new Error('Response timeout'); + err.timeout = ms; + err.status = 503; + next(err); + }); + + req.clearTimeout = function(){ + clearTimeout(id); + }; + + res.on('header', function(){ + clearTimeout(id); + }); + + next(); + }; +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/urlencoded.js b/node_modules/express/node_modules/connect/lib/middleware/urlencoded.js new file mode 100644 index 0000000..30fd088 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/urlencoded.js @@ -0,0 +1,86 @@ + +/*! + * Connect - urlencoded + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils'); +var getBody = require('raw-body'); +var bytes = require('bytes'); +var qs = require('qs'); + +/** + * Urlencoded: + * + * Parse x-ww-form-urlencoded request bodies, + * providing the parsed object as `req.body`. + * + * Options: + * + * - `limit` byte limit [1mb] + * - `verify` synchronous verification function. + * should have signature (req, res, buffer). + * should throw an error on failure. + * + * @param {Object} options + * @return {Function} + * @api public + */ + +exports = module.exports = function(options){ + options = options || {}; + var verify = typeof options.verify === 'function' && options.verify; + + var limit = !options.limit ? bytes('1mb') + : typeof options.limit === 'number' ? options.limit + : typeof options.limit === 'string' ? bytes(options.limit) + : null + + return function urlencoded(req, res, next) { + if (req._body) return next(); + req.body = req.body || {}; + + if (!utils.hasBody(req)) return next(); + + // check Content-Type + if ('application/x-www-form-urlencoded' != utils.mime(req)) return next(); + + // flag as parsed + req._body = true; + + // parse + getBody(req, { + limit: limit, + expected: req.headers['content-length'] + }, function (err, buf) { + if (err) return next(err); + + if (verify) { + try { + verify(req, res, buf) + } catch (err) { + if (!err.status) err.status = 403; + return next(err); + } + } + + buf = buf.toString('utf8').trim(); + + try { + req.body = buf.length + ? qs.parse(buf, options) + : {}; + } catch (err){ + err.body = buf; + return next(err); + } + next(); + }) + } +}; diff --git a/node_modules/express/node_modules/connect/lib/middleware/vhost.js b/node_modules/express/node_modules/connect/lib/middleware/vhost.js new file mode 100644 index 0000000..abbb050 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/middleware/vhost.js @@ -0,0 +1,40 @@ + +/*! + * Connect - vhost + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Vhost: + * + * Setup vhost for the given `hostname` and `server`. + * + * connect() + * .use(connect.vhost('foo.com', fooApp)) + * .use(connect.vhost('bar.com', barApp)) + * .use(connect.vhost('*.com', mainApp)) + * + * The `server` may be a Connect server or + * a regular Node `http.Server`. + * + * @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(/[^*\w]/g, '\\$&').replace(/[*]/g, '(?:.*?)') + '$', 'i'); + 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 (!regexp.test(host)) return next(); + if ('function' == typeof server) return server(req, res, next); + server.emit('request', req, res); + }; +}; diff --git a/node_modules/express/node_modules/connect/lib/patch.js b/node_modules/express/node_modules/connect/lib/patch.js new file mode 100644 index 0000000..22bcbc6 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/patch.js @@ -0,0 +1,89 @@ + +/*! + * Connect + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var http = require('http') + , res = http.ServerResponse.prototype + , setHeader = res.setHeader + , _renderHeaders = res._renderHeaders + , writeHead = res.writeHead; + +// apply only once + +if (!res._hasConnectPatch) { + + /** + * Provide a public "header sent" flag + * until node does. + * + * @return {Boolean} + * @api public + */ + + res.__defineGetter__('headerSent', function(){ + return this._header; + }); + + /** + * 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)) { + if (Array.isArray(prev)) { + val = prev.concat(val); + } else if (Array.isArray(val)) { + val = val.concat(prev); + } else { + val = [prev, val]; + } + } + // charset + } else if ('content-type' == key && this.charset) { + val += '; charset=' + this.charset; + } + + return setHeader.call(this, field, val); + }; + + /** + * Proxy to emit "header" event. + */ + + res._renderHeaders = function(){ + if (!this._emittedHeader) this.emit('header'); + this._emittedHeader = true; + return _renderHeaders.call(this); + }; + + res.writeHead = function(statusCode, reasonPhrase, headers){ + if (typeof reasonPhrase === 'object') headers = reasonPhrase; + if (typeof headers === 'object') { + Object.keys(headers).forEach(function(key){ + this.setHeader(key, headers[key]); + }, this); + } + if (!this._emittedHeader) this.emit('header'); + this._emittedHeader = true; + return writeHead.call(this, statusCode, reasonPhrase); + }; + + res._hasConnectPatch = true; +} diff --git a/node_modules/express/node_modules/connect/lib/proto.js b/node_modules/express/node_modules/connect/lib/proto.js new file mode 100644 index 0000000..44337b3 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/proto.js @@ -0,0 +1,233 @@ +/*! + * Connect - HTTPServer + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var http = require('http') + , utils = require('./utils') + , debug = require('debug')('connect:dispatcher'); + +// prototype + +var app = module.exports = {}; + +// environment + +var env = process.env.NODE_ENV || 'development'; + +/** + * 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_. + * + * Examples: + * + * var app = connect(); + * app.use(connect.favicon()); + * app.use(connect.logger()); + * app.use(connect.static(__dirname + '/public')); + * + * If we wanted to prefix static files with _/public_, we could + * "mount" the `static()` middleware: + * + * app.use('/public', connect.static(__dirname + '/public')); + * + * This api is chainable, so the following is valid: + * + * connect() + * .use(connect.favicon()) + * .use(connect.logger()) + * .use(connect.static(__dirname + '/public')) + * .listen(3000); + * + * @param {String|Function|Server} route, callback or server + * @param {Function|Server} callback or server + * @return {Server} for chaining + * @api public + */ + +app.use = function(route, fn){ + // default route to '/' + if ('string' != typeof route) { + fn = route; + route = '/'; + } + + // wrap sub-apps + if ('function' == typeof fn.handle) { + var server = fn; + fn.route = route; + fn = function(req, res, next){ + server.handle(req, res, next); + }; + } + + // wrap vanilla http.Servers + if (fn instanceof http.Server) { + fn = fn.listeners('request')[0]; + } + + // strip trailing slash + if ('/' == route[route.length - 1]) { + route = route.slice(0, -1); + } + + // add the middleware + debug('use %s %s', route || '/', fn.name || 'anonymous'); + this.stack.push({ route: route, handle: fn }); + + return this; +}; + +/** + * Handle server requests, punting them down + * the middleware stack. + * + * @api private + */ + +app.handle = function(req, res, out) { + var stack = this.stack + , search = 1 + req.url.indexOf('?') + , pathlength = search ? search - 1 : req.url.length + , fqdn = 1 + req.url.substr(0, pathlength).indexOf('://') + , protohost = fqdn ? req.url.substr(0, req.url.indexOf('/', 2 + fqdn)) : '' + , removed = '' + , slashAdded = false + , index = 0; + + function next(err) { + var layer, path, c; + + if (slashAdded) { + req.url = req.url.substr(1); + slashAdded = false; + } + + req.url = protohost + removed + req.url.substr(protohost.length); + req.originalUrl = req.originalUrl || req.url; + removed = ''; + + // next callback + layer = stack[index++]; + + // all done + if (!layer || res.headerSent) { + // delegate to parent + if (out) return out(err); + + // unhandled error + if (err) { + // default to 500 + if (res.statusCode < 400) res.statusCode = 500; + debug('default %s', res.statusCode); + + // respect err.status + if (err.status) res.statusCode = err.status; + + // production gets a basic error message + var msg = 'production' == env + ? http.STATUS_CODES[res.statusCode] + : err.stack || err.toString(); + msg = utils.escape(msg); + + // log to stderr in a non-test env + if ('test' != env) console.error(err.stack || err.toString()); + if (res.headerSent) return req.socket.destroy(); + res.setHeader('Content-Type', 'text/html'); + res.setHeader('Content-Length', Buffer.byteLength(msg)); + if ('HEAD' == req.method) return res.end(); + res.end(msg); + } else { + debug('default 404'); + res.statusCode = 404; + res.setHeader('Content-Type', 'text/html'); + if ('HEAD' == req.method) return res.end(); + res.end('Cannot ' + utils.escape(req.method) + ' ' + utils.escape(req.originalUrl)); + } + return; + } + + try { + path = utils.parseUrl(req).pathname; + if (undefined == path) path = '/'; + + // skip this layer if the route doesn't match. + if (0 != path.toLowerCase().indexOf(layer.route.toLowerCase())) 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 = protohost + req.url.substr(protohost.length + removed.length); + + // Ensure leading slash + if (!fqdn && '/' != req.url[0]) { + req.url = '/' + req.url; + slashAdded = true; + } + + debug('%s %s : %s', layer.handle.name || 'anonymous', layer.route, req.originalUrl); + 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) { + next(e); + } + } + next(); +}; + +/** + * Listen for connections. + * + * This method takes the same arguments + * as node's `http.Server#listen()`. + * + * HTTP and HTTPS: + * + * If you run your application both as HTTP + * and HTTPS you may wrap them individually, + * since your Connect "server" is really just + * a JavaScript `Function`. + * + * var connect = require('connect') + * , http = require('http') + * , https = require('https'); + * + * var app = connect(); + * + * http.createServer(app).listen(80); + * https.createServer(options, app).listen(443); + * + * @return {http.Server} + * @api public + */ + +app.listen = function(){ + var server = http.createServer(this); + return server.listen.apply(server, arguments); +}; diff --git a/node_modules/express/node_modules/connect/lib/public/directory.html b/node_modules/express/node_modules/connect/lib/public/directory.html new file mode 100644 index 0000000..2d63704 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/public/directory.html @@ -0,0 +1,81 @@ + + + + + listing directory {directory} + + + + + +
    +

    {linked-path}

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

    {title}

    +

    {statusCode} {error}

    +
      {stack}
    +
    + + diff --git a/node_modules/express/node_modules/connect/lib/public/favicon.ico b/node_modules/express/node_modules/connect/lib/public/favicon.ico new file mode 100644 index 0000000..895fc96 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/favicon.ico differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page.png b/node_modules/express/node_modules/connect/lib/public/icons/page.png new file mode 100644 index 0000000..03ddd79 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_add.png b/node_modules/express/node_modules/connect/lib/public/icons/page_add.png new file mode 100644 index 0000000..d5bfa07 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_add.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_attach.png b/node_modules/express/node_modules/connect/lib/public/icons/page_attach.png new file mode 100644 index 0000000..89ee2da Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_attach.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_code.png b/node_modules/express/node_modules/connect/lib/public/icons/page_code.png new file mode 100644 index 0000000..f7ea904 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_code.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_copy.png b/node_modules/express/node_modules/connect/lib/public/icons/page_copy.png new file mode 100644 index 0000000..195dc6d Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_copy.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_delete.png b/node_modules/express/node_modules/connect/lib/public/icons/page_delete.png new file mode 100644 index 0000000..3141467 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_delete.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_edit.png b/node_modules/express/node_modules/connect/lib/public/icons/page_edit.png new file mode 100644 index 0000000..046811e Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_edit.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_error.png b/node_modules/express/node_modules/connect/lib/public/icons/page_error.png new file mode 100644 index 0000000..f07f449 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_error.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_excel.png b/node_modules/express/node_modules/connect/lib/public/icons/page_excel.png new file mode 100644 index 0000000..eb6158e Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_excel.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_find.png b/node_modules/express/node_modules/connect/lib/public/icons/page_find.png new file mode 100644 index 0000000..2f19388 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_find.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_gear.png b/node_modules/express/node_modules/connect/lib/public/icons/page_gear.png new file mode 100644 index 0000000..8e83281 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_gear.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_go.png b/node_modules/express/node_modules/connect/lib/public/icons/page_go.png new file mode 100644 index 0000000..80fe1ed Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_go.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_green.png b/node_modules/express/node_modules/connect/lib/public/icons/page_green.png new file mode 100644 index 0000000..de8e003 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_green.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_key.png b/node_modules/express/node_modules/connect/lib/public/icons/page_key.png new file mode 100644 index 0000000..d6626cb Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_key.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_lightning.png b/node_modules/express/node_modules/connect/lib/public/icons/page_lightning.png new file mode 100644 index 0000000..7e56870 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_lightning.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_link.png b/node_modules/express/node_modules/connect/lib/public/icons/page_link.png new file mode 100644 index 0000000..312eab0 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_link.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_paintbrush.png b/node_modules/express/node_modules/connect/lib/public/icons/page_paintbrush.png new file mode 100644 index 0000000..246a2f0 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_paintbrush.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_paste.png b/node_modules/express/node_modules/connect/lib/public/icons/page_paste.png new file mode 100644 index 0000000..968f073 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_paste.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_red.png b/node_modules/express/node_modules/connect/lib/public/icons/page_red.png new file mode 100644 index 0000000..0b18247 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_red.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_refresh.png b/node_modules/express/node_modules/connect/lib/public/icons/page_refresh.png new file mode 100644 index 0000000..cf347c7 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_refresh.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_save.png b/node_modules/express/node_modules/connect/lib/public/icons/page_save.png new file mode 100644 index 0000000..caea546 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_save.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white.png new file mode 100644 index 0000000..8b8b1ca Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_acrobat.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_acrobat.png new file mode 100644 index 0000000..8f8095e Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_acrobat.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_actionscript.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_actionscript.png new file mode 100644 index 0000000..159b240 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_actionscript.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_add.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_add.png new file mode 100644 index 0000000..aa23dde Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_add.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_c.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_c.png new file mode 100644 index 0000000..34a05cc Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_c.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_camera.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_camera.png new file mode 100644 index 0000000..f501a59 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_camera.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_cd.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_cd.png new file mode 100644 index 0000000..848bdaf Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_cd.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_code.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_code.png new file mode 100644 index 0000000..0c76bd1 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_code.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_code_red.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_code_red.png new file mode 100644 index 0000000..87a6914 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_code_red.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_coldfusion.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_coldfusion.png new file mode 100644 index 0000000..c66011f Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_coldfusion.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_compressed.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_compressed.png new file mode 100644 index 0000000..2b6b100 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_compressed.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_copy.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_copy.png new file mode 100644 index 0000000..a9f31a2 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_copy.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_cplusplus.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_cplusplus.png new file mode 100644 index 0000000..a87cf84 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_cplusplus.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_csharp.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_csharp.png new file mode 100644 index 0000000..ffb8fc9 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_csharp.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_cup.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_cup.png new file mode 100644 index 0000000..0a7d6f4 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_cup.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_database.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_database.png new file mode 100644 index 0000000..bddba1f Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_database.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_delete.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_delete.png new file mode 100644 index 0000000..af1ecaf Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_delete.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_dvd.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_dvd.png new file mode 100644 index 0000000..4cc537a Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_dvd.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_edit.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_edit.png new file mode 100644 index 0000000..b93e776 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_edit.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_error.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_error.png new file mode 100644 index 0000000..9fc5a0a Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_error.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_excel.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_excel.png new file mode 100644 index 0000000..b977d7e Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_excel.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_find.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_find.png new file mode 100644 index 0000000..5818436 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_find.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_flash.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_flash.png new file mode 100644 index 0000000..5769120 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_flash.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_freehand.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_freehand.png new file mode 100644 index 0000000..8d719df Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_freehand.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_gear.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_gear.png new file mode 100644 index 0000000..106f5aa Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_gear.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_get.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_get.png new file mode 100644 index 0000000..e4a1ecb Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_get.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_go.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_go.png new file mode 100644 index 0000000..7e62a92 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_go.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_h.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_h.png new file mode 100644 index 0000000..e902abb Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_h.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_horizontal.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_horizontal.png new file mode 100644 index 0000000..1d2d0a4 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_horizontal.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_key.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_key.png new file mode 100644 index 0000000..d616484 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_key.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_lightning.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_lightning.png new file mode 100644 index 0000000..7215d1e Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_lightning.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_link.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_link.png new file mode 100644 index 0000000..bf7bd1c Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_link.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_magnify.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_magnify.png new file mode 100644 index 0000000..f6b74cc Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_magnify.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_medal.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_medal.png new file mode 100644 index 0000000..d3fffb6 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_medal.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_office.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_office.png new file mode 100644 index 0000000..a65bcb3 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_office.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_paint.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_paint.png new file mode 100644 index 0000000..23a37b8 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_paint.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_paintbrush.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_paintbrush.png new file mode 100644 index 0000000..f907e44 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_paintbrush.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_paste.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_paste.png new file mode 100644 index 0000000..5b2cbb3 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_paste.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_php.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_php.png new file mode 100644 index 0000000..7868a25 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_php.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_picture.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_picture.png new file mode 100644 index 0000000..134b669 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_picture.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_powerpoint.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_powerpoint.png new file mode 100644 index 0000000..c4eff03 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_powerpoint.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_put.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_put.png new file mode 100644 index 0000000..884ffd6 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_put.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_ruby.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_ruby.png new file mode 100644 index 0000000..f59b7c4 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_ruby.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_stack.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_stack.png new file mode 100644 index 0000000..44084ad Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_stack.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_star.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_star.png new file mode 100644 index 0000000..3a1441c Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_star.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_swoosh.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_swoosh.png new file mode 100644 index 0000000..e770829 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_swoosh.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_text.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_text.png new file mode 100644 index 0000000..813f712 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_text.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_text_width.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_text_width.png new file mode 100644 index 0000000..d9cf132 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_text_width.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_tux.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_tux.png new file mode 100644 index 0000000..52699bf Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_tux.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_vector.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_vector.png new file mode 100644 index 0000000..4a05955 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_vector.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_visualstudio.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_visualstudio.png new file mode 100644 index 0000000..a0a433d Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_visualstudio.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_width.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_width.png new file mode 100644 index 0000000..1eb8809 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_width.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_word.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_word.png new file mode 100644 index 0000000..ae8ecbf Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_word.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_world.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_world.png new file mode 100644 index 0000000..6ed2490 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_world.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_wrench.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_wrench.png new file mode 100644 index 0000000..fecadd0 Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_wrench.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_white_zip.png b/node_modules/express/node_modules/connect/lib/public/icons/page_white_zip.png new file mode 100644 index 0000000..fd4bbcc Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_white_zip.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_word.png b/node_modules/express/node_modules/connect/lib/public/icons/page_word.png new file mode 100644 index 0000000..834cdfa Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_word.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/icons/page_world.png b/node_modules/express/node_modules/connect/lib/public/icons/page_world.png new file mode 100644 index 0000000..b8895dd Binary files /dev/null and b/node_modules/express/node_modules/connect/lib/public/icons/page_world.png differ diff --git a/node_modules/express/node_modules/connect/lib/public/style.css b/node_modules/express/node_modules/connect/lib/public/style.css new file mode 100644 index 0000000..32b6507 --- /dev/null +++ b/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/node_modules/express/node_modules/connect/lib/utils.js b/node_modules/express/node_modules/connect/lib/utils.js new file mode 100644 index 0000000..9839bc3 --- /dev/null +++ b/node_modules/express/node_modules/connect/lib/utils.js @@ -0,0 +1,408 @@ + +/*! + * Connect - utils + * Copyright(c) 2010 Sencha Inc. + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var http = require('http') + , crypto = require('crypto') + , parse = require('url').parse + , sep = require('path').sep + , signature = require('cookie-signature') + , nodeVersion = process.versions.node.split('.'); + +// pause is broken in node < 0.10 +exports.brokenPause = parseInt(nodeVersion[0], 10) === 0 + && parseInt(nodeVersion[1], 10) < 10; + +/** + * Return `true` if the request has a body, otherwise return `false`. + * + * @param {IncomingMessage} req + * @return {Boolean} + * @api private + */ + +exports.hasBody = function(req) { + var encoding = 'transfer-encoding' in req.headers; + var length = 'content-length' in req.headers && req.headers['content-length'] !== '0'; + return encoding || length; +}; + +/** + * Extract the mime type from the given request's + * _Content-Type_ header. + * + * @param {IncomingMessage} req + * @return {String} + * @api private + */ + +exports.mime = function(req) { + var str = req.headers['content-type'] || ''; + return str.split(';')[0]; +}; + +/** + * Generate an `Error` from the given status `code` + * and optional `msg`. + * + * @param {Number} code + * @param {String} msg + * @return {Error} + * @api private + */ + +exports.error = function(code, msg){ + var err = new Error(msg || http.STATUS_CODES[code]); + err.status = code; + return err; +}; + +/** + * 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 private + */ + +exports.md5 = function(str, encoding){ + return crypto + .createHash('md5') + .update(str, 'utf8') + .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 private + */ + +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 private + */ + +exports.escape = function(html){ + return String(html) + .replace(/&(?!\w+;)/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +}; + +/** + * Sign the given `val` with `secret`. + * + * @param {String} val + * @param {String} secret + * @return {String} + * @api private + */ + +exports.sign = function(val, secret){ + console.warn('do not use utils.sign(), use https://github.com/visionmedia/node-cookie-signature') + return val + '.' + crypto + .createHmac('sha256', secret) + .update(val) + .digest('base64') + .replace(/=+$/, ''); +}; + +/** + * Unsign and decode the given `val` with `secret`, + * returning `false` if the signature is invalid. + * + * @param {String} val + * @param {String} secret + * @return {String|Boolean} + * @api private + */ + +exports.unsign = function(val, secret){ + console.warn('do not use utils.unsign(), use https://github.com/visionmedia/node-cookie-signature') + var str = val.slice(0, val.lastIndexOf('.')); + return exports.sign(str, secret) == val + ? str + : false; +}; + +/** + * Parse signed cookies, returning an object + * containing the decoded key/value pairs, + * while removing the signed key from `obj`. + * + * @param {Object} obj + * @return {Object} + * @api private + */ + +exports.parseSignedCookies = function(obj, secret){ + var ret = {}; + Object.keys(obj).forEach(function(key){ + var val = obj[key]; + if (0 == val.indexOf('s:')) { + val = signature.unsign(val.slice(2), secret); + if (val) { + ret[key] = val; + delete obj[key]; + } + } + }); + return ret; +}; + +/** + * Parse a signed cookie string, return the decoded value + * + * @param {String} str signed cookie string + * @param {String} secret + * @return {String} decoded value + * @api private + */ + +exports.parseSignedCookie = function(str, secret){ + return 0 == str.indexOf('s:') + ? signature.unsign(str.slice(2), secret) + : str; +}; + +/** + * Parse JSON cookies. + * + * @param {Object} obj + * @return {Object} + * @api private + */ + +exports.parseJSONCookies = function(obj){ + Object.keys(obj).forEach(function(key){ + var val = obj[key]; + var res = exports.parseJSONCookie(val); + if (res) obj[key] = res; + }); + return obj; +}; + +/** + * Parse JSON cookie string + * + * @param {String} str + * @return {Object} Parsed object or null if not json cookie + * @api private + */ + +exports.parseJSONCookie = function(str) { + if (0 == str.indexOf('j:')) { + try { + return JSON.parse(str.slice(2)); + } catch (err) { + // no op + } + } +}; + +/** + * 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. Pause is only required for + * node versions less than 10, and is replaced with + * noop's otherwise. + * + * var pause = utils.pause(req); + * fs.readFile(path, function(){ + * next(); + * pause.resume(); + * }); + * + * @param {Object} obj + * @return {Object} + * @api private + */ + +exports.pause = exports.brokenPause + ? require('pause') + : function () { + return { + end: noop, + resume: noop + } + } + +/** + * Strip `Content-*` headers from `res`. + * + * @param {ServerResponse} res + * @api private + */ + +exports.removeContentHeaders = function(res){ + if (!res._headers) return; + 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 private + */ + +exports.conditionalGET = function(req) { + return req.headers['if-modified-since'] + || req.headers['if-none-match']; +}; + +/** + * Respond with 401 "Unauthorized". + * + * @param {ServerResponse} res + * @param {String} realm + * @api private + */ + +exports.unauthorized = function(res, realm) { + res.statusCode = 401; + res.setHeader('WWW-Authenticate', 'Basic realm="' + realm + '"'); + res.end('Unauthorized'); +}; + +/** + * Respond with 304 "Not Modified". + * + * @param {ServerResponse} res + * @param {Object} headers + * @api private + */ + +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 private + */ + +exports.etag = function(stat) { + return '"' + stat.size + '-' + Number(stat.mtime) + '"'; +}; + +/** + * Parse the given Cache-Control `str`. + * + * @param {String} str + * @return {Object} + * @api private + */ + +exports.parseCacheControl = function(str){ + var directives = str.split(',') + , obj = {}; + + for(var i = 0, len = directives.length; i < len; i++) { + var parts = directives[i].split('=') + , key = parts.shift().trim() + , val = parseInt(parts.shift(), 10); + + obj[key] = isNaN(val) ? true : val; + } + + return obj; +}; + +/** + * Parse the `req` url with memoization. + * + * @param {ServerRequest} req + * @return {Object} + * @api private + */ + +exports.parseUrl = function(req){ + var parsed = req._parsedUrl; + if (parsed && parsed.href == req.url) { + return parsed; + } else { + parsed = parse(req.url); + + if (parsed.auth && !parsed.protocol && ~parsed.href.indexOf('//')) { + // This parses pathnames, and a strange pathname like //r@e should work + parsed = parse(req.url.replace(/@/g, '%40')); + } + + return req._parsedUrl = parsed; + } +}; + +/** + * Parse byte `size` string. + * + * @param {String} size + * @return {Number} + * @api private + */ + +exports.parseBytes = require('bytes'); + +/** + * Normalizes the path separator from system separator + * to URL separator, aka `/`. + * + * @param {String} path + * @return {String} + * @api private + */ + +exports.normalizeSlashes = function normalizeSlashes(path) { + return path.split(sep).join('/'); +}; + +function noop() {} diff --git a/node_modules/express/node_modules/connect/node_modules/bytes/.npmignore b/node_modules/express/node_modules/connect/node_modules/bytes/.npmignore new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/bytes/.npmignore @@ -0,0 +1 @@ +test diff --git a/node_modules/express/node_modules/connect/node_modules/bytes/History.md b/node_modules/express/node_modules/connect/node_modules/bytes/History.md new file mode 100644 index 0000000..f233ed1 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/bytes/History.md @@ -0,0 +1,15 @@ + +0.2.1 / 2013-04-01 +================== + + * add .component + +0.2.0 / 2012-10-28 +================== + + * bytes(200).should.eql('200b') + +0.1.0 / 2012-07-04 +================== + + * add bytes to string conversion [yields] diff --git a/node_modules/express/node_modules/connect/node_modules/bytes/Makefile b/node_modules/express/node_modules/connect/node_modules/bytes/Makefile new file mode 100644 index 0000000..8e8640f --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/bytes/Makefile @@ -0,0 +1,7 @@ + +test: + @./node_modules/.bin/mocha \ + --reporter spec \ + --require should + +.PHONY: test \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/bytes/Readme.md b/node_modules/express/node_modules/connect/node_modules/bytes/Readme.md new file mode 100644 index 0000000..9325d5b --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/bytes/Readme.md @@ -0,0 +1,51 @@ +# node-bytes + + Byte string parser / formatter. + +## Example: + +```js +bytes('1kb') +// => 1024 + +bytes('2mb') +// => 2097152 + +bytes('1gb') +// => 1073741824 + +bytes(1073741824) +// => 1gb +``` + +## Installation + +``` +$ npm install bytes +$ component install visionmedia/bytes.js +``` + +## License + +(The MIT License) + +Copyright (c) 2012 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/node_modules/express/node_modules/connect/node_modules/bytes/component.json b/node_modules/express/node_modules/connect/node_modules/bytes/component.json new file mode 100644 index 0000000..2929c25 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/bytes/component.json @@ -0,0 +1,7 @@ +{ + "name": "bytes", + "description": "byte size string parser / serializer", + "keywords": ["bytes", "utility"], + "version": "0.2.1", + "scripts": ["index.js"] +} diff --git a/node_modules/express/node_modules/connect/node_modules/bytes/index.js b/node_modules/express/node_modules/connect/node_modules/bytes/index.js new file mode 100644 index 0000000..70b2e01 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/bytes/index.js @@ -0,0 +1,39 @@ + +/** + * Parse byte `size` string. + * + * @param {String} size + * @return {Number} + * @api public + */ + +module.exports = function(size) { + if ('number' == typeof size) return convert(size); + var parts = size.match(/^(\d+(?:\.\d+)?) *(kb|mb|gb)$/) + , n = parseFloat(parts[1]) + , type = parts[2]; + + var map = { + kb: 1 << 10 + , mb: 1 << 20 + , gb: 1 << 30 + }; + + return map[type] * n; +}; + +/** + * convert bytes into string. + * + * @param {Number} b - bytes to convert + * @return {String} + * @api public + */ + +function convert (b) { + var gb = 1 << 30, mb = 1 << 20, kb = 1 << 10; + if (b >= gb) return (Math.round(b / gb * 100) / 100) + 'gb'; + if (b >= mb) return (Math.round(b / mb * 100) / 100) + 'mb'; + if (b >= kb) return (Math.round(b / kb * 100) / 100) + 'kb'; + return b + 'b'; +} diff --git a/node_modules/express/node_modules/connect/node_modules/bytes/package.json b/node_modules/express/node_modules/connect/node_modules/bytes/package.json new file mode 100644 index 0000000..601b110 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/bytes/package.json @@ -0,0 +1,29 @@ +{ + "name": "bytes", + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca", + "url": "http://tjholowaychuk.com" + }, + "description": "byte size string parser / serializer", + "version": "0.2.1", + "main": "index.js", + "dependencies": {}, + "devDependencies": { + "mocha": "*", + "should": "*" + }, + "component": { + "scripts": { + "bytes/index.js": "index.js" + } + }, + "readme": "# node-bytes\n\n Byte string parser / formatter.\n\n## Example:\n\n```js\nbytes('1kb')\n// => 1024\n\nbytes('2mb')\n// => 2097152\n\nbytes('1gb')\n// => 1073741824\n\nbytes(1073741824)\n// => 1gb\n```\n\n## Installation\n\n```\n$ npm install bytes\n$ component install visionmedia/bytes.js\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "_id": "bytes@0.2.1", + "dist": { + "shasum": "586572818c283774f959f5c5762ece7bdf522f03" + }, + "_from": "bytes@0.2.1", + "_resolved": "https://registry.npmjs.org/bytes/-/bytes-0.2.1.tgz" +} diff --git a/node_modules/express/node_modules/connect/node_modules/methods/index.js b/node_modules/express/node_modules/connect/node_modules/methods/index.js new file mode 100644 index 0000000..297d022 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/methods/index.js @@ -0,0 +1,26 @@ + +module.exports = [ + 'get' + , 'post' + , 'put' + , 'head' + , 'delete' + , 'options' + , 'trace' + , 'copy' + , 'lock' + , 'mkcol' + , 'move' + , 'propfind' + , 'proppatch' + , 'unlock' + , 'report' + , 'mkactivity' + , 'checkout' + , 'merge' + , 'm-search' + , 'notify' + , 'subscribe' + , 'unsubscribe' + , 'patch' +]; \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/methods/package.json b/node_modules/express/node_modules/connect/node_modules/methods/package.json new file mode 100644 index 0000000..1c15a33 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/methods/package.json @@ -0,0 +1,24 @@ +{ + "name": "methods", + "version": "0.0.1", + "description": "HTTP methods that node supports", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "http", + "methods" + ], + "author": { + "name": "TJ Holowaychuk" + }, + "license": "MIT", + "readme": "ERROR: No README data found!", + "_id": "methods@0.0.1", + "dist": { + "shasum": "277c90f8bef39709645a8371c51c3b6c648e068c" + }, + "_from": "methods@0.0.1", + "_resolved": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz" +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/.jshintrc b/node_modules/express/node_modules/connect/node_modules/multiparty/.jshintrc new file mode 100644 index 0000000..a93b50c --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/.jshintrc @@ -0,0 +1,70 @@ +{ + // Settings + "passfail" : false, // Stop on first error. + "maxerr" : 100, // Maximum errors before stopping. + + + // Predefined globals whom JSHint will ignore. + "browser" : false, // Standard browser globals e.g. `window`, `document`. + + "node" : true, + "rhino" : false, + "couch" : false, + "wsh" : false, // Windows Scripting Host. + + "jquery" : false, + "prototypejs" : false, + "mootools" : false, + "dojo" : false, + + + "predef" : [ + "describe", "it", "before", "after" + ], + + // Development. + "debug" : true, // Allow debugger statements e.g. browser breakpoints. + "devel" : true, // Allow development statements e.g. `console.log();`. + + + // EcmaScript 5. + "es5" : true, // Allow EcmaScript 5 syntax. + "strict" : false, // Require `use strict` pragma in every file. + "globalstrict" : true, // Allow global "use strict" (also enables 'strict'). + + + // The Good Parts. + "asi" : true, // Tolerate Automatic Semicolon Insertion (no semicolons). + "laxbreak" : false, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons. + "laxcomma" : true, + "bitwise" : false, // Prohibit bitwise operators (&, |, ^, etc.). + "boss" : true, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments. + "curly" : false, // Require {} for every new block or scope. + "eqeqeq" : true, // Require triple equals i.e. `===`. + "eqnull" : true, // Tolerate use of `== null`. + "evil" : false, // Tolerate use of `eval`. + "expr" : false, // Tolerate `ExpressionStatement` as Programs. + "forin" : false, // Prohibt `for in` loops without `hasOwnProperty`. + "immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` + "latedef" : false, // Prohibit variable use before definition. + "loopfunc" : false, // Allow functions to be defined within loops. + "noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`. + "regexp" : false, // Prohibit `.` and `[^...]` in regular expressions. + "regexdash" : false, // Tolerate unescaped last dash i.e. `[-...]`. + "scripturl" : false, // Tolerate script-targeted URLs. + "shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`. + "supernew" : false, // Tolerate `new function () { ... };` and `new Object;`. + "undef" : true, // Require all non-global variables be declared before they are used. + + + // Persone styling prefrences. + "newcap" : true, // Require capitalization of all constructor functions e.g. `new F()`. + "noempty" : true, // Prohibit use of empty blocks. + "nonew" : true, // Prohibit use of constructors for side-effects. + "nomen" : false, // Prohibit use of initial or trailing underbars in names. + "onevar" : false, // Allow only one `var` statement per function. + "plusplus" : false, // Prohibit use of `++` & `--`. + "sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`. + "trailing" : true, // Prohibit trailing whitespaces. + "white" : false // Check against strict whitespace and indentation rules. +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/.npmignore b/node_modules/express/node_modules/connect/node_modules/multiparty/.npmignore new file mode 100644 index 0000000..07e6e47 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/.npmignore @@ -0,0 +1 @@ +/node_modules diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/.travis.yml b/node_modules/express/node_modules/connect/node_modules/multiparty/.travis.yml new file mode 100644 index 0000000..b1fc4b0 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/.travis.yml @@ -0,0 +1,6 @@ +language: node_js +node_js: + - "0.8" + - "0.10" +before_script: + - ulimit -n 500 diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/CHANGELOG.md b/node_modules/express/node_modules/connect/node_modules/multiparty/CHANGELOG.md new file mode 100644 index 0000000..ea54d9a --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/CHANGELOG.md @@ -0,0 +1,191 @@ +### 2.2.0 + + * additional callback API to support multiple files with same field name + * fix assertion crash when max field count is exceeded + * fix assertion crash when client aborts an invalid request + * (>=v0.10 only) unpipe the request when an error occurs to save resources. + * update readable-stream to ~1.1.9 + * fix assertion crash when EMFILE occurrs + * (no more assertions - only 'error' events) + +### 2.1.9 + + * relax content-type detection regex. (thanks amitaibu) + +### 2.1.8 + + * replace deprecated Buffer.write(). (thanks hueniverse) + +### 2.1.7 + + * add repository field to package.json + +### 2.1.6 + + * expose `hash` as an option to `Form`. (thanks wookiehangover) + +### 2.1.5 + + * fix possible 'close' event before all temp files are done + +### 2.1.4 + + * fix crash for invalid requests + +### 2.1.3 + + * add `file.size` + +### 2.1.2 + + * proper backpressure support + * update s3 example + +### 2.1.1 + + * fix uploads larger than 2KB + * fix both s3 and upload example + * add part.byteCount and part.byteOffset + +### 2.1.0 (recalled) + + * Complete rewrite. See README for changes and new API. + +### v1.0.13 + +* Only update hash if update method exists (Sven Lito) +* According to travis v0.10 needs to go quoted (Sven Lito) +* Bumping build node versions (Sven Lito) +* Additional fix for empty requests (Eugene Girshov) +* Change the default to 1000, to match the new Node behaviour. (OrangeDog) +* Add ability to control maxKeys in the querystring parser. (OrangeDog) +* Adjust test case to work with node 0.9.x (Eugene Girshov) +* Update package.json (Sven Lito) +* Path adjustment according to eb4468b (Markus Ast) + +### v1.0.12 + +* Emit error on aborted connections (Eugene Girshov) +* Add support for empty requests (Eugene Girshov) +* Fix name/filename handling in Content-Disposition (jesperp) +* Tolerate malformed closing boundary in multipart (Eugene Girshov) +* Ignore preamble in multipart messages (Eugene Girshov) +* Add support for application/json (Mike Frey, Carlos Rodriguez) +* Add support for Base64 encoding (Elmer Bulthuis) +* Add File#toJSON (TJ Holowaychuk) +* Remove support for Node.js 0.4 & 0.6 (Andrew Kelley) +* Documentation improvements (Sven Lito, Andre Azevedo) +* Add support for application/octet-stream (Ion Lupascu, Chris Scribner) +* Use os.tmpDir() to get tmp directory (Andrew Kelley) +* Improve package.json (Andrew Kelley, Sven Lito) +* Fix benchmark script (Andrew Kelley) +* Fix scope issue in incoming_forms (Sven Lito) +* Fix file handle leak on error (OrangeDog) + +### v1.0.11 + +* Calculate checksums for incoming files (sreuter) +* Add definition parameters to "IncomingForm" as an argument (Math-) + +### v1.0.10 + +* Make parts to be proper Streams (Matt Robenolt) + +### v1.0.9 + +* Emit progress when content length header parsed (Tim Koschützki) +* Fix Readme syntax due to GitHub changes (goob) +* Replace references to old 'sys' module in Readme with 'util' (Peter Sugihara) + +### v1.0.8 + +* Strip potentially unsafe characters when using `keepExtensions: true`. +* Switch to utest / urun for testing +* Add travis build + +### v1.0.7 + +* Remove file from package that was causing problems when installing on windows. (#102) +* Fix typos in Readme (Jason Davies). + +### v1.0.6 + +* Do not default to the default to the field name for file uploads where + filename="". + +### v1.0.5 + +* Support filename="" in multipart parts +* Explain unexpected end() errors in parser better + +**Note:** Starting with this version, formidable emits 'file' events for empty +file input fields. Previously those were incorrectly emitted as regular file +input fields with value = "". + +### v1.0.4 + +* Detect a good default tmp directory regardless of platform. (#88) + +### v1.0.3 + +* Fix problems with utf8 characters (#84) / semicolons in filenames (#58) +* Small performance improvements +* New test suite and fixture system + +### v1.0.2 + +* Exclude node\_modules folder from git +* Implement new `'aborted'` event +* Fix files in example folder to work with recent node versions +* Make gently a devDependency + +[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.1...v1.0.2) + +### v1.0.1 + +* Fix package.json to refer to proper main directory. (#68, Dean Landolt) + +[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.0...v1.0.1) + +### v1.0.0 + +* Add support for multipart boundaries that are quoted strings. (Jeff Craig) + +This marks the beginning of development on version 2.0 which will include +several architectural improvements. + +[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.11...v1.0.0) + +### v0.9.11 + +* Emit `'progress'` event when receiving data, regardless of parsing it. (Tim Koschützki) +* Use [W3C FileAPI Draft](http://dev.w3.org/2006/webapi/FileAPI/) properties for File class + +**Important:** The old property names of the File class will be removed in a +future release. + +[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.10...v0.9.11) + +### Older releases + +These releases were done before starting to maintain the above Changelog: + +* [v0.9.10](https://github.com/felixge/node-formidable/compare/v0.9.9...v0.9.10) +* [v0.9.9](https://github.com/felixge/node-formidable/compare/v0.9.8...v0.9.9) +* [v0.9.8](https://github.com/felixge/node-formidable/compare/v0.9.7...v0.9.8) +* [v0.9.7](https://github.com/felixge/node-formidable/compare/v0.9.6...v0.9.7) +* [v0.9.6](https://github.com/felixge/node-formidable/compare/v0.9.5...v0.9.6) +* [v0.9.5](https://github.com/felixge/node-formidable/compare/v0.9.4...v0.9.5) +* [v0.9.4](https://github.com/felixge/node-formidable/compare/v0.9.3...v0.9.4) +* [v0.9.3](https://github.com/felixge/node-formidable/compare/v0.9.2...v0.9.3) +* [v0.9.2](https://github.com/felixge/node-formidable/compare/v0.9.1...v0.9.2) +* [v0.9.1](https://github.com/felixge/node-formidable/compare/v0.9.0...v0.9.1) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0) +* [v0.1.0](https://github.com/felixge/node-formidable/commits/v0.1.0) diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/LICENSE b/node_modules/express/node_modules/connect/node_modules/multiparty/LICENSE new file mode 100644 index 0000000..8488a40 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/LICENSE @@ -0,0 +1,7 @@ +Copyright (C) 2011-2013 Felix Geisendörfer, Andrew Kelley + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/README.md b/node_modules/express/node_modules/connect/node_modules/multiparty/README.md new file mode 100644 index 0000000..f149ac0 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/README.md @@ -0,0 +1,177 @@ +[![Build Status](https://travis-ci.org/superjoe30/node-multiparty.png?branch=master)](https://travis-ci.org/superjoe30/node-multiparty) +# multiparty + +Parse http requests with content-type `multipart/form-data`, also known as file uploads. + +See also [busboy](https://github.com/mscdex/busboy) - a +[faster](https://github.com/mscdex/dicer/wiki/Benchmarks) alternative +which may be worth looking into. + +### Why the fork? + + * This module uses the Node.js v0.10 streams properly, *even in Node.js v0.8* + * It will not create a temp file for you unless you want it to. + * Counts bytes and does math to help you figure out the `Content-Length` of + each part. + * You can easily stream uploads to s3 with + [knox](https://github.com/LearnBoost/knox), for [example](examples/s3.js). + * Less bugs. This code is simpler, has all deprecated functionality removed, + has cleaner tests, and does not try to do anything beyond multipart stream + parsing. + +## Installation + +``` +npm install multiparty +``` + +## Usage + + * See [examples](examples). + +Parse an incoming `multipart/form-data` request. + +```js +var multiparty = require('multiparty') + , http = require('http') + , util = require('util') + +http.createServer(function(req, res) { + if (req.url === '/upload' && req.method === 'POST') { + // parse a file upload + var form = new multiparty.Form(); + + form.parse(req, function(err, fields, files) { + res.writeHead(200, {'content-type': 'text/plain'}); + res.write('received upload:\n\n'); + res.end(util.inspect({fields: fields, files: files})); + }); + + return; + } + + // show a file upload form + res.writeHead(200, {'content-type': 'text/html'}); + res.end( + '
    '+ + '
    '+ + '
    '+ + ''+ + '
    ' + ); +}).listen(8080); +``` + +## API + +### multiparty.Form +```js +var form = new multiparty.Form(options) +``` +Creates a new form. Options: + + * `encoding` - sets encoding for the incoming form fields. Defaults to `utf8`. + * `maxFieldSize` - Limits the amount of memory a field (not a file) can + allocate in bytes. If this value is exceeded, an `error` event is emitted. + The default size is 2MB. + * `maxFields` - Limits the number of fields that will be parsed before + emitting an `error` event. A file counts as a field in this case. + Defaults to 1000. + * `autoFields` - Enables `field` events. This is automatically set to `true` + if you add a `field` listener. + * `autoFiles` - Enables `file` events. This is automatically set to `true` + if you add a `file` listener. + * `uploadDir` - Only relevant when `autoFiles` is `true`. The directory for + placing file uploads in. You can move them later using `fs.rename()`. + Defaults to `os.tmpDir()`. + * `hash` - Only relevant when `autoFiles` is `true`. If you want checksums + calculated for incoming files, set this to either `sha1` or `md5`. + Defaults to off. + +#### form.parse(request, [cb]) + +Parses an incoming node.js `request` containing form data. If `cb` is +provided, `autoFields` and `autoFiles` are set to `true` and all fields and +files are collected and passed to the callback: + +```js +form.parse(req, function(err, fieldsObject, filesObject, fieldsList, filesList) { + // ... +}); +``` + +It is often convenient to access a field or file by name. In this situation, +use `fieldsObject` or `filesObject`. However sometimes, as in the case of a +`` the multipart stream will contain +multiple files of the same input name, and you are interested in all of them. +In this case, use `filesList`. + +Another example is when you do not care what the field name of a file is; you +are merely interested in a single upload. In this case, set `maxFields` to 1 +(assuming no other fields expected besides the file) and use `filesList[0]`. + +#### form.bytesReceived + +The amount of bytes received for this form so far. + +#### form.bytesExpected + +The expected number of bytes in this form. + +### Events + +#### 'error' (err) + +You definitely want to handle this event. If not your server *will* crash when +users submit bogus multipart requests! + +#### 'part' (part) + +Emitted when a part is encountered in the request. `part` is a +`ReadableStream`. It also has the following properties: + + * `headers` - the headers for this part. For example, you may be interested + in `content-type`. + * `name` - the field name for this part + * `filename` - only if the part is an incoming file + * `byteOffset` - the byte offset of this part in the request body + * `byteCount` - assuming that this is the last part in the request, + this is the size of this part in bytes. You could use this, for + example, to set the `Content-Length` header if uploading to S3. + If the part had a `Content-Length` header then that value is used + here instead. + +#### 'aborted' + +Emitted when the request is aborted. This event will be followed shortly +by an `error` event. In practice you do not need to handle this event. + +#### 'progress' (bytesReceived, bytesExpected) + +#### 'close' + +Emitted after all parts have been parsed and emitted. Not emitted if an `error` +event is emitted. This is typically when you would send your response. + +#### 'file' (name, file) + +**By default multiparty will not touch your hard drive.** But if you add this +listener, multiparty automatically sets `form.autoFiles` to `true` and will +stream uploads to disk for you. + + * `name` - the field name for this file + * `file` - an object with these properties: + - `fieldName` - same as `name` - the field name for this file + - `originalFilename` - the filename that the user reports for the file + - `path` - the absolute path of the uploaded file on disk + - `headers` - the HTTP headers that were sent along with this file + - `size` - size of the file in bytes + +If you set the `form.hash` option, then `file` will also contain a `hash` +property which is the checksum of the file. + +#### 'field' (name, value) + + * `name` - field name + * `value` - string field value + diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/examples/azureblobstorage.js b/node_modules/express/node_modules/connect/node_modules/multiparty/examples/azureblobstorage.js new file mode 100644 index 0000000..273c332 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/examples/azureblobstorage.js @@ -0,0 +1,41 @@ +var http = require('http') + , util = require('util') + , multiparty = require('../') + , azure = require('azure') + , PORT = process.env.PORT || 27372 + +var server = http.createServer(function(req, res) { + if (req.url === '/') { + res.writeHead(200, {'content-type': 'text/html'}); + res.end( + '
    '+ + '
    '+ + '
    '+ + ''+ + '
    ' + ); + } else if (req.url === '/upload') { + + var blobService = azure.createBlobService(); + var form = new multiparty.Form(); + form.on('part', function(part) { + if (!part.filename) return; + + var size = part.byteCount - part.byteOffset; + var name = part.filename; + var container = 'blobContainerName'; + + blobService.createBlockBlobFromStream(container, name, part, size, function(error) { + if (error) { + // error handling + } + }); + }); + form.parse(req); + + res.send('File uploaded successfully'); + } +}); +server.listen(PORT, function() { + console.info('listening on http://0.0.0.0:'+PORT+'/'); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/examples/s3.js b/node_modules/express/node_modules/connect/node_modules/multiparty/examples/s3.js new file mode 100644 index 0000000..60617ba --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/examples/s3.js @@ -0,0 +1,74 @@ +var http = require('http') + , util = require('util') + , multiparty = require('../') + , knox = require('knox') + , Batch = require('batch') + , PORT = process.env.PORT || 27372 + +var s3Client = knox.createClient({ + secure: false, + key: process.env.S3_KEY, + secret: process.env.S3_SECRET, + bucket: process.env.S3_BUCKET, +}); + +var server = http.createServer(function(req, res) { + if (req.url === '/') { + res.writeHead(200, {'content-type': 'text/html'}); + res.end( + '
    '+ + '
    '+ + '
    '+ + ''+ + '
    ' + ); + } else if (req.url === '/upload') { + var headers = { + 'x-amz-acl': 'public-read', + }; + var form = new multiparty.Form(); + var batch = new Batch(); + batch.push(function(cb) { + form.on('field', function(name, value) { + if (name === 'path') { + var destPath = value; + if (destPath[0] !== '/') destPath = '/' + destPath; + cb(null, destPath); + } + }); + }); + batch.push(function(cb) { + form.on('part', function(part) { + if (! part.filename) return; + cb(null, part); + }); + }); + batch.end(function(err, results) { + if (err) throw err; + form.removeListener('close', onEnd); + var destPath = results[0] + , part = results[1]; + + headers['Content-Length'] = part.byteCount; + s3Client.putStream(part, destPath, headers, function(err, s3Response) { + if (err) throw err; + res.statusCode = s3Response.statusCode; + s3Response.pipe(res); + console.log("https://s3.amazonaws.com/" + process.env.S3_BUCKET + destPath); + }); + }); + form.on('close', onEnd); + form.parse(req); + + } else { + res.writeHead(404, {'content-type': 'text/plain'}); + res.end('404'); + } + + function onEnd() { + throw new Error("no uploaded file"); + } +}); +server.listen(PORT, function() { + console.info('listening on http://0.0.0.0:'+PORT+'/'); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/examples/upload.js b/node_modules/express/node_modules/connect/node_modules/multiparty/examples/upload.js new file mode 100644 index 0000000..5dd3926 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/examples/upload.js @@ -0,0 +1,37 @@ +var http = require('http') + , util = require('util') + , multiparty = require('../') + , PORT = process.env.PORT || 27372 + +var server = http.createServer(function(req, res) { + if (req.url === '/') { + res.writeHead(200, {'content-type': 'text/html'}); + res.end( + '
    '+ + '
    '+ + '
    '+ + ''+ + '
    ' + ); + } else if (req.url === '/upload') { + var form = new multiparty.Form(); + + form.parse(req, function(err, fields, files) { + if (err) { + res.writeHead(400, {'content-type': 'text/plain'}); + res.end("invalid request: " + err.message); + return; + } + res.writeHead(200, {'content-type': 'text/plain'}); + res.write('received fields:\n\n '+util.inspect(fields)); + res.write('\n\n'); + res.end('received files:\n\n '+util.inspect(files)); + }); + } else { + res.writeHead(404, {'content-type': 'text/plain'}); + res.end('404'); + } +}); +server.listen(PORT, function() { + console.info('listening on http://0.0.0.0:'+PORT+'/'); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/index.js b/node_modules/express/node_modules/connect/node_modules/multiparty/index.js new file mode 100755 index 0000000..71c88ae --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/index.js @@ -0,0 +1,618 @@ +exports.Form = Form; + +var stream = require('readable-stream') + , util = require('util') + , fs = require('fs') + , crypto = require('crypto') + , path = require('path') + , os = require('os') + , StringDecoder = require('string_decoder').StringDecoder + , StreamCounter = require('stream-counter') + +var START = 0 + , START_BOUNDARY = 1 + , HEADER_FIELD_START = 2 + , HEADER_FIELD = 3 + , HEADER_VALUE_START = 4 + , HEADER_VALUE = 5 + , HEADER_VALUE_ALMOST_DONE = 6 + , HEADERS_ALMOST_DONE = 7 + , PART_DATA_START = 8 + , PART_DATA = 9 + , PART_END = 10 + , END = 11 + + , LF = 10 + , CR = 13 + , SPACE = 32 + , HYPHEN = 45 + , COLON = 58 + , A = 97 + , Z = 122 + +var CONTENT_TYPE_RE = /^multipart\/(form-data|related);\s*boundary=(?:"([^"]+)"|([^;]+))$/i; +var FILE_EXT_RE = /(\.[_\-a-zA-Z0-9]{0,16}).*/; +var LAST_BOUNDARY_SUFFIX_LEN = 4; // --\r\n + +util.inherits(Form, stream.Writable); +function Form(options) { + var self = this; + stream.Writable.call(self); + + options = options || {}; + + self.error = null; + self.finished = false; + + self.autoFields = !!options.autoFields; + self.autoFiles = !!options.autoFields; + + self.maxFields = options.maxFields || 1000; + self.maxFieldsSize = options.maxFieldsSize || 2 * 1024 * 1024; + self.uploadDir = options.uploadDir || os.tmpDir(); + self.encoding = options.encoding || 'utf8'; + self.hash = options.hash || false; + + self.bytesReceived = 0; + self.bytesExpected = null; + + self.openedFiles = []; + self.totalFieldSize = 0; + self.totalFieldCount = 0; + self.flushing = 0; + + self.backpressure = false; + self.writeCbs = []; + + if (options.boundary) setUpParser(self, options.boundary); + + self.on('newListener', function(eventName) { + if (eventName === 'file') { + self.autoFiles = true; + } else if (eventName === 'field') { + self.autoFields = true; + } + }); +} + +Form.prototype.parse = function(req, cb) { + var self = this; + + // if the user supplies a callback, this implies autoFields and autoFiles + if (cb) { + self.autoFields = true; + self.autoFiles = true; + } + + self.handleError = handleError; + self.bytesExpected = getBytesExpected(req.headers); + + req.on('error', handleError); + req.on('aborted', onReqAborted); + + var contentType = req.headers['content-type']; + if (!contentType) { + handleError(new Error('missing content-type header')); + return; + } + + var m = contentType.match(CONTENT_TYPE_RE); + if (!m) { + handleError(new Error('unrecognized content-type: ' + contentType)); + return; + } + var boundary = m[2] || m[3]; + setUpParser(self, boundary); + req.pipe(self); + + if (cb) { + var fieldsTable = {}; + var filesTable = {}; + var fieldsList = []; + var filesList = []; + self.on('error', function(err) { + cb(err); + }); + self.on('field', function(name, value) { + fieldsTable[name] = value; + fieldsList.push({name: name, value: value}); + }); + self.on('file', function(name, file) { + filesTable[name] = file; + filesList.push(file); + }); + self.on('close', function() { + cb(null, fieldsTable, filesTable, fieldsList, filesList); + }); + } + + function onReqAborted() { + self.emit('aborted'); + handleError(new Error("Request aborted")); + } + + function handleError(err) { + var first = !self.error; + if (first) { + self.error = err; + req.removeListener('aborted', onReqAborted); + + // welp. 0.8 doesn't support unpipe, too bad so sad. + // let's drop support for 0.8 soon. + if (req.unpipe) { + req.unpipe(self); + } + } + + self.openedFiles.forEach(function(file) { + file.ws.destroy(); + fs.unlink(file.path, function(err) { + // this is already an error condition, ignore 2nd error + }); + }); + self.openedFiles = []; + + if (first) { + self.emit('error', err); + } + } + +}; + +Form.prototype._write = function(buffer, encoding, cb) { + var self = this + , i = 0 + , len = buffer.length + , prevIndex = self.index + , index = self.index + , state = self.state + , lookbehind = self.lookbehind + , boundary = self.boundary + , boundaryChars = self.boundaryChars + , boundaryLength = self.boundary.length + , boundaryEnd = boundaryLength - 1 + , bufferLength = buffer.length + , c + , cl + + for (i = 0; i < len; i++) { + c = buffer[i]; + switch (state) { + case START: + index = 0; + state = START_BOUNDARY; + /* falls through */ + case START_BOUNDARY: + if (index === boundaryLength - 2) { + if (c !== CR) return self.handleError(new Error("Expected CR Received " + c)); + index++; + break; + } else if (index === boundaryLength - 1) { + if (c !== LF) return self.handleError(new Error("Expected LF Received " + c)); + index = 0; + self.onParsePartBegin(); + state = HEADER_FIELD_START; + break; + } + + if (c !== boundary[index+2]) index = -2; + if (c === boundary[index+2]) index++; + break; + case HEADER_FIELD_START: + state = HEADER_FIELD; + self.headerFieldMark = i; + index = 0; + /* falls through */ + case HEADER_FIELD: + if (c === CR) { + self.headerFieldMark = null; + state = HEADERS_ALMOST_DONE; + break; + } + + index++; + if (c === HYPHEN) break; + + if (c === COLON) { + if (index === 1) { + // empty header field + self.handleError(new Error("Empty header field")); + return; + } + self.onParseHeaderField(buffer.slice(self.headerFieldMark, i)); + self.headerFieldMark = null; + state = HEADER_VALUE_START; + break; + } + + cl = lower(c); + if (cl < A || cl > Z) { + self.handleError(new Error("Expected alphabetic character, received " + c)); + return; + } + break; + case HEADER_VALUE_START: + if (c === SPACE) break; + + self.headerValueMark = i; + state = HEADER_VALUE; + /* falls through */ + case HEADER_VALUE: + if (c === CR) { + self.onParseHeaderValue(buffer.slice(self.headerValueMark, i)); + self.headerValueMark = null; + self.onParseHeaderEnd(); + state = HEADER_VALUE_ALMOST_DONE; + } + break; + case HEADER_VALUE_ALMOST_DONE: + if (c !== LF) return self.handleError(new Error("Expected LF Received " + c)); + state = HEADER_FIELD_START; + break; + case HEADERS_ALMOST_DONE: + if (c !== LF) return self.handleError(new Error("Expected LF Received " + c)); + var err = self.onParseHeadersEnd(i + 1); + if (err) return self.handleError(err); + state = PART_DATA_START; + break; + case PART_DATA_START: + state = PART_DATA; + self.partDataMark = i; + /* falls through */ + case PART_DATA: + prevIndex = index; + + if (index === 0) { + // boyer-moore derrived algorithm to safely skip non-boundary data + i += boundaryEnd; + while (i < bufferLength && !(buffer[i] in boundaryChars)) { + i += boundaryLength; + } + i -= boundaryEnd; + c = buffer[i]; + } + + if (index < boundaryLength) { + if (boundary[index] === c) { + if (index === 0) { + self.onParsePartData(buffer.slice(self.partDataMark, i)); + self.partDataMark = null; + } + index++; + } else { + index = 0; + } + } else if (index === boundaryLength) { + index++; + if (c === CR) { + // CR = part boundary + self.partBoundaryFlag = true; + } else if (c === HYPHEN) { + // HYPHEN = end boundary + self.lastBoundaryFlag = true; + } else { + index = 0; + } + } else if (index - 1 === boundaryLength) { + if (self.partBoundaryFlag) { + index = 0; + if (c === LF) { + self.partBoundaryFlag = false; + self.onParsePartEnd(); + self.onParsePartBegin(); + state = HEADER_FIELD_START; + break; + } + } else if (self.lastBoundaryFlag) { + if (c === HYPHEN) { + self.onParsePartEnd(); + self.end(); + state = END; + } else { + index = 0; + } + } else { + index = 0; + } + } + + if (index > 0) { + // when matching a possible boundary, keep a lookbehind reference + // in case it turns out to be a false lead + lookbehind[index-1] = c; + } else if (prevIndex > 0) { + // if our boundary turned out to be rubbish, the captured lookbehind + // belongs to partData + self.onParsePartData(lookbehind.slice(0, prevIndex)); + prevIndex = 0; + self.partDataMark = i; + + // reconsider the current character even so it interrupted the sequence + // it could be the beginning of a new sequence + i--; + } + + break; + case END: + break; + default: + self.handleError(new Error("Parser has invalid state.")); + return; + } + } + + if (self.headerFieldMark != null) { + self.onParseHeaderField(buffer.slice(self.headerFieldMark)); + self.headerFieldMark = 0; + } + if (self.headerValueMark != null) { + self.onParseHeaderValue(buffer.slice(self.headerValueMark)); + self.headerValueMark = 0; + } + if (self.partDataMark != null) { + self.onParsePartData(buffer.slice(self.partDataMark)); + self.partDataMark = 0; + } + + self.index = index; + self.state = state; + + self.bytesReceived += buffer.length; + self.emit('progress', self.bytesReceived, self.bytesExpected); + + if (self.backpressure) { + self.writeCbs.push(cb); + } else { + cb(); + } +}; + +Form.prototype.onParsePartBegin = function() { + clearPartVars(this); +} + +Form.prototype.onParseHeaderField = function(b) { + this.headerField += this.headerFieldDecoder.write(b); +} + +Form.prototype.onParseHeaderValue = function(b) { + this.headerValue += this.headerValueDecoder.write(b); +} + +Form.prototype.onParseHeaderEnd = function() { + this.headerField = this.headerField.toLowerCase(); + this.partHeaders[this.headerField] = this.headerValue; + + var m; + if (this.headerField === 'content-disposition') { + if (m = this.headerValue.match(/\bname="([^"]+)"/i)) { + this.partName = m[1]; + } + this.partFilename = parseFilename(this.headerValue); + } else if (this.headerField === 'content-transfer-encoding') { + this.partTransferEncoding = this.headerValue.toLowerCase(); + } + + this.headerFieldDecoder = new StringDecoder(this.encoding); + this.headerField = ''; + this.headerValueDecoder = new StringDecoder(this.encoding); + this.headerValue = ''; +} + +Form.prototype.onParsePartData = function(b) { + if (this.partTransferEncoding === 'base64') { + this.backpressure = ! this.destStream.write(b.toString('ascii'), 'base64'); + } else { + this.backpressure = ! this.destStream.write(b); + } +} + +Form.prototype.onParsePartEnd = function() { + if (this.destStream) { + flushWriteCbs(this); + var s = this.destStream; + process.nextTick(function() { + s.end(); + }); + } + clearPartVars(this); +} + +Form.prototype.onParseHeadersEnd = function(offset) { + var self = this; + switch(self.partTransferEncoding){ + case 'binary': + case '7bit': + case '8bit': + self.partTransferEncoding = 'binary'; + break; + + case 'base64': break; + default: + return new Error("unknown transfer-encoding: " + self.partTransferEncoding); + } + + self.totalFieldCount += 1; + if (self.totalFieldCount >= self.maxFields) { + return new Error("maxFields " + self.maxFields + " exceeded."); + } + + self.destStream = new stream.PassThrough(); + self.destStream.on('drain', function() { + flushWriteCbs(self); + }); + self.destStream.headers = self.partHeaders; + self.destStream.name = self.partName; + self.destStream.filename = self.partFilename; + self.destStream.byteOffset = self.bytesReceived + offset; + var partContentLength = self.destStream.headers['content-length']; + self.destStream.byteCount = partContentLength ? + parseInt(partContentLength, 10) : + (self.bytesExpected - self.destStream.byteOffset - + self.boundary.length - LAST_BOUNDARY_SUFFIX_LEN); + + self.emit('part', self.destStream); + if (self.destStream.filename == null && self.autoFields) { + handleField(self, self.destStream); + } else if (self.destStream.filename != null && self.autoFiles) { + handleFile(self, self.destStream); + } +} + +function flushWriteCbs(self) { + self.writeCbs.forEach(function(cb) { + process.nextTick(cb); + }); + self.writeCbs = []; + self.backpressure = false; +} + +function getBytesExpected(headers) { + var contentLength = headers['content-length']; + if (contentLength) { + return parseInt(contentLength, 10); + } else if (headers['transfer-encoding'] == null) { + return 0; + } else { + return null; + } +} + +function beginFlush(self) { + self.flushing += 1; +} + +function endFlush(self) { + self.flushing -= 1; + maybeClose(self); +} + +function maybeClose(self) { + if (!self.flushing && self.finished && !self.error) { + self.emit('close'); + } +} + +function handleFile(self, fileStream) { + beginFlush(self); + var file = { + fieldName: fileStream.name, + originalFilename: fileStream.filename, + path: uploadPath(self.uploadDir, fileStream.filename), + headers: fileStream.headers, + }; + file.ws = fs.createWriteStream(file.path); + self.openedFiles.push(file); + fileStream.pipe(file.ws); + var counter = new StreamCounter(); + fileStream.pipe(counter); + var hashWorkaroundStream + , hash = null; + if (self.hash) { + // workaround stream because https://github.com/joyent/node/issues/5216 + hashWorkaroundStream = stream.Writable(); + hash = crypto.createHash(self.hash); + hashWorkaroundStream._write = function(buffer, encoding, callback) { + hash.update(buffer); + callback(); + }; + fileStream.pipe(hashWorkaroundStream); + } + file.ws.on('error', function(err) { + if (!self.error) self.handleError(err); + }); + file.ws.on('close', function() { + if (hash) file.hash = hash.digest('hex'); + file.size = counter.bytes; + self.emit('file', fileStream.name, file); + endFlush(self); + }); +} + +function handleField(self, fieldStream) { + var value = ''; + var decoder = new StringDecoder(self.encoding); + + beginFlush(self); + fieldStream.on('readable', function() { + var buffer = fieldStream.read(); + if (!buffer) return; + + self.totalFieldSize += buffer.length; + if (self.totalFieldSize > self.maxFieldsSize) { + self.handleError(new Error("maxFieldsSize " + self.maxFieldsSize + " exceeded")); + return; + } + value += decoder.write(buffer); + }); + + fieldStream.on('end', function() { + self.emit('field', fieldStream.name, value); + endFlush(self); + }); +} + +function clearPartVars(self) { + self.partHeaders = {}; + self.partName = null; + self.partFilename = null; + self.partTransferEncoding = 'binary'; + self.destStream = null; + + self.headerFieldDecoder = new StringDecoder(self.encoding); + self.headerField = ""; + self.headerValueDecoder = new StringDecoder(self.encoding); + self.headerValue = ""; +} + +function setUpParser(self, boundary) { + self.boundary = new Buffer(boundary.length + 4); + self.boundary.write('\r\n--', 0, boundary.length + 4, 'ascii'); + self.boundary.write(boundary, 4, boundary.length, 'ascii'); + self.lookbehind = new Buffer(self.boundary.length + 8); + self.state = START; + self.boundaryChars = {}; + for (var i = 0; i < self.boundary.length; i++) { + self.boundaryChars[self.boundary[i]] = true; + } + + self.index = null; + self.partBoundaryFlag = false; + self.lastBoundaryFlag = false; + + self.on('finish', function() { + if ((self.state === HEADER_FIELD_START && self.index === 0) || + (self.state === PART_DATA && self.index === self.boundary.length)) + { + self.onParsePartEnd(); + } else if (self.state !== END) { + self.handleError(new Error('stream ended unexpectedly')); + } + self.finished = true; + maybeClose(self); + }); +} + +function uploadPath(baseDir, filename) { + var ext = path.extname(filename).replace(FILE_EXT_RE, '$1'); + var name = process.pid + '-' + + (Math.random() * 0x100000000 + 1).toString(36) + ext; + return path.join(baseDir, name); +} + +function parseFilename(headerValue) { + var m = headerValue.match(/\bfilename="(.*?)"($|; )/i); + if (!m) return; + + var filename = m[1].substr(m[1].lastIndexOf('\\') + 1); + filename = filename.replace(/%22/g, '"'); + filename = filename.replace(/&#([\d]{4});/g, function(m, code) { + return String.fromCharCode(code); + }); + return filename; +} + +function lower(c) { + return c | 0x20; +} + diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/LICENSE b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/LICENSE new file mode 100644 index 0000000..e3d4e69 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/LICENSE @@ -0,0 +1,18 @@ +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/README.md b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/README.md new file mode 100644 index 0000000..be97668 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/README.md @@ -0,0 +1,768 @@ +# readable-stream + +A new class of streams for Node.js + +This module provides the new Stream base classes introduced in Node +v0.10, for use in Node v0.8. You can use it to have programs that +have to work with node v0.8, while being forward-compatible for v0.10 +and beyond. When you drop support for v0.8, you can remove this +module, and only use the native streams. + +This is almost exactly the same codebase as appears in Node v0.10. +However: + +1. The exported object is actually the Readable class. Decorating the + native `stream` module would be global pollution. +2. In v0.10, you can safely use `base64` as an argument to + `setEncoding` in Readable streams. However, in v0.8, the + StringDecoder class has no `end()` method, which is problematic for + Base64. So, don't use that, because it'll break and be weird. + +Other than that, the API is the same as `require('stream')` in v0.10, +so the API docs are reproduced below. + +---------- + + Stability: 2 - Unstable + +A stream is an abstract interface implemented by various objects in +Node. For example a request to an HTTP server is a stream, as is +stdout. Streams are readable, writable, or both. All streams are +instances of [EventEmitter][] + +You can load the Stream base classes by doing `require('stream')`. +There are base classes provided for Readable streams, Writable +streams, Duplex streams, and Transform streams. + +## Compatibility + +In earlier versions of Node, the Readable stream interface was +simpler, but also less powerful and less useful. + +* Rather than waiting for you to call the `read()` method, `'data'` + events would start emitting immediately. If you needed to do some + I/O to decide how to handle data, then you had to store the chunks + in some kind of buffer so that they would not be lost. +* The `pause()` method was advisory, rather than guaranteed. This + meant that you still had to be prepared to receive `'data'` events + even when the stream was in a paused state. + +In Node v0.10, the Readable class described below was added. For +backwards compatibility with older Node programs, Readable streams +switch into "old mode" when a `'data'` event handler is added, or when +the `pause()` or `resume()` methods are called. The effect is that, +even if you are not using the new `read()` method and `'readable'` +event, you no longer have to worry about losing `'data'` chunks. + +Most programs will continue to function normally. However, this +introduces an edge case in the following conditions: + +* No `'data'` event handler is added. +* The `pause()` and `resume()` methods are never called. + +For example, consider the following code: + +```javascript +// WARNING! BROKEN! +net.createServer(function(socket) { + + // we add an 'end' method, but never consume the data + socket.on('end', function() { + // It will never get here. + socket.end('I got your message (but didnt read it)\n'); + }); + +}).listen(1337); +``` + +In versions of node prior to v0.10, the incoming message data would be +simply discarded. However, in Node v0.10 and beyond, the socket will +remain paused forever. + +The workaround in this situation is to call the `resume()` method to +trigger "old mode" behavior: + +```javascript +// Workaround +net.createServer(function(socket) { + + socket.on('end', function() { + socket.end('I got your message (but didnt read it)\n'); + }); + + // start the flow of data, discarding it. + socket.resume(); + +}).listen(1337); +``` + +In addition to new Readable streams switching into old-mode, pre-v0.10 +style streams can be wrapped in a Readable class using the `wrap()` +method. + +## Class: stream.Readable + + + +A `Readable Stream` has the following methods, members, and events. + +Note that `stream.Readable` is an abstract class designed to be +extended with an underlying implementation of the `_read(size)` +method. (See below.) + +### new stream.Readable([options]) + +* `options` {Object} + * `highWaterMark` {Number} The maximum number of bytes to store in + the internal buffer before ceasing to read from the underlying + resource. Default=16kb + * `encoding` {String} If specified, then buffers will be decoded to + strings using the specified encoding. Default=null + * `objectMode` {Boolean} Whether this stream should behave + as a stream of objects. Meaning that stream.read(n) returns + a single value instead of a Buffer of size n + +In classes that extend the Readable class, make sure to call the +constructor so that the buffering settings can be properly +initialized. + +### readable.\_read(size) + +* `size` {Number} Number of bytes to read asynchronously + +Note: **This function should NOT be called directly.** It should be +implemented by child classes, and called by the internal Readable +class methods only. + +All Readable stream implementations must provide a `_read` method +to fetch data from the underlying resource. + +This method is prefixed with an underscore because it is internal to +the class that defines it, and should not be called directly by user +programs. However, you **are** expected to override this method in +your own extension classes. + +When data is available, put it into the read queue by calling +`readable.push(chunk)`. If `push` returns false, then you should stop +reading. When `_read` is called again, you should start pushing more +data. + +The `size` argument is advisory. Implementations where a "read" is a +single call that returns data can use this to know how much data to +fetch. Implementations where that is not relevant, such as TCP or +TLS, may ignore this argument, and simply provide data whenever it +becomes available. There is no need, for example to "wait" until +`size` bytes are available before calling `stream.push(chunk)`. + +### readable.push(chunk) + +* `chunk` {Buffer | null | String} Chunk of data to push into the read queue +* return {Boolean} Whether or not more pushes should be performed + +Note: **This function should be called by Readable implementors, NOT +by consumers of Readable subclasses.** The `_read()` function will not +be called again until at least one `push(chunk)` call is made. If no +data is available, then you MAY call `push('')` (an empty string) to +allow a future `_read` call, without adding any data to the queue. + +The `Readable` class works by putting data into a read queue to be +pulled out later by calling the `read()` method when the `'readable'` +event fires. + +The `push()` method will explicitly insert some data into the read +queue. If it is called with `null` then it will signal the end of the +data. + +In some cases, you may be wrapping a lower-level source which has some +sort of pause/resume mechanism, and a data callback. In those cases, +you could wrap the low-level source object by doing something like +this: + +```javascript +// source is an object with readStop() and readStart() methods, +// and an `ondata` member that gets called when it has data, and +// an `onend` member that gets called when the data is over. + +var stream = new Readable(); + +source.ondata = function(chunk) { + // if push() returns false, then we need to stop reading from source + if (!stream.push(chunk)) + source.readStop(); +}; + +source.onend = function() { + stream.push(null); +}; + +// _read will be called when the stream wants to pull more data in +// the advisory size argument is ignored in this case. +stream._read = function(n) { + source.readStart(); +}; +``` + +### readable.unshift(chunk) + +* `chunk` {Buffer | null | String} Chunk of data to unshift onto the read queue +* return {Boolean} Whether or not more pushes should be performed + +This is the corollary of `readable.push(chunk)`. Rather than putting +the data at the *end* of the read queue, it puts it at the *front* of +the read queue. + +This is useful in certain use-cases where a stream is being consumed +by a parser, which needs to "un-consume" some data that it has +optimistically pulled out of the source. + +```javascript +// A parser for a simple data protocol. +// The "header" is a JSON object, followed by 2 \n characters, and +// then a message body. +// +// Note: This can be done more simply as a Transform stream. See below. + +function SimpleProtocol(source, options) { + if (!(this instanceof SimpleProtocol)) + return new SimpleProtocol(options); + + Readable.call(this, options); + this._inBody = false; + this._sawFirstCr = false; + + // source is a readable stream, such as a socket or file + this._source = source; + + var self = this; + source.on('end', function() { + self.push(null); + }); + + // give it a kick whenever the source is readable + // read(0) will not consume any bytes + source.on('readable', function() { + self.read(0); + }); + + this._rawHeader = []; + this.header = null; +} + +SimpleProtocol.prototype = Object.create( + Readable.prototype, { constructor: { value: SimpleProtocol }}); + +SimpleProtocol.prototype._read = function(n) { + if (!this._inBody) { + var chunk = this._source.read(); + + // if the source doesn't have data, we don't have data yet. + if (chunk === null) + return this.push(''); + + // check if the chunk has a \n\n + var split = -1; + for (var i = 0; i < chunk.length; i++) { + if (chunk[i] === 10) { // '\n' + if (this._sawFirstCr) { + split = i; + break; + } else { + this._sawFirstCr = true; + } + } else { + this._sawFirstCr = false; + } + } + + if (split === -1) { + // still waiting for the \n\n + // stash the chunk, and try again. + this._rawHeader.push(chunk); + this.push(''); + } else { + this._inBody = true; + var h = chunk.slice(0, split); + this._rawHeader.push(h); + var header = Buffer.concat(this._rawHeader).toString(); + try { + this.header = JSON.parse(header); + } catch (er) { + this.emit('error', new Error('invalid simple protocol data')); + return; + } + // now, because we got some extra data, unshift the rest + // back into the read queue so that our consumer will see it. + var b = chunk.slice(split); + this.unshift(b); + + // and let them know that we are done parsing the header. + this.emit('header', this.header); + } + } else { + // from there on, just provide the data to our consumer. + // careful not to push(null), since that would indicate EOF. + var chunk = this._source.read(); + if (chunk) this.push(chunk); + } +}; + +// Usage: +var parser = new SimpleProtocol(source); +// Now parser is a readable stream that will emit 'header' +// with the parsed header data. +``` + +### readable.wrap(stream) + +* `stream` {Stream} An "old style" readable stream + +If you are using an older Node library that emits `'data'` events and +has a `pause()` method that is advisory only, then you can use the +`wrap()` method to create a Readable stream that uses the old stream +as its data source. + +For example: + +```javascript +var OldReader = require('./old-api-module.js').OldReader; +var oreader = new OldReader; +var Readable = require('stream').Readable; +var myReader = new Readable().wrap(oreader); + +myReader.on('readable', function() { + myReader.read(); // etc. +}); +``` + +### Event: 'readable' + +When there is data ready to be consumed, this event will fire. + +When this event emits, call the `read()` method to consume the data. + +### Event: 'end' + +Emitted when the stream has received an EOF (FIN in TCP terminology). +Indicates that no more `'data'` events will happen. If the stream is +also writable, it may be possible to continue writing. + +### Event: 'data' + +The `'data'` event emits either a `Buffer` (by default) or a string if +`setEncoding()` was used. + +Note that adding a `'data'` event listener will switch the Readable +stream into "old mode", where data is emitted as soon as it is +available, rather than waiting for you to call `read()` to consume it. + +### Event: 'error' + +Emitted if there was an error receiving data. + +### Event: 'close' + +Emitted when the underlying resource (for example, the backing file +descriptor) has been closed. Not all streams will emit this. + +### readable.setEncoding(encoding) + +Makes the `'data'` event emit a string instead of a `Buffer`. `encoding` +can be `'utf8'`, `'utf16le'` (`'ucs2'`), `'ascii'`, or `'hex'`. + +The encoding can also be set by specifying an `encoding` field to the +constructor. + +### readable.read([size]) + +* `size` {Number | null} Optional number of bytes to read. +* Return: {Buffer | String | null} + +Note: **This function SHOULD be called by Readable stream users.** + +Call this method to consume data once the `'readable'` event is +emitted. + +The `size` argument will set a minimum number of bytes that you are +interested in. If not set, then the entire content of the internal +buffer is returned. + +If there is no data to consume, or if there are fewer bytes in the +internal buffer than the `size` argument, then `null` is returned, and +a future `'readable'` event will be emitted when more is available. + +Calling `stream.read(0)` will always return `null`, and will trigger a +refresh of the internal buffer, but otherwise be a no-op. + +### readable.pipe(destination, [options]) + +* `destination` {Writable Stream} +* `options` {Object} Optional + * `end` {Boolean} Default=true + +Connects this readable stream to `destination` WriteStream. Incoming +data on this stream gets written to `destination`. Properly manages +back-pressure so that a slow destination will not be overwhelmed by a +fast readable stream. + +This function returns the `destination` stream. + +For example, emulating the Unix `cat` command: + + process.stdin.pipe(process.stdout); + +By default `end()` is called on the destination when the source stream +emits `end`, so that `destination` is no longer writable. Pass `{ end: +false }` as `options` to keep the destination stream open. + +This keeps `writer` open so that "Goodbye" can be written at the +end. + + reader.pipe(writer, { end: false }); + reader.on("end", function() { + writer.end("Goodbye\n"); + }); + +Note that `process.stderr` and `process.stdout` are never closed until +the process exits, regardless of the specified options. + +### readable.unpipe([destination]) + +* `destination` {Writable Stream} Optional + +Undo a previously established `pipe()`. If no destination is +provided, then all previously established pipes are removed. + +### readable.pause() + +Switches the readable stream into "old mode", where data is emitted +using a `'data'` event rather than being buffered for consumption via +the `read()` method. + +Ceases the flow of data. No `'data'` events are emitted while the +stream is in a paused state. + +### readable.resume() + +Switches the readable stream into "old mode", where data is emitted +using a `'data'` event rather than being buffered for consumption via +the `read()` method. + +Resumes the incoming `'data'` events after a `pause()`. + + +## Class: stream.Writable + + + +A `Writable` Stream has the following methods, members, and events. + +Note that `stream.Writable` is an abstract class designed to be +extended with an underlying implementation of the +`_write(chunk, encoding, cb)` method. (See below.) + +### new stream.Writable([options]) + +* `options` {Object} + * `highWaterMark` {Number} Buffer level when `write()` starts + returning false. Default=16kb + * `decodeStrings` {Boolean} Whether or not to decode strings into + Buffers before passing them to `_write()`. Default=true + +In classes that extend the Writable class, make sure to call the +constructor so that the buffering settings can be properly +initialized. + +### writable.\_write(chunk, encoding, callback) + +* `chunk` {Buffer | String} The chunk to be written. Will always + be a buffer unless the `decodeStrings` option was set to `false`. +* `encoding` {String} If the chunk is a string, then this is the + encoding type. Ignore chunk is a buffer. Note that chunk will + **always** be a buffer unless the `decodeStrings` option is + explicitly set to `false`. +* `callback` {Function} Call this function (optionally with an error + argument) when you are done processing the supplied chunk. + +All Writable stream implementations must provide a `_write` method to +send data to the underlying resource. + +Note: **This function MUST NOT be called directly.** It should be +implemented by child classes, and called by the internal Writable +class methods only. + +Call the callback using the standard `callback(error)` pattern to +signal that the write completed successfully or with an error. + +If the `decodeStrings` flag is set in the constructor options, then +`chunk` may be a string rather than a Buffer, and `encoding` will +indicate the sort of string that it is. This is to support +implementations that have an optimized handling for certain string +data encodings. If you do not explicitly set the `decodeStrings` +option to `false`, then you can safely ignore the `encoding` argument, +and assume that `chunk` will always be a Buffer. + +This method is prefixed with an underscore because it is internal to +the class that defines it, and should not be called directly by user +programs. However, you **are** expected to override this method in +your own extension classes. + + +### writable.write(chunk, [encoding], [callback]) + +* `chunk` {Buffer | String} Data to be written +* `encoding` {String} Optional. If `chunk` is a string, then encoding + defaults to `'utf8'` +* `callback` {Function} Optional. Called when this chunk is + successfully written. +* Returns {Boolean} + +Writes `chunk` to the stream. Returns `true` if the data has been +flushed to the underlying resource. Returns `false` to indicate that +the buffer is full, and the data will be sent out in the future. The +`'drain'` event will indicate when the buffer is empty again. + +The specifics of when `write()` will return false, is determined by +the `highWaterMark` option provided to the constructor. + +### writable.end([chunk], [encoding], [callback]) + +* `chunk` {Buffer | String} Optional final data to be written +* `encoding` {String} Optional. If `chunk` is a string, then encoding + defaults to `'utf8'` +* `callback` {Function} Optional. Called when the final chunk is + successfully written. + +Call this method to signal the end of the data being written to the +stream. + +### Event: 'drain' + +Emitted when the stream's write queue empties and it's safe to write +without buffering again. Listen for it when `stream.write()` returns +`false`. + +### Event: 'close' + +Emitted when the underlying resource (for example, the backing file +descriptor) has been closed. Not all streams will emit this. + +### Event: 'finish' + +When `end()` is called and there are no more chunks to write, this +event is emitted. + +### Event: 'pipe' + +* `source` {Readable Stream} + +Emitted when the stream is passed to a readable stream's pipe method. + +### Event 'unpipe' + +* `source` {Readable Stream} + +Emitted when a previously established `pipe()` is removed using the +source Readable stream's `unpipe()` method. + +## Class: stream.Duplex + + + +A "duplex" stream is one that is both Readable and Writable, such as a +TCP socket connection. + +Note that `stream.Duplex` is an abstract class designed to be +extended with an underlying implementation of the `_read(size)` +and `_write(chunk, encoding, callback)` methods as you would with a Readable or +Writable stream class. + +Since JavaScript doesn't have multiple prototypal inheritance, this +class prototypally inherits from Readable, and then parasitically from +Writable. It is thus up to the user to implement both the lowlevel +`_read(n)` method as well as the lowlevel `_write(chunk, encoding, cb)` method +on extension duplex classes. + +### new stream.Duplex(options) + +* `options` {Object} Passed to both Writable and Readable + constructors. Also has the following fields: + * `allowHalfOpen` {Boolean} Default=true. If set to `false`, then + the stream will automatically end the readable side when the + writable side ends and vice versa. + +In classes that extend the Duplex class, make sure to call the +constructor so that the buffering settings can be properly +initialized. + +## Class: stream.Transform + +A "transform" stream is a duplex stream where the output is causally +connected in some way to the input, such as a zlib stream or a crypto +stream. + +There is no requirement that the output be the same size as the input, +the same number of chunks, or arrive at the same time. For example, a +Hash stream will only ever have a single chunk of output which is +provided when the input is ended. A zlib stream will either produce +much smaller or much larger than its input. + +Rather than implement the `_read()` and `_write()` methods, Transform +classes must implement the `_transform()` method, and may optionally +also implement the `_flush()` method. (See below.) + +### new stream.Transform([options]) + +* `options` {Object} Passed to both Writable and Readable + constructors. + +In classes that extend the Transform class, make sure to call the +constructor so that the buffering settings can be properly +initialized. + +### transform.\_transform(chunk, encoding, callback) + +* `chunk` {Buffer | String} The chunk to be transformed. Will always + be a buffer unless the `decodeStrings` option was set to `false`. +* `encoding` {String} If the chunk is a string, then this is the + encoding type. (Ignore if `decodeStrings` chunk is a buffer.) +* `callback` {Function} Call this function (optionally with an error + argument) when you are done processing the supplied chunk. + +Note: **This function MUST NOT be called directly.** It should be +implemented by child classes, and called by the internal Transform +class methods only. + +All Transform stream implementations must provide a `_transform` +method to accept input and produce output. + +`_transform` should do whatever has to be done in this specific +Transform class, to handle the bytes being written, and pass them off +to the readable portion of the interface. Do asynchronous I/O, +process things, and so on. + +Call `transform.push(outputChunk)` 0 or more times to generate output +from this input chunk, depending on how much data you want to output +as a result of this chunk. + +Call the callback function only when the current chunk is completely +consumed. Note that there may or may not be output as a result of any +particular input chunk. + +This method is prefixed with an underscore because it is internal to +the class that defines it, and should not be called directly by user +programs. However, you **are** expected to override this method in +your own extension classes. + +### transform.\_flush(callback) + +* `callback` {Function} Call this function (optionally with an error + argument) when you are done flushing any remaining data. + +Note: **This function MUST NOT be called directly.** It MAY be implemented +by child classes, and if so, will be called by the internal Transform +class methods only. + +In some cases, your transform operation may need to emit a bit more +data at the end of the stream. For example, a `Zlib` compression +stream will store up some internal state so that it can optimally +compress the output. At the end, however, it needs to do the best it +can with what is left, so that the data will be complete. + +In those cases, you can implement a `_flush` method, which will be +called at the very end, after all the written data is consumed, but +before emitting `end` to signal the end of the readable side. Just +like with `_transform`, call `transform.push(chunk)` zero or more +times, as appropriate, and call `callback` when the flush operation is +complete. + +This method is prefixed with an underscore because it is internal to +the class that defines it, and should not be called directly by user +programs. However, you **are** expected to override this method in +your own extension classes. + +### Example: `SimpleProtocol` parser + +The example above of a simple protocol parser can be implemented much +more simply by using the higher level `Transform` stream class. + +In this example, rather than providing the input as an argument, it +would be piped into the parser, which is a more idiomatic Node stream +approach. + +```javascript +function SimpleProtocol(options) { + if (!(this instanceof SimpleProtocol)) + return new SimpleProtocol(options); + + Transform.call(this, options); + this._inBody = false; + this._sawFirstCr = false; + this._rawHeader = []; + this.header = null; +} + +SimpleProtocol.prototype = Object.create( + Transform.prototype, { constructor: { value: SimpleProtocol }}); + +SimpleProtocol.prototype._transform = function(chunk, encoding, done) { + if (!this._inBody) { + // check if the chunk has a \n\n + var split = -1; + for (var i = 0; i < chunk.length; i++) { + if (chunk[i] === 10) { // '\n' + if (this._sawFirstCr) { + split = i; + break; + } else { + this._sawFirstCr = true; + } + } else { + this._sawFirstCr = false; + } + } + + if (split === -1) { + // still waiting for the \n\n + // stash the chunk, and try again. + this._rawHeader.push(chunk); + } else { + this._inBody = true; + var h = chunk.slice(0, split); + this._rawHeader.push(h); + var header = Buffer.concat(this._rawHeader).toString(); + try { + this.header = JSON.parse(header); + } catch (er) { + this.emit('error', new Error('invalid simple protocol data')); + return; + } + // and let them know that we are done parsing the header. + this.emit('header', this.header); + + // now, because we got some extra data, emit this first. + this.push(b); + } + } else { + // from there on, just provide the data to our consumer as-is. + this.push(b); + } + done(); +}; + +var parser = new SimpleProtocol(); +source.pipe(parser) + +// Now parser is a readable stream that will emit 'header' +// with the parsed header data. +``` + + +## Class: stream.PassThrough + +This is a trivial implementation of a `Transform` stream that simply +passes the input bytes across to the output. Its purpose is mainly +for examples and testing, but there are occasionally use cases where +it can come in handy. + + +[EventEmitter]: events.html#events_class_events_eventemitter diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/duplex.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/duplex.js new file mode 100644 index 0000000..ca807af --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/duplex.js @@ -0,0 +1 @@ +module.exports = require("./lib/_stream_duplex.js") diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/examples/CAPSLOCKTYPER.JS b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/examples/CAPSLOCKTYPER.JS new file mode 100644 index 0000000..205a425 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/examples/CAPSLOCKTYPER.JS @@ -0,0 +1,32 @@ +var Transform = require('../transform'); +var inherits = require('util').inherits; + +// subclass +function MyStream () { + Transform.call(this, { + lowWaterMark: 0, + encoding: 'utf8' + }); +} +inherits(MyStream, Transform); + +MyStream.prototype._transform = function (chunk, outputFn, callback) { + outputFn(new Buffer(String(chunk).toUpperCase())); + callback(); +}; + +// use it! +var s = new MyStream(); +process.stdin.resume(); +process.stdin.pipe(s).pipe(process.stdout); +if (process.stdin.setRawMode) + process.stdin.setRawMode(true); +process.stdin.on('data', function (c) { + c = c.toString(); + if (c === '\u0003' || c === '\u0004') { + process.stdin.pause(); + s.end(); + } + if (c === '\r') + process.stdout.write('\n'); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/examples/typer-fsr.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/examples/typer-fsr.js new file mode 100644 index 0000000..7e71584 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/examples/typer-fsr.js @@ -0,0 +1,15 @@ +var fs = require('fs'); +var FSReadable = require('../fs.js'); +var rst = new FSReadable(__filename); + +rst.on('end', function() { + process.stdin.pause(); +}); + +process.stdin.setRawMode(true); +process.stdin.on('data', function() { + var c = rst.read(3); + if (!c) return; + process.stdout.write(c); +}); +process.stdin.resume(); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/examples/typer.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/examples/typer.js new file mode 100644 index 0000000..c16eb6f --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/examples/typer.js @@ -0,0 +1,17 @@ +var fs = require('fs'); +var fst = fs.createReadStream(__filename); +var Readable = require('../readable.js'); +var rst = new Readable(); +rst.wrap(fst); + +rst.on('end', function() { + process.stdin.pause(); +}); + +process.stdin.setRawMode(true); +process.stdin.on('data', function() { + var c = rst.read(3); + if (!c) return setTimeout(process.exit, 500) + process.stdout.write(c); +}); +process.stdin.resume(); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/float.patch b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/float.patch new file mode 100644 index 0000000..b984607 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/float.patch @@ -0,0 +1,923 @@ +diff --git a/lib/_stream_duplex.js b/lib/_stream_duplex.js +index c5a741c..a2e0d8e 100644 +--- a/lib/_stream_duplex.js ++++ b/lib/_stream_duplex.js +@@ -26,8 +26,8 @@ + + module.exports = Duplex; + var util = require('util'); +-var Readable = require('_stream_readable'); +-var Writable = require('_stream_writable'); ++var Readable = require('./_stream_readable'); ++var Writable = require('./_stream_writable'); + + util.inherits(Duplex, Readable); + +diff --git a/lib/_stream_passthrough.js b/lib/_stream_passthrough.js +index a5e9864..330c247 100644 +--- a/lib/_stream_passthrough.js ++++ b/lib/_stream_passthrough.js +@@ -25,7 +25,7 @@ + + module.exports = PassThrough; + +-var Transform = require('_stream_transform'); ++var Transform = require('./_stream_transform'); + var util = require('util'); + util.inherits(PassThrough, Transform); + +diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js +index 0c3fe3e..90a8298 100644 +--- a/lib/_stream_readable.js ++++ b/lib/_stream_readable.js +@@ -23,10 +23,34 @@ module.exports = Readable; + Readable.ReadableState = ReadableState; + + var EE = require('events').EventEmitter; ++if (!EE.listenerCount) EE.listenerCount = function(emitter, type) { ++ return emitter.listeners(type).length; ++}; ++ ++if (!global.setImmediate) global.setImmediate = function setImmediate(fn) { ++ return setTimeout(fn, 0); ++}; ++if (!global.clearImmediate) global.clearImmediate = function clearImmediate(i) { ++ return clearTimeout(i); ++}; ++ + var Stream = require('stream'); + var util = require('util'); ++if (!util.isUndefined) { ++ var utilIs = require('core-util-is'); ++ for (var f in utilIs) { ++ util[f] = utilIs[f]; ++ } ++} + var StringDecoder; +-var debug = util.debuglog('stream'); ++var debug; ++if (util.debuglog) ++ debug = util.debuglog('stream'); ++else try { ++ debug = require('debuglog')('stream'); ++} catch (er) { ++ debug = function() {}; ++} + + util.inherits(Readable, Stream); + +@@ -380,7 +404,7 @@ function chunkInvalid(state, chunk) { + + + function onEofChunk(stream, state) { +- if (state.decoder && !state.ended) { ++ if (state.decoder && !state.ended && state.decoder.end) { + var chunk = state.decoder.end(); + if (chunk && chunk.length) { + state.buffer.push(chunk); +diff --git a/lib/_stream_transform.js b/lib/_stream_transform.js +index b1f9fcc..b0caf57 100644 +--- a/lib/_stream_transform.js ++++ b/lib/_stream_transform.js +@@ -64,8 +64,14 @@ + + module.exports = Transform; + +-var Duplex = require('_stream_duplex'); ++var Duplex = require('./_stream_duplex'); + var util = require('util'); ++if (!util.isUndefined) { ++ var utilIs = require('core-util-is'); ++ for (var f in utilIs) { ++ util[f] = utilIs[f]; ++ } ++} + util.inherits(Transform, Duplex); + + +diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js +index ba2e920..f49288b 100644 +--- a/lib/_stream_writable.js ++++ b/lib/_stream_writable.js +@@ -27,6 +27,12 @@ module.exports = Writable; + Writable.WritableState = WritableState; + + var util = require('util'); ++if (!util.isUndefined) { ++ var utilIs = require('core-util-is'); ++ for (var f in utilIs) { ++ util[f] = utilIs[f]; ++ } ++} + var Stream = require('stream'); + + util.inherits(Writable, Stream); +@@ -119,7 +125,7 @@ function WritableState(options, stream) { + function Writable(options) { + // Writable ctor is applied to Duplexes, though they're not + // instanceof Writable, they're instanceof Readable. +- if (!(this instanceof Writable) && !(this instanceof Stream.Duplex)) ++ if (!(this instanceof Writable) && !(this instanceof require('./_stream_duplex'))) + return new Writable(options); + + this._writableState = new WritableState(options, this); +diff --git a/test/simple/test-stream-big-push.js b/test/simple/test-stream-big-push.js +index e3787e4..8cd2127 100644 +--- a/test/simple/test-stream-big-push.js ++++ b/test/simple/test-stream-big-push.js +@@ -21,7 +21,7 @@ + + var common = require('../common'); + var assert = require('assert'); +-var stream = require('stream'); ++var stream = require('../../'); + var str = 'asdfasdfasdfasdfasdf'; + + var r = new stream.Readable({ +diff --git a/test/simple/test-stream-end-paused.js b/test/simple/test-stream-end-paused.js +index bb73777..d40efc7 100644 +--- a/test/simple/test-stream-end-paused.js ++++ b/test/simple/test-stream-end-paused.js +@@ -25,7 +25,7 @@ var gotEnd = false; + + // Make sure we don't miss the end event for paused 0-length streams + +-var Readable = require('stream').Readable; ++var Readable = require('../../').Readable; + var stream = new Readable(); + var calledRead = false; + stream._read = function() { +diff --git a/test/simple/test-stream-pipe-after-end.js b/test/simple/test-stream-pipe-after-end.js +index b46ee90..0be8366 100644 +--- a/test/simple/test-stream-pipe-after-end.js ++++ b/test/simple/test-stream-pipe-after-end.js +@@ -22,8 +22,8 @@ + var common = require('../common'); + var assert = require('assert'); + +-var Readable = require('_stream_readable'); +-var Writable = require('_stream_writable'); ++var Readable = require('../../lib/_stream_readable'); ++var Writable = require('../../lib/_stream_writable'); + var util = require('util'); + + util.inherits(TestReadable, Readable); +diff --git a/test/simple/test-stream-pipe-cleanup.js b/test/simple/test-stream-pipe-cleanup.js +deleted file mode 100644 +index f689358..0000000 +--- a/test/simple/test-stream-pipe-cleanup.js ++++ /dev/null +@@ -1,122 +0,0 @@ +-// Copyright Joyent, Inc. and other Node contributors. +-// +-// Permission is hereby granted, free of charge, to any person obtaining a +-// copy of this software and associated documentation files (the +-// "Software"), to deal in the Software without restriction, including +-// without limitation the rights to use, copy, modify, merge, publish, +-// distribute, sublicense, and/or sell copies of the Software, and to permit +-// persons to whom the Software is furnished to do so, subject to the +-// following conditions: +-// +-// The above copyright notice and this permission notice shall be included +-// in all copies or substantial portions of the Software. +-// +-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +-// USE OR OTHER DEALINGS IN THE SOFTWARE. +- +-// This test asserts that Stream.prototype.pipe does not leave listeners +-// hanging on the source or dest. +- +-var common = require('../common'); +-var stream = require('stream'); +-var assert = require('assert'); +-var util = require('util'); +- +-function Writable() { +- this.writable = true; +- this.endCalls = 0; +- stream.Stream.call(this); +-} +-util.inherits(Writable, stream.Stream); +-Writable.prototype.end = function() { +- this.endCalls++; +-}; +- +-Writable.prototype.destroy = function() { +- this.endCalls++; +-}; +- +-function Readable() { +- this.readable = true; +- stream.Stream.call(this); +-} +-util.inherits(Readable, stream.Stream); +- +-function Duplex() { +- this.readable = true; +- Writable.call(this); +-} +-util.inherits(Duplex, Writable); +- +-var i = 0; +-var limit = 100; +- +-var w = new Writable(); +- +-var r; +- +-for (i = 0; i < limit; i++) { +- r = new Readable(); +- r.pipe(w); +- r.emit('end'); +-} +-assert.equal(0, r.listeners('end').length); +-assert.equal(limit, w.endCalls); +- +-w.endCalls = 0; +- +-for (i = 0; i < limit; i++) { +- r = new Readable(); +- r.pipe(w); +- r.emit('close'); +-} +-assert.equal(0, r.listeners('close').length); +-assert.equal(limit, w.endCalls); +- +-w.endCalls = 0; +- +-r = new Readable(); +- +-for (i = 0; i < limit; i++) { +- w = new Writable(); +- r.pipe(w); +- w.emit('close'); +-} +-assert.equal(0, w.listeners('close').length); +- +-r = new Readable(); +-w = new Writable(); +-var d = new Duplex(); +-r.pipe(d); // pipeline A +-d.pipe(w); // pipeline B +-assert.equal(r.listeners('end').length, 2); // A.onend, A.cleanup +-assert.equal(r.listeners('close').length, 2); // A.onclose, A.cleanup +-assert.equal(d.listeners('end').length, 2); // B.onend, B.cleanup +-assert.equal(d.listeners('close').length, 3); // A.cleanup, B.onclose, B.cleanup +-assert.equal(w.listeners('end').length, 0); +-assert.equal(w.listeners('close').length, 1); // B.cleanup +- +-r.emit('end'); +-assert.equal(d.endCalls, 1); +-assert.equal(w.endCalls, 0); +-assert.equal(r.listeners('end').length, 0); +-assert.equal(r.listeners('close').length, 0); +-assert.equal(d.listeners('end').length, 2); // B.onend, B.cleanup +-assert.equal(d.listeners('close').length, 2); // B.onclose, B.cleanup +-assert.equal(w.listeners('end').length, 0); +-assert.equal(w.listeners('close').length, 1); // B.cleanup +- +-d.emit('end'); +-assert.equal(d.endCalls, 1); +-assert.equal(w.endCalls, 1); +-assert.equal(r.listeners('end').length, 0); +-assert.equal(r.listeners('close').length, 0); +-assert.equal(d.listeners('end').length, 0); +-assert.equal(d.listeners('close').length, 0); +-assert.equal(w.listeners('end').length, 0); +-assert.equal(w.listeners('close').length, 0); +diff --git a/test/simple/test-stream-pipe-error-handling.js b/test/simple/test-stream-pipe-error-handling.js +index c5d724b..c7d6b7d 100644 +--- a/test/simple/test-stream-pipe-error-handling.js ++++ b/test/simple/test-stream-pipe-error-handling.js +@@ -21,7 +21,7 @@ + + var common = require('../common'); + var assert = require('assert'); +-var Stream = require('stream').Stream; ++var Stream = require('../../').Stream; + + (function testErrorListenerCatches() { + var source = new Stream(); +diff --git a/test/simple/test-stream-pipe-event.js b/test/simple/test-stream-pipe-event.js +index cb9d5fe..56f8d61 100644 +--- a/test/simple/test-stream-pipe-event.js ++++ b/test/simple/test-stream-pipe-event.js +@@ -20,7 +20,7 @@ + // USE OR OTHER DEALINGS IN THE SOFTWARE. + + var common = require('../common'); +-var stream = require('stream'); ++var stream = require('../../'); + var assert = require('assert'); + var util = require('util'); + +diff --git a/test/simple/test-stream-push-order.js b/test/simple/test-stream-push-order.js +index f2e6ec2..a5c9bf9 100644 +--- a/test/simple/test-stream-push-order.js ++++ b/test/simple/test-stream-push-order.js +@@ -20,7 +20,7 @@ + // USE OR OTHER DEALINGS IN THE SOFTWARE. + + var common = require('../common.js'); +-var Readable = require('stream').Readable; ++var Readable = require('../../').Readable; + var assert = require('assert'); + + var s = new Readable({ +diff --git a/test/simple/test-stream-push-strings.js b/test/simple/test-stream-push-strings.js +index 06f43dc..1701a9a 100644 +--- a/test/simple/test-stream-push-strings.js ++++ b/test/simple/test-stream-push-strings.js +@@ -22,7 +22,7 @@ + var common = require('../common'); + var assert = require('assert'); + +-var Readable = require('stream').Readable; ++var Readable = require('../../').Readable; + var util = require('util'); + + util.inherits(MyStream, Readable); +diff --git a/test/simple/test-stream-readable-event.js b/test/simple/test-stream-readable-event.js +index ba6a577..a8e6f7b 100644 +--- a/test/simple/test-stream-readable-event.js ++++ b/test/simple/test-stream-readable-event.js +@@ -22,7 +22,7 @@ + var common = require('../common'); + var assert = require('assert'); + +-var Readable = require('stream').Readable; ++var Readable = require('../../').Readable; + + (function first() { + // First test, not reading when the readable is added. +diff --git a/test/simple/test-stream-readable-flow-recursion.js b/test/simple/test-stream-readable-flow-recursion.js +index 2891ad6..11689ba 100644 +--- a/test/simple/test-stream-readable-flow-recursion.js ++++ b/test/simple/test-stream-readable-flow-recursion.js +@@ -27,7 +27,7 @@ var assert = require('assert'); + // more data continuously, but without triggering a nextTick + // warning or RangeError. + +-var Readable = require('stream').Readable; ++var Readable = require('../../').Readable; + + // throw an error if we trigger a nextTick warning. + process.throwDeprecation = true; +diff --git a/test/simple/test-stream-unshift-empty-chunk.js b/test/simple/test-stream-unshift-empty-chunk.js +index 0c96476..7827538 100644 +--- a/test/simple/test-stream-unshift-empty-chunk.js ++++ b/test/simple/test-stream-unshift-empty-chunk.js +@@ -24,7 +24,7 @@ var assert = require('assert'); + + // This test verifies that stream.unshift(Buffer(0)) or + // stream.unshift('') does not set state.reading=false. +-var Readable = require('stream').Readable; ++var Readable = require('../../').Readable; + + var r = new Readable(); + var nChunks = 10; +diff --git a/test/simple/test-stream-unshift-read-race.js b/test/simple/test-stream-unshift-read-race.js +index 83fd9fa..17c18aa 100644 +--- a/test/simple/test-stream-unshift-read-race.js ++++ b/test/simple/test-stream-unshift-read-race.js +@@ -29,7 +29,7 @@ var assert = require('assert'); + // 3. push() after the EOF signaling null is an error. + // 4. _read() is not called after pushing the EOF null chunk. + +-var stream = require('stream'); ++var stream = require('../../'); + var hwm = 10; + var r = stream.Readable({ highWaterMark: hwm }); + var chunks = 10; +@@ -51,7 +51,14 @@ r._read = function(n) { + + function push(fast) { + assert(!pushedNull, 'push() after null push'); +- var c = pos >= data.length ? null : data.slice(pos, pos + n); ++ var c; ++ if (pos >= data.length) ++ c = null; ++ else { ++ if (n + pos > data.length) ++ n = data.length - pos; ++ c = data.slice(pos, pos + n); ++ } + pushedNull = c === null; + if (fast) { + pos += n; +diff --git a/test/simple/test-stream-writev.js b/test/simple/test-stream-writev.js +index 5b49e6e..b5321f3 100644 +--- a/test/simple/test-stream-writev.js ++++ b/test/simple/test-stream-writev.js +@@ -22,7 +22,7 @@ + var common = require('../common'); + var assert = require('assert'); + +-var stream = require('stream'); ++var stream = require('../../'); + + var queue = []; + for (var decode = 0; decode < 2; decode++) { +diff --git a/test/simple/test-stream2-basic.js b/test/simple/test-stream2-basic.js +index 3814bf0..248c1be 100644 +--- a/test/simple/test-stream2-basic.js ++++ b/test/simple/test-stream2-basic.js +@@ -21,7 +21,7 @@ + + + var common = require('../common.js'); +-var R = require('_stream_readable'); ++var R = require('../../lib/_stream_readable'); + var assert = require('assert'); + + var util = require('util'); +diff --git a/test/simple/test-stream2-compatibility.js b/test/simple/test-stream2-compatibility.js +index 6cdd4e9..f0fa84b 100644 +--- a/test/simple/test-stream2-compatibility.js ++++ b/test/simple/test-stream2-compatibility.js +@@ -21,7 +21,7 @@ + + + var common = require('../common.js'); +-var R = require('_stream_readable'); ++var R = require('../../lib/_stream_readable'); + var assert = require('assert'); + + var util = require('util'); +diff --git a/test/simple/test-stream2-finish-pipe.js b/test/simple/test-stream2-finish-pipe.js +index 39b274f..006a19b 100644 +--- a/test/simple/test-stream2-finish-pipe.js ++++ b/test/simple/test-stream2-finish-pipe.js +@@ -20,7 +20,7 @@ + // USE OR OTHER DEALINGS IN THE SOFTWARE. + + var common = require('../common.js'); +-var stream = require('stream'); ++var stream = require('../../'); + var Buffer = require('buffer').Buffer; + + var r = new stream.Readable(); +diff --git a/test/simple/test-stream2-fs.js b/test/simple/test-stream2-fs.js +deleted file mode 100644 +index e162406..0000000 +--- a/test/simple/test-stream2-fs.js ++++ /dev/null +@@ -1,72 +0,0 @@ +-// Copyright Joyent, Inc. and other Node contributors. +-// +-// Permission is hereby granted, free of charge, to any person obtaining a +-// copy of this software and associated documentation files (the +-// "Software"), to deal in the Software without restriction, including +-// without limitation the rights to use, copy, modify, merge, publish, +-// distribute, sublicense, and/or sell copies of the Software, and to permit +-// persons to whom the Software is furnished to do so, subject to the +-// following conditions: +-// +-// The above copyright notice and this permission notice shall be included +-// in all copies or substantial portions of the Software. +-// +-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +-// USE OR OTHER DEALINGS IN THE SOFTWARE. +- +- +-var common = require('../common.js'); +-var R = require('_stream_readable'); +-var assert = require('assert'); +- +-var fs = require('fs'); +-var FSReadable = fs.ReadStream; +- +-var path = require('path'); +-var file = path.resolve(common.fixturesDir, 'x1024.txt'); +- +-var size = fs.statSync(file).size; +- +-var expectLengths = [1024]; +- +-var util = require('util'); +-var Stream = require('stream'); +- +-util.inherits(TestWriter, Stream); +- +-function TestWriter() { +- Stream.apply(this); +- this.buffer = []; +- this.length = 0; +-} +- +-TestWriter.prototype.write = function(c) { +- this.buffer.push(c.toString()); +- this.length += c.length; +- return true; +-}; +- +-TestWriter.prototype.end = function(c) { +- if (c) this.buffer.push(c.toString()); +- this.emit('results', this.buffer); +-} +- +-var r = new FSReadable(file); +-var w = new TestWriter(); +- +-w.on('results', function(res) { +- console.error(res, w.length); +- assert.equal(w.length, size); +- var l = 0; +- assert.deepEqual(res.map(function (c) { +- return c.length; +- }), expectLengths); +- console.log('ok'); +-}); +- +-r.pipe(w); +diff --git a/test/simple/test-stream2-httpclient-response-end.js b/test/simple/test-stream2-httpclient-response-end.js +deleted file mode 100644 +index 15cffc2..0000000 +--- a/test/simple/test-stream2-httpclient-response-end.js ++++ /dev/null +@@ -1,52 +0,0 @@ +-// Copyright Joyent, Inc. and other Node contributors. +-// +-// Permission is hereby granted, free of charge, to any person obtaining a +-// copy of this software and associated documentation files (the +-// "Software"), to deal in the Software without restriction, including +-// without limitation the rights to use, copy, modify, merge, publish, +-// distribute, sublicense, and/or sell copies of the Software, and to permit +-// persons to whom the Software is furnished to do so, subject to the +-// following conditions: +-// +-// The above copyright notice and this permission notice shall be included +-// in all copies or substantial portions of the Software. +-// +-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +-// USE OR OTHER DEALINGS IN THE SOFTWARE. +- +-var common = require('../common.js'); +-var assert = require('assert'); +-var http = require('http'); +-var msg = 'Hello'; +-var readable_event = false; +-var end_event = false; +-var server = http.createServer(function(req, res) { +- res.writeHead(200, {'Content-Type': 'text/plain'}); +- res.end(msg); +-}).listen(common.PORT, function() { +- http.get({port: common.PORT}, function(res) { +- var data = ''; +- res.on('readable', function() { +- console.log('readable event'); +- readable_event = true; +- data += res.read(); +- }); +- res.on('end', function() { +- console.log('end event'); +- end_event = true; +- assert.strictEqual(msg, data); +- server.close(); +- }); +- }); +-}); +- +-process.on('exit', function() { +- assert(readable_event); +- assert(end_event); +-}); +- +diff --git a/test/simple/test-stream2-large-read-stall.js b/test/simple/test-stream2-large-read-stall.js +index 2fbfbca..667985b 100644 +--- a/test/simple/test-stream2-large-read-stall.js ++++ b/test/simple/test-stream2-large-read-stall.js +@@ -30,7 +30,7 @@ var PUSHSIZE = 20; + var PUSHCOUNT = 1000; + var HWM = 50; + +-var Readable = require('stream').Readable; ++var Readable = require('../../').Readable; + var r = new Readable({ + highWaterMark: HWM + }); +@@ -39,23 +39,23 @@ var rs = r._readableState; + r._read = push; + + r.on('readable', function() { +- console.error('>> readable'); ++ //console.error('>> readable'); + do { +- console.error(' > read(%d)', READSIZE); ++ //console.error(' > read(%d)', READSIZE); + var ret = r.read(READSIZE); +- console.error(' < %j (%d remain)', ret && ret.length, rs.length); ++ //console.error(' < %j (%d remain)', ret && ret.length, rs.length); + } while (ret && ret.length === READSIZE); + +- console.error('<< after read()', +- ret && ret.length, +- rs.needReadable, +- rs.length); ++ //console.error('<< after read()', ++ // ret && ret.length, ++ // rs.needReadable, ++ // rs.length); + }); + + var endEmitted = false; + r.on('end', function() { + endEmitted = true; +- console.error('end'); ++ //console.error('end'); + }); + + var pushes = 0; +@@ -64,11 +64,11 @@ function push() { + return; + + if (pushes++ === PUSHCOUNT) { +- console.error(' push(EOF)'); ++ //console.error(' push(EOF)'); + return r.push(null); + } + +- console.error(' push #%d', pushes); ++ //console.error(' push #%d', pushes); + if (r.push(new Buffer(PUSHSIZE))) + setTimeout(push); + } +diff --git a/test/simple/test-stream2-objects.js b/test/simple/test-stream2-objects.js +index 3e6931d..ff47d89 100644 +--- a/test/simple/test-stream2-objects.js ++++ b/test/simple/test-stream2-objects.js +@@ -21,8 +21,8 @@ + + + var common = require('../common.js'); +-var Readable = require('_stream_readable'); +-var Writable = require('_stream_writable'); ++var Readable = require('../../lib/_stream_readable'); ++var Writable = require('../../lib/_stream_writable'); + var assert = require('assert'); + + // tiny node-tap lookalike. +diff --git a/test/simple/test-stream2-pipe-error-handling.js b/test/simple/test-stream2-pipe-error-handling.js +index cf7531c..e3f3e4e 100644 +--- a/test/simple/test-stream2-pipe-error-handling.js ++++ b/test/simple/test-stream2-pipe-error-handling.js +@@ -21,7 +21,7 @@ + + var common = require('../common'); + var assert = require('assert'); +-var stream = require('stream'); ++var stream = require('../../'); + + (function testErrorListenerCatches() { + var count = 1000; +diff --git a/test/simple/test-stream2-pipe-error-once-listener.js b/test/simple/test-stream2-pipe-error-once-listener.js +index 5e8e3cb..53b2616 100755 +--- a/test/simple/test-stream2-pipe-error-once-listener.js ++++ b/test/simple/test-stream2-pipe-error-once-listener.js +@@ -24,7 +24,7 @@ var common = require('../common.js'); + var assert = require('assert'); + + var util = require('util'); +-var stream = require('stream'); ++var stream = require('../../'); + + + var Read = function() { +diff --git a/test/simple/test-stream2-push.js b/test/simple/test-stream2-push.js +index b63edc3..eb2b0e9 100644 +--- a/test/simple/test-stream2-push.js ++++ b/test/simple/test-stream2-push.js +@@ -20,7 +20,7 @@ + // USE OR OTHER DEALINGS IN THE SOFTWARE. + + var common = require('../common.js'); +-var stream = require('stream'); ++var stream = require('../../'); + var Readable = stream.Readable; + var Writable = stream.Writable; + var assert = require('assert'); +diff --git a/test/simple/test-stream2-read-sync-stack.js b/test/simple/test-stream2-read-sync-stack.js +index e8a7305..9740a47 100644 +--- a/test/simple/test-stream2-read-sync-stack.js ++++ b/test/simple/test-stream2-read-sync-stack.js +@@ -21,7 +21,7 @@ + + var common = require('../common'); + var assert = require('assert'); +-var Readable = require('stream').Readable; ++var Readable = require('../../').Readable; + var r = new Readable(); + var N = 256 * 1024; + +diff --git a/test/simple/test-stream2-readable-empty-buffer-no-eof.js b/test/simple/test-stream2-readable-empty-buffer-no-eof.js +index cd30178..4b1659d 100644 +--- a/test/simple/test-stream2-readable-empty-buffer-no-eof.js ++++ b/test/simple/test-stream2-readable-empty-buffer-no-eof.js +@@ -22,10 +22,9 @@ + var common = require('../common'); + var assert = require('assert'); + +-var Readable = require('stream').Readable; ++var Readable = require('../../').Readable; + + test1(); +-test2(); + + function test1() { + var r = new Readable(); +@@ -88,31 +87,3 @@ function test1() { + console.log('ok'); + }); + } +- +-function test2() { +- var r = new Readable({ encoding: 'base64' }); +- var reads = 5; +- r._read = function(n) { +- if (!reads--) +- return r.push(null); // EOF +- else +- return r.push(new Buffer('x')); +- }; +- +- var results = []; +- function flow() { +- var chunk; +- while (null !== (chunk = r.read())) +- results.push(chunk + ''); +- } +- r.on('readable', flow); +- r.on('end', function() { +- results.push('EOF'); +- }); +- flow(); +- +- process.on('exit', function() { +- assert.deepEqual(results, [ 'eHh4', 'eHg=', 'EOF' ]); +- console.log('ok'); +- }); +-} +diff --git a/test/simple/test-stream2-readable-from-list.js b/test/simple/test-stream2-readable-from-list.js +index 7c96ffe..04a96f5 100644 +--- a/test/simple/test-stream2-readable-from-list.js ++++ b/test/simple/test-stream2-readable-from-list.js +@@ -21,7 +21,7 @@ + + var assert = require('assert'); + var common = require('../common.js'); +-var fromList = require('_stream_readable')._fromList; ++var fromList = require('../../lib/_stream_readable')._fromList; + + // tiny node-tap lookalike. + var tests = []; +diff --git a/test/simple/test-stream2-readable-legacy-drain.js b/test/simple/test-stream2-readable-legacy-drain.js +index 675da8e..51fd3d5 100644 +--- a/test/simple/test-stream2-readable-legacy-drain.js ++++ b/test/simple/test-stream2-readable-legacy-drain.js +@@ -22,7 +22,7 @@ + var common = require('../common'); + var assert = require('assert'); + +-var Stream = require('stream'); ++var Stream = require('../../'); + var Readable = Stream.Readable; + + var r = new Readable(); +diff --git a/test/simple/test-stream2-readable-non-empty-end.js b/test/simple/test-stream2-readable-non-empty-end.js +index 7314ae7..c971898 100644 +--- a/test/simple/test-stream2-readable-non-empty-end.js ++++ b/test/simple/test-stream2-readable-non-empty-end.js +@@ -21,7 +21,7 @@ + + var assert = require('assert'); + var common = require('../common.js'); +-var Readable = require('_stream_readable'); ++var Readable = require('../../lib/_stream_readable'); + + var len = 0; + var chunks = new Array(10); +diff --git a/test/simple/test-stream2-readable-wrap-empty.js b/test/simple/test-stream2-readable-wrap-empty.js +index 2e5cf25..fd8a3dc 100644 +--- a/test/simple/test-stream2-readable-wrap-empty.js ++++ b/test/simple/test-stream2-readable-wrap-empty.js +@@ -22,7 +22,7 @@ + var common = require('../common'); + var assert = require('assert'); + +-var Readable = require('_stream_readable'); ++var Readable = require('../../lib/_stream_readable'); + var EE = require('events').EventEmitter; + + var oldStream = new EE(); +diff --git a/test/simple/test-stream2-readable-wrap.js b/test/simple/test-stream2-readable-wrap.js +index 90eea01..6b177f7 100644 +--- a/test/simple/test-stream2-readable-wrap.js ++++ b/test/simple/test-stream2-readable-wrap.js +@@ -22,8 +22,8 @@ + var common = require('../common'); + var assert = require('assert'); + +-var Readable = require('_stream_readable'); +-var Writable = require('_stream_writable'); ++var Readable = require('../../lib/_stream_readable'); ++var Writable = require('../../lib/_stream_writable'); + var EE = require('events').EventEmitter; + + var testRuns = 0, completedRuns = 0; +diff --git a/test/simple/test-stream2-set-encoding.js b/test/simple/test-stream2-set-encoding.js +index 5d2c32a..685531b 100644 +--- a/test/simple/test-stream2-set-encoding.js ++++ b/test/simple/test-stream2-set-encoding.js +@@ -22,7 +22,7 @@ + + var common = require('../common.js'); + var assert = require('assert'); +-var R = require('_stream_readable'); ++var R = require('../../lib/_stream_readable'); + var util = require('util'); + + // tiny node-tap lookalike. +diff --git a/test/simple/test-stream2-transform.js b/test/simple/test-stream2-transform.js +index 9c9ddd8..a0cacc6 100644 +--- a/test/simple/test-stream2-transform.js ++++ b/test/simple/test-stream2-transform.js +@@ -21,8 +21,8 @@ + + var assert = require('assert'); + var common = require('../common.js'); +-var PassThrough = require('_stream_passthrough'); +-var Transform = require('_stream_transform'); ++var PassThrough = require('../../').PassThrough; ++var Transform = require('../../').Transform; + + // tiny node-tap lookalike. + var tests = []; +diff --git a/test/simple/test-stream2-unpipe-drain.js b/test/simple/test-stream2-unpipe-drain.js +index d66dc3c..365b327 100644 +--- a/test/simple/test-stream2-unpipe-drain.js ++++ b/test/simple/test-stream2-unpipe-drain.js +@@ -22,7 +22,7 @@ + + var common = require('../common.js'); + var assert = require('assert'); +-var stream = require('stream'); ++var stream = require('../../'); + var crypto = require('crypto'); + + var util = require('util'); +diff --git a/test/simple/test-stream2-unpipe-leak.js b/test/simple/test-stream2-unpipe-leak.js +index 99f8746..17c92ae 100644 +--- a/test/simple/test-stream2-unpipe-leak.js ++++ b/test/simple/test-stream2-unpipe-leak.js +@@ -22,7 +22,7 @@ + + var common = require('../common.js'); + var assert = require('assert'); +-var stream = require('stream'); ++var stream = require('../../'); + + var chunk = new Buffer('hallo'); + +diff --git a/test/simple/test-stream2-writable.js b/test/simple/test-stream2-writable.js +index 704100c..209c3a6 100644 +--- a/test/simple/test-stream2-writable.js ++++ b/test/simple/test-stream2-writable.js +@@ -20,8 +20,8 @@ + // USE OR OTHER DEALINGS IN THE SOFTWARE. + + var common = require('../common.js'); +-var W = require('_stream_writable'); +-var D = require('_stream_duplex'); ++var W = require('../../').Writable; ++var D = require('../../').Duplex; + var assert = require('assert'); + + var util = require('util'); +diff --git a/test/simple/test-stream3-pause-then-read.js b/test/simple/test-stream3-pause-then-read.js +index b91bde3..2f72c15 100644 +--- a/test/simple/test-stream3-pause-then-read.js ++++ b/test/simple/test-stream3-pause-then-read.js +@@ -22,7 +22,7 @@ + var common = require('../common'); + var assert = require('assert'); + +-var stream = require('stream'); ++var stream = require('../../'); + var Readable = stream.Readable; + var Writable = stream.Writable; + diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/fs.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/fs.js new file mode 100644 index 0000000..a663af8 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/fs.js @@ -0,0 +1,1705 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// Maintainers, keep in mind that octal literals are not allowed +// in strict mode. Use the decimal value and add a comment with +// the octal value. Example: +// +// var mode = 438; /* mode=0666 */ + +var util = require('util'); +var pathModule = require('path'); + +var binding = process.binding('fs'); +var constants = process.binding('constants'); +var fs = exports; +var Stream = require('stream').Stream; +var EventEmitter = require('events').EventEmitter; + +var Readable = require('./lib/_stream_readable.js'); +var Writable = require('./lib/_stream_writable.js'); + +var kMinPoolSpace = 128; +var kPoolSize = 40 * 1024; + +var O_APPEND = constants.O_APPEND || 0; +var O_CREAT = constants.O_CREAT || 0; +var O_DIRECTORY = constants.O_DIRECTORY || 0; +var O_EXCL = constants.O_EXCL || 0; +var O_NOCTTY = constants.O_NOCTTY || 0; +var O_NOFOLLOW = constants.O_NOFOLLOW || 0; +var O_RDONLY = constants.O_RDONLY || 0; +var O_RDWR = constants.O_RDWR || 0; +var O_SYMLINK = constants.O_SYMLINK || 0; +var O_SYNC = constants.O_SYNC || 0; +var O_TRUNC = constants.O_TRUNC || 0; +var O_WRONLY = constants.O_WRONLY || 0; + +var isWindows = process.platform === 'win32'; + +var DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG); + +function rethrow() { + // Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and + // is fairly slow to generate. + if (DEBUG) { + var backtrace = new Error; + return function(err) { + if (err) { + backtrace.message = err.message; + err = backtrace; + throw err; + } + }; + } + + return function(err) { + if (err) { + throw err; // Forgot a callback but don't know where? Use NODE_DEBUG=fs + } + }; +} + +function maybeCallback(cb) { + return typeof cb === 'function' ? cb : rethrow(); +} + +// Ensure that callbacks run in the global context. Only use this function +// for callbacks that are passed to the binding layer, callbacks that are +// invoked from JS already run in the proper scope. +function makeCallback(cb) { + if (typeof cb !== 'function') { + return rethrow(); + } + + return function() { + return cb.apply(null, arguments); + }; +} + +function assertEncoding(encoding) { + if (encoding && !Buffer.isEncoding(encoding)) { + throw new Error('Unknown encoding: ' + encoding); + } +} + +function nullCheck(path, callback) { + if (('' + path).indexOf('\u0000') !== -1) { + var er = new Error('Path must be a string without null bytes.'); + if (!callback) + throw er; + process.nextTick(function() { + callback(er); + }); + return false; + } + return true; +} + +fs.Stats = binding.Stats; + +fs.Stats.prototype._checkModeProperty = function(property) { + return ((this.mode & constants.S_IFMT) === property); +}; + +fs.Stats.prototype.isDirectory = function() { + return this._checkModeProperty(constants.S_IFDIR); +}; + +fs.Stats.prototype.isFile = function() { + return this._checkModeProperty(constants.S_IFREG); +}; + +fs.Stats.prototype.isBlockDevice = function() { + return this._checkModeProperty(constants.S_IFBLK); +}; + +fs.Stats.prototype.isCharacterDevice = function() { + return this._checkModeProperty(constants.S_IFCHR); +}; + +fs.Stats.prototype.isSymbolicLink = function() { + return this._checkModeProperty(constants.S_IFLNK); +}; + +fs.Stats.prototype.isFIFO = function() { + return this._checkModeProperty(constants.S_IFIFO); +}; + +fs.Stats.prototype.isSocket = function() { + return this._checkModeProperty(constants.S_IFSOCK); +}; + +fs.exists = function(path, callback) { + if (!nullCheck(path, cb)) return; + binding.stat(pathModule._makeLong(path), cb); + function cb(err, stats) { + if (callback) callback(err ? false : true); + } +}; + +fs.existsSync = function(path) { + try { + nullCheck(path); + binding.stat(pathModule._makeLong(path)); + return true; + } catch (e) { + return false; + } +}; + +fs.readFile = function(path, encoding_) { + var encoding = typeof(encoding_) === 'string' ? encoding_ : null; + var callback = maybeCallback(arguments[arguments.length - 1]); + + assertEncoding(encoding); + + // first, stat the file, so we know the size. + var size; + var buffer; // single buffer with file data + var buffers; // list for when size is unknown + var pos = 0; + var fd; + + fs.open(path, constants.O_RDONLY, 438 /*=0666*/, function(er, fd_) { + if (er) return callback(er); + fd = fd_; + + fs.fstat(fd, function(er, st) { + if (er) return callback(er); + size = st.size; + if (size === 0) { + // the kernel lies about many files. + // Go ahead and try to read some bytes. + buffers = []; + return read(); + } + + buffer = new Buffer(size); + read(); + }); + }); + + function read() { + if (size === 0) { + buffer = new Buffer(8192); + fs.read(fd, buffer, 0, 8192, -1, afterRead); + } else { + fs.read(fd, buffer, pos, size - pos, -1, afterRead); + } + } + + function afterRead(er, bytesRead) { + if (er) { + return fs.close(fd, function(er2) { + return callback(er); + }); + } + + if (bytesRead === 0) { + return close(); + } + + pos += bytesRead; + if (size !== 0) { + if (pos === size) close(); + else read(); + } else { + // unknown size, just read until we don't get bytes. + buffers.push(buffer.slice(0, bytesRead)); + read(); + } + } + + function close() { + fs.close(fd, function(er) { + if (size === 0) { + // collected the data into the buffers list. + buffer = Buffer.concat(buffers, pos); + } else if (pos < size) { + buffer = buffer.slice(0, pos); + } + + if (encoding) buffer = buffer.toString(encoding); + return callback(er, buffer); + }); + } +}; + +fs.readFileSync = function(path, encoding) { + assertEncoding(encoding); + + var fd = fs.openSync(path, constants.O_RDONLY, 438 /*=0666*/); + + var size; + var threw = true; + try { + size = fs.fstatSync(fd).size; + threw = false; + } finally { + if (threw) fs.closeSync(fd); + } + + var pos = 0; + var buffer; // single buffer with file data + var buffers; // list for when size is unknown + + if (size === 0) { + buffers = []; + } else { + buffer = new Buffer(size); + } + + var done = false; + while (!done) { + var threw = true; + try { + if (size !== 0) { + var bytesRead = fs.readSync(fd, buffer, pos, size - pos); + } else { + // the kernel lies about many files. + // Go ahead and try to read some bytes. + buffer = new Buffer(8192); + var bytesRead = fs.readSync(fd, buffer, 0, 8192); + if (bytesRead) { + buffers.push(buffer.slice(0, bytesRead)); + } + } + threw = false; + } finally { + if (threw) fs.closeSync(fd); + } + + pos += bytesRead; + done = (bytesRead === 0) || (size !== 0 && pos >= size); + } + + fs.closeSync(fd); + + if (size === 0) { + // data was collected into the buffers list. + buffer = Buffer.concat(buffers, pos); + } else if (pos < size) { + buffer = buffer.slice(0, pos); + } + + if (encoding) buffer = buffer.toString(encoding); + return buffer; +}; + + +// Used by binding.open and friends +function stringToFlags(flag) { + // Only mess with strings + if (typeof flag !== 'string') { + return flag; + } + + // O_EXCL is mandated by POSIX, Windows supports it too. + // Let's add a check anyway, just in case. + if (!O_EXCL && ~flag.indexOf('x')) { + throw errnoException('ENOSYS', 'fs.open(O_EXCL)'); + } + + switch (flag) { + case 'r' : return O_RDONLY; + case 'rs' : return O_RDONLY | O_SYNC; + case 'r+' : return O_RDWR; + case 'rs+' : return O_RDWR | O_SYNC; + + case 'w' : return O_TRUNC | O_CREAT | O_WRONLY; + case 'wx' : // fall through + case 'xw' : return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL; + + case 'w+' : return O_TRUNC | O_CREAT | O_RDWR; + case 'wx+': // fall through + case 'xw+': return O_TRUNC | O_CREAT | O_RDWR | O_EXCL; + + case 'a' : return O_APPEND | O_CREAT | O_WRONLY; + case 'ax' : // fall through + case 'xa' : return O_APPEND | O_CREAT | O_WRONLY | O_EXCL; + + case 'a+' : return O_APPEND | O_CREAT | O_RDWR; + case 'ax+': // fall through + case 'xa+': return O_APPEND | O_CREAT | O_RDWR | O_EXCL; + } + + throw new Error('Unknown file open flag: ' + flag); +} + +// exported but hidden, only used by test/simple/test-fs-open-flags.js +Object.defineProperty(exports, '_stringToFlags', { + enumerable: false, + value: stringToFlags +}); + + +// Yes, the follow could be easily DRYed up but I provide the explicit +// list to make the arguments clear. + +fs.close = function(fd, callback) { + binding.close(fd, makeCallback(callback)); +}; + +fs.closeSync = function(fd) { + return binding.close(fd); +}; + +function modeNum(m, def) { + switch (typeof m) { + case 'number': return m; + case 'string': return parseInt(m, 8); + default: + if (def) { + return modeNum(def); + } else { + return undefined; + } + } +} + +fs.open = function(path, flags, mode, callback) { + callback = makeCallback(arguments[arguments.length - 1]); + mode = modeNum(mode, 438 /*=0666*/); + + if (!nullCheck(path, callback)) return; + binding.open(pathModule._makeLong(path), + stringToFlags(flags), + mode, + callback); +}; + +fs.openSync = function(path, flags, mode) { + mode = modeNum(mode, 438 /*=0666*/); + nullCheck(path); + return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode); +}; + +fs.read = function(fd, buffer, offset, length, position, callback) { + if (!Buffer.isBuffer(buffer)) { + // legacy string interface (fd, length, position, encoding, callback) + var cb = arguments[4], + encoding = arguments[3]; + + assertEncoding(encoding); + + position = arguments[2]; + length = arguments[1]; + buffer = new Buffer(length); + offset = 0; + + callback = function(err, bytesRead) { + if (!cb) return; + + var str = (bytesRead > 0) ? buffer.toString(encoding, 0, bytesRead) : ''; + + (cb)(err, str, bytesRead); + }; + } + + function wrapper(err, bytesRead) { + // Retain a reference to buffer so that it can't be GC'ed too soon. + callback && callback(err, bytesRead || 0, buffer); + } + + binding.read(fd, buffer, offset, length, position, wrapper); +}; + +fs.readSync = function(fd, buffer, offset, length, position) { + var legacy = false; + if (!Buffer.isBuffer(buffer)) { + // legacy string interface (fd, length, position, encoding, callback) + legacy = true; + var encoding = arguments[3]; + + assertEncoding(encoding); + + position = arguments[2]; + length = arguments[1]; + buffer = new Buffer(length); + + offset = 0; + } + + var r = binding.read(fd, buffer, offset, length, position); + if (!legacy) { + return r; + } + + var str = (r > 0) ? buffer.toString(encoding, 0, r) : ''; + return [str, r]; +}; + +fs.write = function(fd, buffer, offset, length, position, callback) { + if (!Buffer.isBuffer(buffer)) { + // legacy string interface (fd, data, position, encoding, callback) + callback = arguments[4]; + position = arguments[2]; + assertEncoding(arguments[3]); + + buffer = new Buffer('' + arguments[1], arguments[3]); + offset = 0; + length = buffer.length; + } + + if (!length) { + if (typeof callback == 'function') { + process.nextTick(function() { + callback(undefined, 0); + }); + } + return; + } + + callback = maybeCallback(callback); + + function wrapper(err, written) { + // Retain a reference to buffer so that it can't be GC'ed too soon. + callback(err, written || 0, buffer); + } + + binding.write(fd, buffer, offset, length, position, wrapper); +}; + +fs.writeSync = function(fd, buffer, offset, length, position) { + if (!Buffer.isBuffer(buffer)) { + // legacy string interface (fd, data, position, encoding) + position = arguments[2]; + assertEncoding(arguments[3]); + + buffer = new Buffer('' + arguments[1], arguments[3]); + offset = 0; + length = buffer.length; + } + if (!length) return 0; + + return binding.write(fd, buffer, offset, length, position); +}; + +fs.rename = function(oldPath, newPath, callback) { + callback = makeCallback(callback); + if (!nullCheck(oldPath, callback)) return; + if (!nullCheck(newPath, callback)) return; + binding.rename(pathModule._makeLong(oldPath), + pathModule._makeLong(newPath), + callback); +}; + +fs.renameSync = function(oldPath, newPath) { + nullCheck(oldPath); + nullCheck(newPath); + return binding.rename(pathModule._makeLong(oldPath), + pathModule._makeLong(newPath)); +}; + +fs.truncate = function(path, len, callback) { + if (typeof path === 'number') { + // legacy + return fs.ftruncate(path, len, callback); + } + if (typeof len === 'function') { + callback = len; + len = 0; + } else if (typeof len === 'undefined') { + len = 0; + } + callback = maybeCallback(callback); + fs.open(path, 'w', function(er, fd) { + if (er) return callback(er); + binding.ftruncate(fd, len, function(er) { + fs.close(fd, function(er2) { + callback(er || er2); + }); + }); + }); +}; + +fs.truncateSync = function(path, len) { + if (typeof path === 'number') { + // legacy + return fs.ftruncateSync(path, len); + } + if (typeof len === 'undefined') { + len = 0; + } + // allow error to be thrown, but still close fd. + var fd = fs.openSync(path, 'w'); + try { + var ret = fs.ftruncateSync(fd, len); + } finally { + fs.closeSync(fd); + } + return ret; +}; + +fs.ftruncate = function(fd, len, callback) { + if (typeof len === 'function') { + callback = len; + len = 0; + } else if (typeof len === 'undefined') { + len = 0; + } + binding.ftruncate(fd, len, makeCallback(callback)); +}; + +fs.ftruncateSync = function(fd, len) { + if (typeof len === 'undefined') { + len = 0; + } + return binding.ftruncate(fd, len); +}; + +fs.rmdir = function(path, callback) { + callback = makeCallback(callback); + if (!nullCheck(path, callback)) return; + binding.rmdir(pathModule._makeLong(path), callback); +}; + +fs.rmdirSync = function(path) { + nullCheck(path); + return binding.rmdir(pathModule._makeLong(path)); +}; + +fs.fdatasync = function(fd, callback) { + binding.fdatasync(fd, makeCallback(callback)); +}; + +fs.fdatasyncSync = function(fd) { + return binding.fdatasync(fd); +}; + +fs.fsync = function(fd, callback) { + binding.fsync(fd, makeCallback(callback)); +}; + +fs.fsyncSync = function(fd) { + return binding.fsync(fd); +}; + +fs.mkdir = function(path, mode, callback) { + if (typeof mode === 'function') callback = mode; + callback = makeCallback(callback); + if (!nullCheck(path, callback)) return; + binding.mkdir(pathModule._makeLong(path), + modeNum(mode, 511 /*=0777*/), + callback); +}; + +fs.mkdirSync = function(path, mode) { + nullCheck(path); + return binding.mkdir(pathModule._makeLong(path), + modeNum(mode, 511 /*=0777*/)); +}; + +fs.sendfile = function(outFd, inFd, inOffset, length, callback) { + binding.sendfile(outFd, inFd, inOffset, length, makeCallback(callback)); +}; + +fs.sendfileSync = function(outFd, inFd, inOffset, length) { + return binding.sendfile(outFd, inFd, inOffset, length); +}; + +fs.readdir = function(path, callback) { + callback = makeCallback(callback); + if (!nullCheck(path, callback)) return; + binding.readdir(pathModule._makeLong(path), callback); +}; + +fs.readdirSync = function(path) { + nullCheck(path); + return binding.readdir(pathModule._makeLong(path)); +}; + +fs.fstat = function(fd, callback) { + binding.fstat(fd, makeCallback(callback)); +}; + +fs.lstat = function(path, callback) { + callback = makeCallback(callback); + if (!nullCheck(path, callback)) return; + binding.lstat(pathModule._makeLong(path), callback); +}; + +fs.stat = function(path, callback) { + callback = makeCallback(callback); + if (!nullCheck(path, callback)) return; + binding.stat(pathModule._makeLong(path), callback); +}; + +fs.fstatSync = function(fd) { + return binding.fstat(fd); +}; + +fs.lstatSync = function(path) { + nullCheck(path); + return binding.lstat(pathModule._makeLong(path)); +}; + +fs.statSync = function(path) { + nullCheck(path); + return binding.stat(pathModule._makeLong(path)); +}; + +fs.readlink = function(path, callback) { + callback = makeCallback(callback); + if (!nullCheck(path, callback)) return; + binding.readlink(pathModule._makeLong(path), callback); +}; + +fs.readlinkSync = function(path) { + nullCheck(path); + return binding.readlink(pathModule._makeLong(path)); +}; + +function preprocessSymlinkDestination(path, type) { + if (!isWindows) { + // No preprocessing is needed on Unix. + return path; + } else if (type === 'junction') { + // Junctions paths need to be absolute and \\?\-prefixed. + return pathModule._makeLong(path); + } else { + // Windows symlinks don't tolerate forward slashes. + return ('' + path).replace(/\//g, '\\'); + } +} + +fs.symlink = function(destination, path, type_, callback) { + var type = (typeof type_ === 'string' ? type_ : null); + var callback = makeCallback(arguments[arguments.length - 1]); + + if (!nullCheck(destination, callback)) return; + if (!nullCheck(path, callback)) return; + + binding.symlink(preprocessSymlinkDestination(destination, type), + pathModule._makeLong(path), + type, + callback); +}; + +fs.symlinkSync = function(destination, path, type) { + type = (typeof type === 'string' ? type : null); + + nullCheck(destination); + nullCheck(path); + + return binding.symlink(preprocessSymlinkDestination(destination, type), + pathModule._makeLong(path), + type); +}; + +fs.link = function(srcpath, dstpath, callback) { + callback = makeCallback(callback); + if (!nullCheck(srcpath, callback)) return; + if (!nullCheck(dstpath, callback)) return; + + binding.link(pathModule._makeLong(srcpath), + pathModule._makeLong(dstpath), + callback); +}; + +fs.linkSync = function(srcpath, dstpath) { + nullCheck(srcpath); + nullCheck(dstpath); + return binding.link(pathModule._makeLong(srcpath), + pathModule._makeLong(dstpath)); +}; + +fs.unlink = function(path, callback) { + callback = makeCallback(callback); + if (!nullCheck(path, callback)) return; + binding.unlink(pathModule._makeLong(path), callback); +}; + +fs.unlinkSync = function(path) { + nullCheck(path); + return binding.unlink(pathModule._makeLong(path)); +}; + +fs.fchmod = function(fd, mode, callback) { + binding.fchmod(fd, modeNum(mode), makeCallback(callback)); +}; + +fs.fchmodSync = function(fd, mode) { + return binding.fchmod(fd, modeNum(mode)); +}; + +if (constants.hasOwnProperty('O_SYMLINK')) { + fs.lchmod = function(path, mode, callback) { + callback = maybeCallback(callback); + fs.open(path, constants.O_WRONLY | constants.O_SYMLINK, function(err, fd) { + if (err) { + callback(err); + return; + } + // prefer to return the chmod error, if one occurs, + // but still try to close, and report closing errors if they occur. + fs.fchmod(fd, mode, function(err) { + fs.close(fd, function(err2) { + callback(err || err2); + }); + }); + }); + }; + + fs.lchmodSync = function(path, mode) { + var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK); + + // prefer to return the chmod error, if one occurs, + // but still try to close, and report closing errors if they occur. + var err, err2; + try { + var ret = fs.fchmodSync(fd, mode); + } catch (er) { + err = er; + } + try { + fs.closeSync(fd); + } catch (er) { + err2 = er; + } + if (err || err2) throw (err || err2); + return ret; + }; +} + + +fs.chmod = function(path, mode, callback) { + callback = makeCallback(callback); + if (!nullCheck(path, callback)) return; + binding.chmod(pathModule._makeLong(path), + modeNum(mode), + callback); +}; + +fs.chmodSync = function(path, mode) { + nullCheck(path); + return binding.chmod(pathModule._makeLong(path), modeNum(mode)); +}; + +if (constants.hasOwnProperty('O_SYMLINK')) { + fs.lchown = function(path, uid, gid, callback) { + callback = maybeCallback(callback); + fs.open(path, constants.O_WRONLY | constants.O_SYMLINK, function(err, fd) { + if (err) { + callback(err); + return; + } + fs.fchown(fd, uid, gid, callback); + }); + }; + + fs.lchownSync = function(path, uid, gid) { + var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK); + return fs.fchownSync(fd, uid, gid); + }; +} + +fs.fchown = function(fd, uid, gid, callback) { + binding.fchown(fd, uid, gid, makeCallback(callback)); +}; + +fs.fchownSync = function(fd, uid, gid) { + return binding.fchown(fd, uid, gid); +}; + +fs.chown = function(path, uid, gid, callback) { + callback = makeCallback(callback); + if (!nullCheck(path, callback)) return; + binding.chown(pathModule._makeLong(path), uid, gid, callback); +}; + +fs.chownSync = function(path, uid, gid) { + nullCheck(path); + return binding.chown(pathModule._makeLong(path), uid, gid); +}; + +// converts Date or number to a fractional UNIX timestamp +function toUnixTimestamp(time) { + if (typeof time == 'number') { + return time; + } + if (time instanceof Date) { + // convert to 123.456 UNIX timestamp + return time.getTime() / 1000; + } + throw new Error('Cannot parse time: ' + time); +} + +// exported for unit tests, not for public consumption +fs._toUnixTimestamp = toUnixTimestamp; + +fs.utimes = function(path, atime, mtime, callback) { + callback = makeCallback(callback); + if (!nullCheck(path, callback)) return; + binding.utimes(pathModule._makeLong(path), + toUnixTimestamp(atime), + toUnixTimestamp(mtime), + callback); +}; + +fs.utimesSync = function(path, atime, mtime) { + nullCheck(path); + atime = toUnixTimestamp(atime); + mtime = toUnixTimestamp(mtime); + binding.utimes(pathModule._makeLong(path), atime, mtime); +}; + +fs.futimes = function(fd, atime, mtime, callback) { + atime = toUnixTimestamp(atime); + mtime = toUnixTimestamp(mtime); + binding.futimes(fd, atime, mtime, makeCallback(callback)); +}; + +fs.futimesSync = function(fd, atime, mtime) { + atime = toUnixTimestamp(atime); + mtime = toUnixTimestamp(mtime); + binding.futimes(fd, atime, mtime); +}; + +function writeAll(fd, buffer, offset, length, position, callback) { + callback = maybeCallback(arguments[arguments.length - 1]); + + // write(fd, buffer, offset, length, position, callback) + fs.write(fd, buffer, offset, length, position, function(writeErr, written) { + if (writeErr) { + fs.close(fd, function() { + if (callback) callback(writeErr); + }); + } else { + if (written === length) { + fs.close(fd, callback); + } else { + offset += written; + length -= written; + position += written; + writeAll(fd, buffer, offset, length, position, callback); + } + } + }); +} + +fs.writeFile = function(path, data, encoding_, callback) { + var encoding = (typeof(encoding_) == 'string' ? encoding_ : 'utf8'); + assertEncoding(encoding); + + callback = maybeCallback(arguments[arguments.length - 1]); + fs.open(path, 'w', 438 /*=0666*/, function(openErr, fd) { + if (openErr) { + if (callback) callback(openErr); + } else { + var buffer = Buffer.isBuffer(data) ? data : new Buffer('' + data, + encoding); + writeAll(fd, buffer, 0, buffer.length, 0, callback); + } + }); +}; + +fs.writeFileSync = function(path, data, encoding) { + assertEncoding(encoding); + + var fd = fs.openSync(path, 'w'); + if (!Buffer.isBuffer(data)) { + data = new Buffer('' + data, encoding || 'utf8'); + } + var written = 0; + var length = data.length; + try { + while (written < length) { + written += fs.writeSync(fd, data, written, length - written, written); + } + } finally { + fs.closeSync(fd); + } +}; + +fs.appendFile = function(path, data, encoding_, callback) { + var encoding = (typeof(encoding_) == 'string' ? encoding_ : 'utf8'); + assertEncoding(encoding); + + callback = maybeCallback(arguments[arguments.length - 1]); + + fs.open(path, 'a', 438 /*=0666*/, function(err, fd) { + if (err) return callback(err); + var buffer = Buffer.isBuffer(data) ? data : new Buffer('' + data, encoding); + writeAll(fd, buffer, 0, buffer.length, null, callback); + }); +}; + +fs.appendFileSync = function(path, data, encoding) { + assertEncoding(encoding); + + var fd = fs.openSync(path, 'a'); + if (!Buffer.isBuffer(data)) { + data = new Buffer('' + data, encoding || 'utf8'); + } + var written = 0; + var position = null; + var length = data.length; + + try { + while (written < length) { + written += fs.writeSync(fd, data, written, length - written, position); + position += written; // XXX not safe with multiple concurrent writers? + } + } finally { + fs.closeSync(fd); + } +}; + +function errnoException(errorno, syscall) { + // TODO make this more compatible with ErrnoException from src/node.cc + // Once all of Node is using this function the ErrnoException from + // src/node.cc should be removed. + var e = new Error(syscall + ' ' + errorno); + e.errno = e.code = errorno; + e.syscall = syscall; + return e; +} + + +function FSWatcher() { + EventEmitter.call(this); + + var self = this; + var FSEvent = process.binding('fs_event_wrap').FSEvent; + this._handle = new FSEvent(); + this._handle.owner = this; + + this._handle.onchange = function(status, event, filename) { + if (status) { + self._handle.close(); + self.emit('error', errnoException(errno, 'watch')); + } else { + self.emit('change', event, filename); + } + }; +} +util.inherits(FSWatcher, EventEmitter); + +FSWatcher.prototype.start = function(filename, persistent) { + nullCheck(filename); + var r = this._handle.start(pathModule._makeLong(filename), persistent); + + if (r) { + this._handle.close(); + throw errnoException(errno, 'watch'); + } +}; + +FSWatcher.prototype.close = function() { + this._handle.close(); +}; + +fs.watch = function(filename) { + nullCheck(filename); + var watcher; + var options; + var listener; + + if ('object' == typeof arguments[1]) { + options = arguments[1]; + listener = arguments[2]; + } else { + options = {}; + listener = arguments[1]; + } + + if (options.persistent === undefined) options.persistent = true; + + watcher = new FSWatcher(); + watcher.start(filename, options.persistent); + + if (listener) { + watcher.addListener('change', listener); + } + + return watcher; +}; + + +// Stat Change Watchers + +function StatWatcher() { + EventEmitter.call(this); + + var self = this; + this._handle = new binding.StatWatcher(); + + // uv_fs_poll is a little more powerful than ev_stat but we curb it for + // the sake of backwards compatibility + var oldStatus = -1; + + this._handle.onchange = function(current, previous, newStatus) { + if (oldStatus === -1 && + newStatus === -1 && + current.nlink === previous.nlink) return; + + oldStatus = newStatus; + self.emit('change', current, previous); + }; + + this._handle.onstop = function() { + self.emit('stop'); + }; +} +util.inherits(StatWatcher, EventEmitter); + + +StatWatcher.prototype.start = function(filename, persistent, interval) { + nullCheck(filename); + this._handle.start(pathModule._makeLong(filename), persistent, interval); +}; + + +StatWatcher.prototype.stop = function() { + this._handle.stop(); +}; + + +var statWatchers = {}; +function inStatWatchers(filename) { + return Object.prototype.hasOwnProperty.call(statWatchers, filename) && + statWatchers[filename]; +} + + +fs.watchFile = function(filename) { + nullCheck(filename); + var stat; + var listener; + + var options = { + // Poll interval in milliseconds. 5007 is what libev used to use. It's + // a little on the slow side but let's stick with it for now to keep + // behavioral changes to a minimum. + interval: 5007, + persistent: true + }; + + if ('object' == typeof arguments[1]) { + options = util._extend(options, arguments[1]); + listener = arguments[2]; + } else { + listener = arguments[1]; + } + + if (!listener) { + throw new Error('watchFile requires a listener function'); + } + + if (inStatWatchers(filename)) { + stat = statWatchers[filename]; + } else { + stat = statWatchers[filename] = new StatWatcher(); + stat.start(filename, options.persistent, options.interval); + } + stat.addListener('change', listener); + return stat; +}; + +fs.unwatchFile = function(filename, listener) { + nullCheck(filename); + if (!inStatWatchers(filename)) return; + + var stat = statWatchers[filename]; + + if (typeof listener === 'function') { + stat.removeListener('change', listener); + } else { + stat.removeAllListeners('change'); + } + + if (stat.listeners('change').length === 0) { + stat.stop(); + statWatchers[filename] = undefined; + } +}; + +// Realpath +// Not using realpath(2) because it's bad. +// See: http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html + +var normalize = pathModule.normalize; + +// Regexp that finds the next partion of a (partial) path +// result is [base_with_slash, base], e.g. ['somedir/', 'somedir'] +if (isWindows) { + var nextPartRe = /(.*?)(?:[\/\\]+|$)/g; +} else { + var nextPartRe = /(.*?)(?:[\/]+|$)/g; +} + +// Regex to find the device root, including trailing slash. E.g. 'c:\\'. +if (isWindows) { + var splitRootRe = /^(?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?[\\\/]*/; +} else { + var splitRootRe = /^[\/]*/; +} + +fs.realpathSync = function realpathSync(p, cache) { + // make p is absolute + p = pathModule.resolve(p); + + if (cache && Object.prototype.hasOwnProperty.call(cache, p)) { + return cache[p]; + } + + var original = p, + seenLinks = {}, + knownHard = {}; + + // current character position in p + var pos; + // the partial path so far, including a trailing slash if any + var current; + // the partial path without a trailing slash (except when pointing at a root) + var base; + // the partial path scanned in the previous round, with slash + var previous; + + start(); + + function start() { + // Skip over roots + var m = splitRootRe.exec(p); + pos = m[0].length; + current = m[0]; + base = m[0]; + previous = ''; + + // On windows, check that the root exists. On unix there is no need. + if (isWindows && !knownHard[base]) { + fs.lstatSync(base); + knownHard[base] = true; + } + } + + // walk down the path, swapping out linked pathparts for their real + // values + // NB: p.length changes. + while (pos < p.length) { + // find the next part + nextPartRe.lastIndex = pos; + var result = nextPartRe.exec(p); + previous = current; + current += result[0]; + base = previous + result[1]; + pos = nextPartRe.lastIndex; + + // continue if not a symlink + if (knownHard[base] || (cache && cache[base] === base)) { + continue; + } + + var resolvedLink; + if (cache && Object.prototype.hasOwnProperty.call(cache, base)) { + // some known symbolic link. no need to stat again. + resolvedLink = cache[base]; + } else { + var stat = fs.lstatSync(base); + if (!stat.isSymbolicLink()) { + knownHard[base] = true; + if (cache) cache[base] = base; + continue; + } + + // read the link if it wasn't read before + // dev/ino always return 0 on windows, so skip the check. + var linkTarget = null; + if (!isWindows) { + var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); + if (seenLinks.hasOwnProperty(id)) { + linkTarget = seenLinks[id]; + } + } + if (linkTarget === null) { + fs.statSync(base); + linkTarget = fs.readlinkSync(base); + } + resolvedLink = pathModule.resolve(previous, linkTarget); + // track this, if given a cache. + if (cache) cache[base] = resolvedLink; + if (!isWindows) seenLinks[id] = linkTarget; + } + + // resolve the link, then start over + p = pathModule.resolve(resolvedLink, p.slice(pos)); + start(); + } + + if (cache) cache[original] = p; + + return p; +}; + + +fs.realpath = function realpath(p, cache, cb) { + if (typeof cb !== 'function') { + cb = maybeCallback(cache); + cache = null; + } + + // make p is absolute + p = pathModule.resolve(p); + + if (cache && Object.prototype.hasOwnProperty.call(cache, p)) { + return process.nextTick(cb.bind(null, null, cache[p])); + } + + var original = p, + seenLinks = {}, + knownHard = {}; + + // current character position in p + var pos; + // the partial path so far, including a trailing slash if any + var current; + // the partial path without a trailing slash (except when pointing at a root) + var base; + // the partial path scanned in the previous round, with slash + var previous; + + start(); + + function start() { + // Skip over roots + var m = splitRootRe.exec(p); + pos = m[0].length; + current = m[0]; + base = m[0]; + previous = ''; + + // On windows, check that the root exists. On unix there is no need. + if (isWindows && !knownHard[base]) { + fs.lstat(base, function(err) { + if (err) return cb(err); + knownHard[base] = true; + LOOP(); + }); + } else { + process.nextTick(LOOP); + } + } + + // walk down the path, swapping out linked pathparts for their real + // values + function LOOP() { + // stop if scanned past end of path + if (pos >= p.length) { + if (cache) cache[original] = p; + return cb(null, p); + } + + // find the next part + nextPartRe.lastIndex = pos; + var result = nextPartRe.exec(p); + previous = current; + current += result[0]; + base = previous + result[1]; + pos = nextPartRe.lastIndex; + + // continue if not a symlink + if (knownHard[base] || (cache && cache[base] === base)) { + return process.nextTick(LOOP); + } + + if (cache && Object.prototype.hasOwnProperty.call(cache, base)) { + // known symbolic link. no need to stat again. + return gotResolvedLink(cache[base]); + } + + return fs.lstat(base, gotStat); + } + + function gotStat(err, stat) { + if (err) return cb(err); + + // if not a symlink, skip to the next path part + if (!stat.isSymbolicLink()) { + knownHard[base] = true; + if (cache) cache[base] = base; + return process.nextTick(LOOP); + } + + // stat & read the link if not read before + // call gotTarget as soon as the link target is known + // dev/ino always return 0 on windows, so skip the check. + if (!isWindows) { + var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); + if (seenLinks.hasOwnProperty(id)) { + return gotTarget(null, seenLinks[id], base); + } + } + fs.stat(base, function(err) { + if (err) return cb(err); + + fs.readlink(base, function(err, target) { + if (!isWindows) seenLinks[id] = target; + gotTarget(err, target); + }); + }); + } + + function gotTarget(err, target, base) { + if (err) return cb(err); + + var resolvedLink = pathModule.resolve(previous, target); + if (cache) cache[base] = resolvedLink; + gotResolvedLink(resolvedLink); + } + + function gotResolvedLink(resolvedLink) { + // resolve the link, then start over + p = pathModule.resolve(resolvedLink, p.slice(pos)); + start(); + } +}; + + + +var pool; + +function allocNewPool() { + pool = new Buffer(kPoolSize); + pool.used = 0; +} + + + +fs.createReadStream = function(path, options) { + return new ReadStream(path, options); +}; + +util.inherits(ReadStream, Readable); +fs.ReadStream = ReadStream; + +function ReadStream(path, options) { + if (!(this instanceof ReadStream)) + return new ReadStream(path, options); + + // a little bit bigger buffer and water marks by default + options = util._extend({ + bufferSize: 64 * 1024, + lowWaterMark: 16 * 1024, + highWaterMark: 64 * 1024 + }, options || {}); + + Readable.call(this, options); + + this.path = path; + this.fd = options.hasOwnProperty('fd') ? options.fd : null; + this.flags = options.hasOwnProperty('flags') ? options.flags : 'r'; + this.mode = options.hasOwnProperty('mode') ? options.mode : 438; /*=0666*/ + + this.start = options.hasOwnProperty('start') ? options.start : undefined; + this.end = options.hasOwnProperty('start') ? options.end : undefined; + this.pos = undefined; + + if (this.start !== undefined) { + if ('number' !== typeof this.start) { + throw TypeError('start must be a Number'); + } + if (this.end === undefined) { + this.end = Infinity; + } else if ('number' !== typeof this.end) { + throw TypeError('end must be a Number'); + } + + if (this.start > this.end) { + throw new Error('start must be <= end'); + } + + this.pos = this.start; + } + + if (typeof this.fd !== 'number') + this.open(); + + this.on('end', function() { + this.destroy(); + }); +} + +fs.FileReadStream = fs.ReadStream; // support the legacy name + +ReadStream.prototype.open = function() { + var self = this; + fs.open(this.path, this.flags, this.mode, function(er, fd) { + if (er) { + self.destroy(); + self.emit('error', er); + return; + } + + self.fd = fd; + self.emit('open', fd); + // start the flow of data. + self.read(); + }); +}; + +ReadStream.prototype._read = function(n, cb) { + if (typeof this.fd !== 'number') + return this.once('open', function() { + this._read(n, cb); + }); + + if (this.destroyed) + return; + + if (!pool || pool.length - pool.used < kMinPoolSpace) { + // discard the old pool. Can't add to the free list because + // users might have refernces to slices on it. + pool = null; + allocNewPool(); + } + + // Grab another reference to the pool in the case that while we're + // in the thread pool another read() finishes up the pool, and + // allocates a new one. + var thisPool = pool; + var toRead = Math.min(pool.length - pool.used, n); + var start = pool.used; + + if (this.pos !== undefined) + toRead = Math.min(this.end - this.pos + 1, toRead); + + // already read everything we were supposed to read! + // treat as EOF. + if (toRead <= 0) + return cb(); + + // the actual read. + var self = this; + fs.read(this.fd, pool, pool.used, toRead, this.pos, onread); + + // move the pool positions, and internal position for reading. + if (this.pos !== undefined) + this.pos += toRead; + pool.used += toRead; + + function onread(er, bytesRead) { + if (er) { + self.destroy(); + return cb(er); + } + + var b = null; + if (bytesRead > 0) + b = thisPool.slice(start, start + bytesRead); + + cb(null, b); + } +}; + + +ReadStream.prototype.destroy = function() { + if (this.destroyed) + return; + this.destroyed = true; + if ('number' === typeof this.fd) + this.close(); +}; + + +ReadStream.prototype.close = function(cb) { + if (cb) + this.once('close', cb); + if (this.closed || 'number' !== typeof this.fd) { + if ('number' !== typeof this.fd) + this.once('open', close); + return process.nextTick(this.emit.bind(this, 'close')); + } + this.closed = true; + var self = this; + close(); + + function close() { + fs.close(self.fd, function(er) { + if (er) + self.emit('error', er); + else + self.emit('close'); + }); + } +}; + + + + +fs.createWriteStream = function(path, options) { + return new WriteStream(path, options); +}; + +util.inherits(WriteStream, Writable); +fs.WriteStream = WriteStream; +function WriteStream(path, options) { + if (!(this instanceof WriteStream)) + return new WriteStream(path, options); + + // a little bit bigger buffer and water marks by default + options = util._extend({ + bufferSize: 64 * 1024, + lowWaterMark: 16 * 1024, + highWaterMark: 64 * 1024 + }, options || {}); + + Writable.call(this, options); + + this.path = path; + this.fd = null; + + this.fd = options.hasOwnProperty('fd') ? options.fd : null; + this.flags = options.hasOwnProperty('flags') ? options.flags : 'w'; + this.mode = options.hasOwnProperty('mode') ? options.mode : 438; /*=0666*/ + + this.start = options.hasOwnProperty('start') ? options.start : undefined; + this.pos = undefined; + this.bytesWritten = 0; + + if (this.start !== undefined) { + if ('number' !== typeof this.start) { + throw TypeError('start must be a Number'); + } + if (this.start < 0) { + throw new Error('start must be >= zero'); + } + + this.pos = this.start; + } + + if ('number' !== typeof this.fd) + this.open(); + + // dispose on finish. + this.once('finish', this.close); +} + +fs.FileWriteStream = fs.WriteStream; // support the legacy name + + +WriteStream.prototype.open = function() { + fs.open(this.path, this.flags, this.mode, function(er, fd) { + if (er) { + this.destroy(); + this.emit('error', er); + return; + } + + this.fd = fd; + this.emit('open', fd); + }.bind(this)); +}; + + +WriteStream.prototype._write = function(data, cb) { + if (!Buffer.isBuffer(data)) + return this.emit('error', new Error('Invalid data')); + + if (typeof this.fd !== 'number') + return this.once('open', this._write.bind(this, data, cb)); + + fs.write(this.fd, data, 0, data.length, this.pos, function(er, bytes) { + if (er) { + this.destroy(); + return cb(er); + } + this.bytesWritten += bytes; + cb(); + }.bind(this)); + + if (this.pos !== undefined) + this.pos += data.length; +}; + + +WriteStream.prototype.destroy = ReadStream.prototype.destroy; +WriteStream.prototype.close = ReadStream.prototype.close; + +// There is no shutdown() for files. +WriteStream.prototype.destroySoon = WriteStream.prototype.end; + + +// SyncWriteStream is internal. DO NOT USE. +// Temporary hack for process.stdout and process.stderr when piped to files. +function SyncWriteStream(fd) { + Stream.call(this); + + this.fd = fd; + this.writable = true; + this.readable = false; +} + +util.inherits(SyncWriteStream, Stream); + + +// Export +fs.SyncWriteStream = SyncWriteStream; + + +SyncWriteStream.prototype.write = function(data, arg1, arg2) { + var encoding, cb; + + // parse arguments + if (arg1) { + if (typeof arg1 === 'string') { + encoding = arg1; + cb = arg2; + } else if (typeof arg1 === 'function') { + cb = arg1; + } else { + throw new Error('bad arg'); + } + } + assertEncoding(encoding); + + // Change strings to buffers. SLOW + if (typeof data == 'string') { + data = new Buffer(data, encoding); + } + + fs.writeSync(this.fd, data, 0, data.length); + + if (cb) { + process.nextTick(cb); + } + + return true; +}; + + +SyncWriteStream.prototype.end = function(data, arg1, arg2) { + if (data) { + this.write(data, arg1, arg2); + } + this.destroy(); +}; + + +SyncWriteStream.prototype.destroy = function() { + fs.closeSync(this.fd); + this.fd = null; + this.emit('close'); + return true; +}; + +SyncWriteStream.prototype.destroySoon = SyncWriteStream.prototype.destroy; diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/lib/_stream_duplex.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/lib/_stream_duplex.js new file mode 100644 index 0000000..a2e0d8e --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/lib/_stream_duplex.js @@ -0,0 +1,69 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// a duplex stream is just a stream that is both readable and writable. +// Since JS doesn't have multiple prototypal inheritance, this class +// prototypally inherits from Readable, and then parasitically from +// Writable. + +module.exports = Duplex; +var util = require('util'); +var Readable = require('./_stream_readable'); +var Writable = require('./_stream_writable'); + +util.inherits(Duplex, Readable); + +Object.keys(Writable.prototype).forEach(function(method) { + if (!Duplex.prototype[method]) + Duplex.prototype[method] = Writable.prototype[method]; +}); + +function Duplex(options) { + if (!(this instanceof Duplex)) + return new Duplex(options); + + Readable.call(this, options); + Writable.call(this, options); + + if (options && options.readable === false) + this.readable = false; + + if (options && options.writable === false) + this.writable = false; + + this.allowHalfOpen = true; + if (options && options.allowHalfOpen === false) + this.allowHalfOpen = false; + + this.once('end', onend); +} + +// the no-half-open enforcer +function onend() { + // if we allow half-open state, or if the writable side ended, + // then we're ok. + if (this.allowHalfOpen || this._writableState.ended) + return; + + // no more data can be written. + // But allow more writes to happen in this tick. + process.nextTick(this.end.bind(this)); +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/lib/_stream_passthrough.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/lib/_stream_passthrough.js new file mode 100644 index 0000000..330c247 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/lib/_stream_passthrough.js @@ -0,0 +1,41 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// a passthrough stream. +// basically just the most minimal sort of Transform stream. +// Every written chunk gets output as-is. + +module.exports = PassThrough; + +var Transform = require('./_stream_transform'); +var util = require('util'); +util.inherits(PassThrough, Transform); + +function PassThrough(options) { + if (!(this instanceof PassThrough)) + return new PassThrough(options); + + Transform.call(this, options); +} + +PassThrough.prototype._transform = function(chunk, encoding, cb) { + cb(null, chunk); +}; diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/lib/_stream_readable.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/lib/_stream_readable.js new file mode 100644 index 0000000..90a8298 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/lib/_stream_readable.js @@ -0,0 +1,920 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +module.exports = Readable; +Readable.ReadableState = ReadableState; + +var EE = require('events').EventEmitter; +if (!EE.listenerCount) EE.listenerCount = function(emitter, type) { + return emitter.listeners(type).length; +}; + +if (!global.setImmediate) global.setImmediate = function setImmediate(fn) { + return setTimeout(fn, 0); +}; +if (!global.clearImmediate) global.clearImmediate = function clearImmediate(i) { + return clearTimeout(i); +}; + +var Stream = require('stream'); +var util = require('util'); +if (!util.isUndefined) { + var utilIs = require('core-util-is'); + for (var f in utilIs) { + util[f] = utilIs[f]; + } +} +var StringDecoder; +var debug; +if (util.debuglog) + debug = util.debuglog('stream'); +else try { + debug = require('debuglog')('stream'); +} catch (er) { + debug = function() {}; +} + +util.inherits(Readable, Stream); + +function ReadableState(options, stream) { + options = options || {}; + + // the point at which it stops calling _read() to fill the buffer + // Note: 0 is a valid value, means "don't call _read preemptively ever" + var hwm = options.highWaterMark; + this.highWaterMark = (hwm || hwm === 0) ? hwm : 16 * 1024; + + // cast to ints. + this.highWaterMark = ~~this.highWaterMark; + + this.buffer = []; + this.length = 0; + this.pipes = null; + this.pipesCount = 0; + this.flowing = null; + this.ended = false; + this.endEmitted = false; + this.reading = false; + + // a flag to be able to tell if the onwrite cb is called immediately, + // or on a later tick. We set this to true at first, because any + // actions that shouldn't happen until "later" should generally also + // not happen before the first write call. + this.sync = true; + + // whenever we return null, then we set a flag to say + // that we're awaiting a 'readable' event emission. + this.needReadable = false; + this.emittedReadable = false; + this.readableListening = false; + + + // object stream flag. Used to make read(n) ignore n and to + // make all the buffer merging and length checks go away + this.objectMode = !!options.objectMode; + + // Crypto is kind of old and crusty. Historically, its default string + // encoding is 'binary' so we have to make this configurable. + // Everything else in the universe uses 'utf8', though. + this.defaultEncoding = options.defaultEncoding || 'utf8'; + + // when piping, we only care about 'readable' events that happen + // after read()ing all the bytes and not getting any pushback. + this.ranOut = false; + + // the number of writers that are awaiting a drain event in .pipe()s + this.awaitDrain = 0; + + // if true, a maybeReadMore has been scheduled + this.readingMore = false; + + this.decoder = null; + this.encoding = null; + if (options.encoding) { + if (!StringDecoder) + StringDecoder = require('string_decoder').StringDecoder; + this.decoder = new StringDecoder(options.encoding); + this.encoding = options.encoding; + } +} + +function Readable(options) { + if (!(this instanceof Readable)) + return new Readable(options); + + this._readableState = new ReadableState(options, this); + + // legacy + this.readable = true; + + Stream.call(this); +} + +// Manually shove something into the read() buffer. +// This returns true if the highWaterMark has not been hit yet, +// similar to how Writable.write() returns true if you should +// write() some more. +Readable.prototype.push = function(chunk, encoding) { + var state = this._readableState; + + if (util.isString(chunk) && !state.objectMode) { + encoding = encoding || state.defaultEncoding; + if (encoding !== state.encoding) { + chunk = new Buffer(chunk, encoding); + encoding = ''; + } + } + + return readableAddChunk(this, state, chunk, encoding, false); +}; + +// Unshift should *always* be something directly out of read() +Readable.prototype.unshift = function(chunk) { + var state = this._readableState; + return readableAddChunk(this, state, chunk, '', true); +}; + +function readableAddChunk(stream, state, chunk, encoding, addToFront) { + var er = chunkInvalid(state, chunk); + if (er) { + stream.emit('error', er); + } else if (util.isNullOrUndefined(chunk)) { + state.reading = false; + if (!state.ended) + onEofChunk(stream, state); + } else if (state.objectMode || chunk && chunk.length > 0) { + if (state.ended && !addToFront) { + var e = new Error('stream.push() after EOF'); + stream.emit('error', e); + } else if (state.endEmitted && addToFront) { + var e = new Error('stream.unshift() after end event'); + stream.emit('error', e); + } else { + if (state.decoder && !addToFront && !encoding) + chunk = state.decoder.write(chunk); + + if (!addToFront) + state.reading = false; + + // if we want the data now, just emit it. + if (state.flowing && state.length === 0 && !state.sync) { + stream.emit('data', chunk); + stream.read(0); + } else { + // update the buffer info. + state.length += state.objectMode ? 1 : chunk.length; + if (addToFront) + state.buffer.unshift(chunk); + else + state.buffer.push(chunk); + + if (state.needReadable) + emitReadable(stream); + } + + maybeReadMore(stream, state); + } + } else if (!addToFront) { + state.reading = false; + } + + return needMoreData(state); +} + + + +// if it's past the high water mark, we can push in some more. +// Also, if we have no data yet, we can stand some +// more bytes. This is to work around cases where hwm=0, +// such as the repl. Also, if the push() triggered a +// readable event, and the user called read(largeNumber) such that +// needReadable was set, then we ought to push more, so that another +// 'readable' event will be triggered. +function needMoreData(state) { + return !state.ended && + (state.needReadable || + state.length < state.highWaterMark || + state.length === 0); +} + +// backwards compatibility. +Readable.prototype.setEncoding = function(enc) { + if (!StringDecoder) + StringDecoder = require('string_decoder').StringDecoder; + this._readableState.decoder = new StringDecoder(enc); + this._readableState.encoding = enc; +}; + +// Don't raise the hwm > 128MB +var MAX_HWM = 0x800000; +function roundUpToNextPowerOf2(n) { + if (n >= MAX_HWM) { + n = MAX_HWM; + } else { + // Get the next highest power of 2 + n--; + for (var p = 1; p < 32; p <<= 1) n |= n >> p; + n++; + } + return n; +} + +function howMuchToRead(n, state) { + if (state.length === 0 && state.ended) + return 0; + + if (state.objectMode) + return n === 0 ? 0 : 1; + + if (isNaN(n) || util.isNull(n)) { + // only flow one buffer at a time + if (state.flowing && state.buffer.length) + return state.buffer[0].length; + else + return state.length; + } + + if (n <= 0) + return 0; + + // If we're asking for more than the target buffer level, + // then raise the water mark. Bump up to the next highest + // power of 2, to prevent increasing it excessively in tiny + // amounts. + if (n > state.highWaterMark) + state.highWaterMark = roundUpToNextPowerOf2(n); + + // don't have that much. return null, unless we've ended. + if (n > state.length) { + if (!state.ended) { + state.needReadable = true; + return 0; + } else + return state.length; + } + + return n; +} + +// you can override either this method, or the async _read(n) below. +Readable.prototype.read = function(n) { + debug('read', n); + var state = this._readableState; + var nOrig = n; + + if (!util.isNumber(n) || n > 0) + state.emittedReadable = false; + + // if we're doing read(0) to trigger a readable event, but we + // already have a bunch of data in the buffer, then just trigger + // the 'readable' event and move on. + if (n === 0 && + state.needReadable && + (state.length >= state.highWaterMark || state.ended)) { + debug('read: emitReadable', state.length, state.ended); + if (state.length === 0 && state.ended) + endReadable(this); + else + emitReadable(this); + return null; + } + + n = howMuchToRead(n, state); + + // if we've ended, and we're now clear, then finish it up. + if (n === 0 && state.ended) { + if (state.length === 0) + endReadable(this); + return null; + } + + // All the actual chunk generation logic needs to be + // *below* the call to _read. The reason is that in certain + // synthetic stream cases, such as passthrough streams, _read + // may be a completely synchronous operation which may change + // the state of the read buffer, providing enough data when + // before there was *not* enough. + // + // So, the steps are: + // 1. Figure out what the state of things will be after we do + // a read from the buffer. + // + // 2. If that resulting state will trigger a _read, then call _read. + // Note that this may be asynchronous, or synchronous. Yes, it is + // deeply ugly to write APIs this way, but that still doesn't mean + // that the Readable class should behave improperly, as streams are + // designed to be sync/async agnostic. + // Take note if the _read call is sync or async (ie, if the read call + // has returned yet), so that we know whether or not it's safe to emit + // 'readable' etc. + // + // 3. Actually pull the requested chunks out of the buffer and return. + + // if we need a readable event, then we need to do some reading. + var doRead = state.needReadable; + debug('need readable', doRead); + + // if we currently have less than the highWaterMark, then also read some + if (state.length === 0 || state.length - n < state.highWaterMark) { + doRead = true; + debug('length less than watermark', doRead); + } + + // however, if we've ended, then there's no point, and if we're already + // reading, then it's unnecessary. + if (state.ended || state.reading) { + doRead = false; + debug('reading or ended', doRead); + } + + if (doRead) { + debug('do read'); + state.reading = true; + state.sync = true; + // if the length is currently zero, then we *need* a readable event. + if (state.length === 0) + state.needReadable = true; + // call internal read method + this._read(state.highWaterMark); + state.sync = false; + } + + // If _read pushed data synchronously, then `reading` will be false, + // and we need to re-evaluate how much data we can return to the user. + if (doRead && !state.reading) + n = howMuchToRead(nOrig, state); + + var ret; + if (n > 0) + ret = fromList(n, state); + else + ret = null; + + if (util.isNull(ret)) { + state.needReadable = true; + n = 0; + } + + state.length -= n; + + // If we have nothing in the buffer, then we want to know + // as soon as we *do* get something into the buffer. + if (state.length === 0 && !state.ended) + state.needReadable = true; + + // If we tried to read() past the EOF, then emit end on the next tick. + if (nOrig !== n && state.ended && state.length === 0) + endReadable(this); + + if (!util.isNull(ret)) + this.emit('data', ret); + + return ret; +}; + +function chunkInvalid(state, chunk) { + var er = null; + if (!util.isBuffer(chunk) && + !util.isString(chunk) && + !util.isNullOrUndefined(chunk) && + !state.objectMode && + !er) { + er = new TypeError('Invalid non-string/buffer chunk'); + } + return er; +} + + +function onEofChunk(stream, state) { + if (state.decoder && !state.ended && state.decoder.end) { + var chunk = state.decoder.end(); + if (chunk && chunk.length) { + state.buffer.push(chunk); + state.length += state.objectMode ? 1 : chunk.length; + } + } + state.ended = true; + + // emit 'readable' now to make sure it gets picked up. + emitReadable(stream); +} + +// Don't emit readable right away in sync mode, because this can trigger +// another read() call => stack overflow. This way, it might trigger +// a nextTick recursion warning, but that's not so bad. +function emitReadable(stream) { + var state = stream._readableState; + state.needReadable = false; + if (!state.emittedReadable) { + debug('emitReadable', state.flowing); + state.emittedReadable = true; + if (state.sync) + process.nextTick(function() { + emitReadable_(stream); + }); + else + emitReadable_(stream); + } +} + +function emitReadable_(stream) { + debug('emit readable'); + stream.emit('readable'); + flow(stream); +} + + +// at this point, the user has presumably seen the 'readable' event, +// and called read() to consume some data. that may have triggered +// in turn another _read(n) call, in which case reading = true if +// it's in progress. +// However, if we're not ended, or reading, and the length < hwm, +// then go ahead and try to read some more preemptively. +function maybeReadMore(stream, state) { + if (!state.readingMore) { + state.readingMore = true; + process.nextTick(function() { + maybeReadMore_(stream, state); + }); + } +} + +function maybeReadMore_(stream, state) { + var len = state.length; + while (!state.reading && !state.flowing && !state.ended && + state.length < state.highWaterMark) { + debug('maybeReadMore read 0'); + stream.read(0); + if (len === state.length) + // didn't get any data, stop spinning. + break; + else + len = state.length; + } + state.readingMore = false; +} + +// abstract method. to be overridden in specific implementation classes. +// call cb(er, data) where data is <= n in length. +// for virtual (non-string, non-buffer) streams, "length" is somewhat +// arbitrary, and perhaps not very meaningful. +Readable.prototype._read = function(n) { + this.emit('error', new Error('not implemented')); +}; + +Readable.prototype.pipe = function(dest, pipeOpts) { + var src = this; + var state = this._readableState; + + switch (state.pipesCount) { + case 0: + state.pipes = dest; + break; + case 1: + state.pipes = [state.pipes, dest]; + break; + default: + state.pipes.push(dest); + break; + } + state.pipesCount += 1; + debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts); + + var doEnd = (!pipeOpts || pipeOpts.end !== false) && + dest !== process.stdout && + dest !== process.stderr; + + var endFn = doEnd ? onend : cleanup; + if (state.endEmitted) + process.nextTick(endFn); + else + src.once('end', endFn); + + dest.on('unpipe', onunpipe); + function onunpipe(readable) { + debug('onunpipe'); + if (readable === src) { + cleanup(); + } + } + + function onend() { + debug('onend'); + dest.end(); + } + + // when the dest drains, it reduces the awaitDrain counter + // on the source. This would be more elegant with a .once() + // handler in flow(), but adding and removing repeatedly is + // too slow. + var ondrain = pipeOnDrain(src); + dest.on('drain', ondrain); + + function cleanup() { + debug('cleanup'); + // cleanup event handlers once the pipe is broken + dest.removeListener('close', onclose); + dest.removeListener('finish', onfinish); + dest.removeListener('drain', ondrain); + dest.removeListener('error', onerror); + dest.removeListener('unpipe', onunpipe); + src.removeListener('end', onend); + src.removeListener('end', cleanup); + src.removeListener('data', ondata); + + // if the reader is waiting for a drain event from this + // specific writer, then it would cause it to never start + // flowing again. + // So, if this is awaiting a drain, then we just call it now. + // If we don't know, then assume that we are waiting for one. + if (state.awaitDrain && + (!dest._writableState || dest._writableState.needDrain)) + ondrain(); + } + + src.on('data', ondata); + function ondata(chunk) { + debug('ondata'); + var ret = dest.write(chunk); + if (false === ret) { + debug('false write response, pause', + src._readableState.awaitDrain); + src._readableState.awaitDrain++; + src.pause(); + } + } + + // if the dest has an error, then stop piping into it. + // however, don't suppress the throwing behavior for this. + function onerror(er) { + debug('onerror', er); + unpipe(); + dest.removeListener('error', onerror); + if (EE.listenerCount(dest, 'error') === 0) + dest.emit('error', er); + } + // This is a brutally ugly hack to make sure that our error handler + // is attached before any userland ones. NEVER DO THIS. + if (!dest._events.error) + dest.on('error', onerror); + else if (Array.isArray(dest._events.error)) + dest._events.error.unshift(onerror); + else + dest._events.error = [onerror, dest._events.error]; + + + + // Both close and finish should trigger unpipe, but only once. + function onclose() { + dest.removeListener('finish', onfinish); + unpipe(); + } + dest.once('close', onclose); + function onfinish() { + debug('onfinish'); + dest.removeListener('close', onclose); + unpipe(); + } + dest.once('finish', onfinish); + + function unpipe() { + debug('unpipe'); + src.unpipe(dest); + } + + // tell the dest that it's being piped to + dest.emit('pipe', src); + + // start the flow if it hasn't been started already. + if (!state.flowing) { + debug('pipe resume'); + src.resume(); + } + + return dest; +}; + +function pipeOnDrain(src) { + return function() { + var state = src._readableState; + debug('pipeOnDrain', state.awaitDrain); + if (state.awaitDrain) + state.awaitDrain--; + if (state.awaitDrain === 0 && EE.listenerCount(src, 'data')) { + state.flowing = true; + flow(src); + } + }; +} + + +Readable.prototype.unpipe = function(dest) { + var state = this._readableState; + + // if we're not piping anywhere, then do nothing. + if (state.pipesCount === 0) + return this; + + // just one destination. most common case. + if (state.pipesCount === 1) { + // passed in one, but it's not the right one. + if (dest && dest !== state.pipes) + return this; + + if (!dest) + dest = state.pipes; + + // got a match. + state.pipes = null; + state.pipesCount = 0; + state.flowing = false; + if (dest) + dest.emit('unpipe', this); + return this; + } + + // slow case. multiple pipe destinations. + + if (!dest) { + // remove all. + var dests = state.pipes; + var len = state.pipesCount; + state.pipes = null; + state.pipesCount = 0; + state.flowing = false; + + for (var i = 0; i < len; i++) + dests[i].emit('unpipe', this); + return this; + } + + // try to find the right one. + var i = state.pipes.indexOf(dest); + if (i === -1) + return this; + + state.pipes.splice(i, 1); + state.pipesCount -= 1; + if (state.pipesCount === 1) + state.pipes = state.pipes[0]; + + dest.emit('unpipe', this); + + return this; +}; + +// set up data events if they are asked for +// Ensure readable listeners eventually get something +Readable.prototype.on = function(ev, fn) { + var res = Stream.prototype.on.call(this, ev, fn); + + // If listening to data, and it has not explicitly been paused, + // then call resume to start the flow of data on the next tick. + if (ev === 'data' && false !== this._readableState.flowing) { + this.resume(); + } + + if (ev === 'readable' && this.readable) { + var state = this._readableState; + if (!state.readableListening) { + state.readableListening = true; + state.emittedReadable = false; + state.needReadable = true; + if (!state.reading) { + var self = this; + process.nextTick(function() { + debug('readable nexttick read 0'); + self.read(0); + }); + } else if (state.length) { + emitReadable(this, state); + } + } + } + + return res; +}; +Readable.prototype.addListener = Readable.prototype.on; + +// pause() and resume() are remnants of the legacy readable stream API +// If the user uses them, then switch into old mode. +Readable.prototype.resume = function() { + var state = this._readableState; + if (!state.flowing) { + debug('resume'); + state.flowing = true; + if (!state.reading) { + debug('resume read 0'); + this.read(0); + } + resume(this, state); + } +}; + +function resume(stream, state) { + if (!state.resumeScheduled) { + state.resumeScheduled = true; + process.nextTick(function() { + resume_(stream, state); + }); + } +} + +function resume_(stream, state) { + state.resumeScheduled = false; + stream.emit('resume'); + flow(stream); + if (state.flowing && !state.reading) + stream.read(0); +} + +Readable.prototype.pause = function() { + debug('call pause flowing=%j', this._readableState.flowing); + if (false !== this._readableState.flowing) { + debug('pause'); + this._readableState.flowing = false; + this.emit('pause'); + } +}; + +function flow(stream) { + var state = stream._readableState; + debug('flow', state.flowing); + if (state.flowing) { + do { + var chunk = stream.read(); + } while (null !== chunk && state.flowing); + } +} + +// wrap an old-style stream as the async data source. +// This is *not* part of the readable stream interface. +// It is an ugly unfortunate mess of history. +Readable.prototype.wrap = function(stream) { + var state = this._readableState; + var paused = false; + + var self = this; + stream.on('end', function() { + debug('wrapped end'); + if (state.decoder && !state.ended) { + var chunk = state.decoder.end(); + if (chunk && chunk.length) + self.push(chunk); + } + + self.push(null); + }); + + stream.on('data', function(chunk) { + debug('wrapped data'); + if (state.decoder) + chunk = state.decoder.write(chunk); + if (!chunk || !state.objectMode && !chunk.length) + return; + + var ret = self.push(chunk); + if (!ret) { + paused = true; + stream.pause(); + } + }); + + // proxy all the other methods. + // important when wrapping filters and duplexes. + for (var i in stream) { + if (util.isFunction(stream[i]) && util.isUndefined(this[i])) { + this[i] = function(method) { return function() { + return stream[method].apply(stream, arguments); + }}(i); + } + } + + // proxy certain important events. + var events = ['error', 'close', 'destroy', 'pause', 'resume']; + events.forEach(function(ev) { + stream.on(ev, self.emit.bind(self, ev)); + }); + + // when we try to consume some more bytes, simply unpause the + // underlying stream. + self._read = function(n) { + debug('wrapped _read', n); + if (paused) { + paused = false; + stream.resume(); + } + }; + + return self; +}; + + + +// exposed for testing purposes only. +Readable._fromList = fromList; + +// Pluck off n bytes from an array of buffers. +// Length is the combined lengths of all the buffers in the list. +function fromList(n, state) { + var list = state.buffer; + var length = state.length; + var stringMode = !!state.decoder; + var objectMode = !!state.objectMode; + var ret; + + // nothing in the list, definitely empty. + if (list.length === 0) + return null; + + if (length === 0) + ret = null; + else if (objectMode) + ret = list.shift(); + else if (!n || n >= length) { + // read it all, truncate the array. + if (stringMode) + ret = list.join(''); + else + ret = Buffer.concat(list, length); + list.length = 0; + } else { + // read just some of it. + if (n < list[0].length) { + // just take a part of the first list item. + // slice is the same for buffers and strings. + var buf = list[0]; + ret = buf.slice(0, n); + list[0] = buf.slice(n); + } else if (n === list[0].length) { + // first list is a perfect match + ret = list.shift(); + } else { + // complex case. + // we have enough to cover it, but it spans past the first buffer. + if (stringMode) + ret = ''; + else + ret = new Buffer(n); + + var c = 0; + for (var i = 0, l = list.length; i < l && c < n; i++) { + var buf = list[0]; + var cpy = Math.min(n - c, buf.length); + + if (stringMode) + ret += buf.slice(0, cpy); + else + buf.copy(ret, c, 0, cpy); + + if (cpy < buf.length) + list[0] = buf.slice(cpy); + else + list.shift(); + + c += cpy; + } + } + } + + return ret; +} + +function endReadable(stream) { + var state = stream._readableState; + + // If we get here before consuming all the bytes, then that is a + // bug in node. Should never happen. + if (state.length > 0) + throw new Error('endReadable called on non-empty stream'); + + if (!state.endEmitted) { + state.ended = true; + process.nextTick(function() { + // Check that we didn't get one last unshift. + if (!state.endEmitted && state.length === 0) { + state.endEmitted = true; + stream.readable = false; + stream.emit('end'); + } + }); + } +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/lib/_stream_transform.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/lib/_stream_transform.js new file mode 100644 index 0000000..b0caf57 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/lib/_stream_transform.js @@ -0,0 +1,210 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + +// a transform stream is a readable/writable stream where you do +// something with the data. Sometimes it's called a "filter", +// but that's not a great name for it, since that implies a thing where +// some bits pass through, and others are simply ignored. (That would +// be a valid example of a transform, of course.) +// +// While the output is causally related to the input, it's not a +// necessarily symmetric or synchronous transformation. For example, +// a zlib stream might take multiple plain-text writes(), and then +// emit a single compressed chunk some time in the future. +// +// Here's how this works: +// +// The Transform stream has all the aspects of the readable and writable +// stream classes. When you write(chunk), that calls _write(chunk,cb) +// internally, and returns false if there's a lot of pending writes +// buffered up. When you call read(), that calls _read(n) until +// there's enough pending readable data buffered up. +// +// In a transform stream, the written data is placed in a buffer. When +// _read(n) is called, it transforms the queued up data, calling the +// buffered _write cb's as it consumes chunks. If consuming a single +// written chunk would result in multiple output chunks, then the first +// outputted bit calls the readcb, and subsequent chunks just go into +// the read buffer, and will cause it to emit 'readable' if necessary. +// +// This way, back-pressure is actually determined by the reading side, +// since _read has to be called to start processing a new chunk. However, +// a pathological inflate type of transform can cause excessive buffering +// here. For example, imagine a stream where every byte of input is +// interpreted as an integer from 0-255, and then results in that many +// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in +// 1kb of data being output. In this case, you could write a very small +// amount of input, and end up with a very large amount of output. In +// such a pathological inflating mechanism, there'd be no way to tell +// the system to stop doing the transform. A single 4MB write could +// cause the system to run out of memory. +// +// However, even in such a pathological case, only a single written chunk +// would be consumed, and then the rest would wait (un-transformed) until +// the results of the previous transformed chunk were consumed. + +module.exports = Transform; + +var Duplex = require('./_stream_duplex'); +var util = require('util'); +if (!util.isUndefined) { + var utilIs = require('core-util-is'); + for (var f in utilIs) { + util[f] = utilIs[f]; + } +} +util.inherits(Transform, Duplex); + + +function TransformState(options, stream) { + this.afterTransform = function(er, data) { + return afterTransform(stream, er, data); + }; + + this.needTransform = false; + this.transforming = false; + this.writecb = null; + this.writechunk = null; +} + +function afterTransform(stream, er, data) { + var ts = stream._transformState; + ts.transforming = false; + + var cb = ts.writecb; + + if (!cb) + return stream.emit('error', new Error('no writecb in Transform class')); + + ts.writechunk = null; + ts.writecb = null; + + if (!util.isNullOrUndefined(data)) + stream.push(data); + + if (cb) + cb(er); + + var rs = stream._readableState; + rs.reading = false; + if (rs.needReadable || rs.length < rs.highWaterMark) { + stream._read(rs.highWaterMark); + } +} + + +function Transform(options) { + if (!(this instanceof Transform)) + return new Transform(options); + + Duplex.call(this, options); + + this._transformState = new TransformState(options, this); + + // when the writable side finishes, then flush out anything remaining. + var stream = this; + + // start out asking for a readable event once data is transformed. + this._readableState.needReadable = true; + + // we have implemented the _read method, and done the other things + // that Readable wants before the first _read call, so unset the + // sync guard flag. + this._readableState.sync = false; + + this.once('prefinish', function() { + if (util.isFunction(this._flush)) + this._flush(function(er) { + done(stream, er); + }); + else + done(stream); + }); +} + +Transform.prototype.push = function(chunk, encoding) { + this._transformState.needTransform = false; + return Duplex.prototype.push.call(this, chunk, encoding); +}; + +// This is the part where you do stuff! +// override this function in implementation classes. +// 'chunk' is an input chunk. +// +// Call `push(newChunk)` to pass along transformed output +// to the readable side. You may call 'push' zero or more times. +// +// Call `cb(err)` when you are done with this chunk. If you pass +// an error, then that'll put the hurt on the whole operation. If you +// never call cb(), then you'll never get another chunk. +Transform.prototype._transform = function(chunk, encoding, cb) { + throw new Error('not implemented'); +}; + +Transform.prototype._write = function(chunk, encoding, cb) { + var ts = this._transformState; + ts.writecb = cb; + ts.writechunk = chunk; + ts.writeencoding = encoding; + if (!ts.transforming) { + var rs = this._readableState; + if (ts.needTransform || + rs.needReadable || + rs.length < rs.highWaterMark) + this._read(rs.highWaterMark); + } +}; + +// Doesn't matter what the args are here. +// _transform does all the work. +// That we got here means that the readable side wants more data. +Transform.prototype._read = function(n) { + var ts = this._transformState; + + if (!util.isNull(ts.writechunk) && ts.writecb && !ts.transforming) { + ts.transforming = true; + this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); + } else { + // mark that we need a transform, so that any data that comes in + // will get processed, now that we've asked for it. + ts.needTransform = true; + } +}; + + +function done(stream, er) { + if (er) + return stream.emit('error', er); + + // if there's nothing in the write buffer, then that means + // that nothing more will ever be provided + var ws = stream._writableState; + var ts = stream._transformState; + + if (ws.length) + throw new Error('calling transform done when ws.length != 0'); + + if (ts.transforming) + throw new Error('calling transform done when still transforming'); + + return stream.push(null); +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/lib/_stream_writable.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/lib/_stream_writable.js new file mode 100644 index 0000000..f49288b --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/lib/_stream_writable.js @@ -0,0 +1,459 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// A bit simpler than readable streams. +// Implement an async ._write(chunk, cb), and it'll handle all +// the drain event emission and buffering. + +module.exports = Writable; +Writable.WritableState = WritableState; + +var util = require('util'); +if (!util.isUndefined) { + var utilIs = require('core-util-is'); + for (var f in utilIs) { + util[f] = utilIs[f]; + } +} +var Stream = require('stream'); + +util.inherits(Writable, Stream); + +function WriteReq(chunk, encoding, cb) { + this.chunk = chunk; + this.encoding = encoding; + this.callback = cb; +} + +function WritableState(options, stream) { + options = options || {}; + + // the point at which write() starts returning false + // Note: 0 is a valid value, means that we always return false if + // the entire buffer is not flushed immediately on write() + var hwm = options.highWaterMark; + this.highWaterMark = (hwm || hwm === 0) ? hwm : 16 * 1024; + + // object stream flag to indicate whether or not this stream + // contains buffers or objects. + this.objectMode = !!options.objectMode; + + // cast to ints. + this.highWaterMark = ~~this.highWaterMark; + + this.needDrain = false; + // at the start of calling end() + this.ending = false; + // when end() has been called, and returned + this.ended = false; + // when 'finish' is emitted + this.finished = false; + + // should we decode strings into buffers before passing to _write? + // this is here so that some node-core streams can optimize string + // handling at a lower level. + var noDecode = options.decodeStrings === false; + this.decodeStrings = !noDecode; + + // Crypto is kind of old and crusty. Historically, its default string + // encoding is 'binary' so we have to make this configurable. + // Everything else in the universe uses 'utf8', though. + this.defaultEncoding = options.defaultEncoding || 'utf8'; + + // not an actual buffer we keep track of, but a measurement + // of how much we're waiting to get pushed to some underlying + // socket or file. + this.length = 0; + + // a flag to see when we're in the middle of a write. + this.writing = false; + + // when true all writes will be buffered until .uncork() call + this.corked = 0; + + // a flag to be able to tell if the onwrite cb is called immediately, + // or on a later tick. We set this to true at first, because any + // actions that shouldn't happen until "later" should generally also + // not happen before the first write call. + this.sync = true; + + // a flag to know if we're processing previously buffered items, which + // may call the _write() callback in the same tick, so that we don't + // end up in an overlapped onwrite situation. + this.bufferProcessing = false; + + // the callback that's passed to _write(chunk,cb) + this.onwrite = function(er) { + onwrite(stream, er); + }; + + // the callback that the user supplies to write(chunk,encoding,cb) + this.writecb = null; + + // the amount that is being written when _write is called. + this.writelen = 0; + + this.buffer = []; + + // number of pending user-supplied write callbacks + // this must be 0 before 'finish' can be emitted + this.pendingcb = 0; + + // emit prefinish if the only thing we're waiting for is _write cbs + // This is relevant for synchronous Transform streams + this.prefinished = false; +} + +function Writable(options) { + // Writable ctor is applied to Duplexes, though they're not + // instanceof Writable, they're instanceof Readable. + if (!(this instanceof Writable) && !(this instanceof require('./_stream_duplex'))) + return new Writable(options); + + this._writableState = new WritableState(options, this); + + // legacy. + this.writable = true; + + Stream.call(this); +} + +// Otherwise people can pipe Writable streams, which is just wrong. +Writable.prototype.pipe = function() { + this.emit('error', new Error('Cannot pipe. Not readable.')); +}; + + +function writeAfterEnd(stream, state, cb) { + var er = new Error('write after end'); + // TODO: defer error events consistently everywhere, not just the cb + stream.emit('error', er); + process.nextTick(function() { + cb(er); + }); +} + +// If we get something that is not a buffer, string, null, or undefined, +// and we're not in objectMode, then that's an error. +// Otherwise stream chunks are all considered to be of length=1, and the +// watermarks determine how many objects to keep in the buffer, rather than +// how many bytes or characters. +function validChunk(stream, state, chunk, cb) { + var valid = true; + if (!util.isBuffer(chunk) && + !util.isString(chunk) && + !util.isNullOrUndefined(chunk) && + !state.objectMode) { + var er = new TypeError('Invalid non-string/buffer chunk'); + stream.emit('error', er); + process.nextTick(function() { + cb(er); + }); + valid = false; + } + return valid; +} + +Writable.prototype.write = function(chunk, encoding, cb) { + var state = this._writableState; + var ret = false; + + if (util.isFunction(encoding)) { + cb = encoding; + encoding = null; + } + + if (util.isBuffer(chunk)) + encoding = 'buffer'; + else if (!encoding) + encoding = state.defaultEncoding; + + if (!util.isFunction(cb)) + cb = function() {}; + + if (state.ended) + writeAfterEnd(this, state, cb); + else if (validChunk(this, state, chunk, cb)) { + state.pendingcb++; + ret = writeOrBuffer(this, state, chunk, encoding, cb); + } + + return ret; +}; + +Writable.prototype.cork = function() { + var state = this._writableState; + + state.corked++; +}; + +Writable.prototype.uncork = function() { + var state = this._writableState; + + if (state.corked) { + state.corked--; + + if (!state.writing && + !state.corked && + !state.finished && + !state.bufferProcessing && + state.buffer.length) + clearBuffer(this, state); + } +}; + +function decodeChunk(state, chunk, encoding) { + if (!state.objectMode && + state.decodeStrings !== false && + util.isString(chunk)) { + chunk = new Buffer(chunk, encoding); + } + return chunk; +} + +// if we're already writing something, then just put this +// in the queue, and wait our turn. Otherwise, call _write +// If we return false, then we need a drain event, so set that flag. +function writeOrBuffer(stream, state, chunk, encoding, cb) { + chunk = decodeChunk(state, chunk, encoding); + if (util.isBuffer(chunk)) + encoding = 'buffer'; + var len = state.objectMode ? 1 : chunk.length; + + state.length += len; + + var ret = state.length < state.highWaterMark; + state.needDrain = !ret; + + if (state.writing || state.corked) + state.buffer.push(new WriteReq(chunk, encoding, cb)); + else + doWrite(stream, state, false, len, chunk, encoding, cb); + + return ret; +} + +function doWrite(stream, state, writev, len, chunk, encoding, cb) { + state.writelen = len; + state.writecb = cb; + state.writing = true; + state.sync = true; + if (writev) + stream._writev(chunk, state.onwrite); + else + stream._write(chunk, encoding, state.onwrite); + state.sync = false; +} + +function onwriteError(stream, state, sync, er, cb) { + if (sync) + process.nextTick(function() { + state.pendingcb--; + cb(er); + }); + else { + state.pendingcb--; + cb(er); + } + + stream.emit('error', er); +} + +function onwriteStateUpdate(state) { + state.writing = false; + state.writecb = null; + state.length -= state.writelen; + state.writelen = 0; +} + +function onwrite(stream, er) { + var state = stream._writableState; + var sync = state.sync; + var cb = state.writecb; + + onwriteStateUpdate(state); + + if (er) + onwriteError(stream, state, sync, er, cb); + else { + // Check if we're actually ready to finish, but don't emit yet + var finished = needFinish(stream, state); + + if (!finished && + !state.corked && + !state.bufferProcessing && + state.buffer.length) { + clearBuffer(stream, state); + } + + if (sync) { + process.nextTick(function() { + afterWrite(stream, state, finished, cb); + }); + } else { + afterWrite(stream, state, finished, cb); + } + } +} + +function afterWrite(stream, state, finished, cb) { + if (!finished) + onwriteDrain(stream, state); + state.pendingcb--; + cb(); + finishMaybe(stream, state); +} + +// Must force callback to be called on nextTick, so that we don't +// emit 'drain' before the write() consumer gets the 'false' return +// value, and has a chance to attach a 'drain' listener. +function onwriteDrain(stream, state) { + if (state.length === 0 && state.needDrain) { + state.needDrain = false; + stream.emit('drain'); + } +} + + +// if there's something in the buffer waiting, then process it +function clearBuffer(stream, state) { + state.bufferProcessing = true; + + if (stream._writev && state.buffer.length > 1) { + // Fast case, write everything using _writev() + var cbs = []; + for (var c = 0; c < state.buffer.length; c++) + cbs.push(state.buffer[c].callback); + + // count the one we are adding, as well. + // TODO(isaacs) clean this up + state.pendingcb++; + doWrite(stream, state, true, state.length, state.buffer, '', function(err) { + for (var i = 0; i < cbs.length; i++) { + state.pendingcb--; + cbs[i](err); + } + }); + + // Clear buffer + state.buffer = []; + } else { + // Slow case, write chunks one-by-one + for (var c = 0; c < state.buffer.length; c++) { + var entry = state.buffer[c]; + var chunk = entry.chunk; + var encoding = entry.encoding; + var cb = entry.callback; + var len = state.objectMode ? 1 : chunk.length; + + doWrite(stream, state, false, len, chunk, encoding, cb); + + // if we didn't call the onwrite immediately, then + // it means that we need to wait until it does. + // also, that means that the chunk and cb are currently + // being processed, so move the buffer counter past them. + if (state.writing) { + c++; + break; + } + } + + if (c < state.buffer.length) + state.buffer = state.buffer.slice(c); + else + state.buffer.length = 0; + } + + state.bufferProcessing = false; +} + +Writable.prototype._write = function(chunk, encoding, cb) { + cb(new Error('not implemented')); + +}; + +Writable.prototype._writev = null; + +Writable.prototype.end = function(chunk, encoding, cb) { + var state = this._writableState; + + if (util.isFunction(chunk)) { + cb = chunk; + chunk = null; + encoding = null; + } else if (util.isFunction(encoding)) { + cb = encoding; + encoding = null; + } + + if (!util.isNullOrUndefined(chunk)) + this.write(chunk, encoding); + + // .end() fully uncorks + if (state.corked) { + state.corked = 1; + this.uncork(); + } + + // ignore unnecessary end() calls. + if (!state.ending && !state.finished) + endWritable(this, state, cb); +}; + + +function needFinish(stream, state) { + return (state.ending && + state.length === 0 && + !state.finished && + !state.writing); +} + +function prefinish(stream, state) { + if (!state.prefinished) { + state.prefinished = true; + stream.emit('prefinish'); + } +} + +function finishMaybe(stream, state) { + var need = needFinish(stream, state); + if (need) { + if (state.pendingcb === 0) { + prefinish(stream, state); + state.finished = true; + stream.emit('finish'); + } else + prefinish(stream, state); + } + return need; +} + +function endWritable(stream, state, cb) { + state.ending = true; + finishMaybe(stream, state); + if (cb) { + if (state.finished) + process.nextTick(cb); + else + stream.once('finish', cb); + } + state.ended = true; +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/core-util-is/README.md b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/core-util-is/README.md new file mode 100644 index 0000000..5a76b41 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/core-util-is/README.md @@ -0,0 +1,3 @@ +# core-util-is + +The `util.is*` functions introduced in Node v0.12. diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/core-util-is/float.patch b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/core-util-is/float.patch new file mode 100644 index 0000000..ee596bf --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/core-util-is/float.patch @@ -0,0 +1,590 @@ +diff --git a/lib/util.js b/lib/util.js +index 9901a66..007fa10 100644 +--- a/lib/util.js ++++ b/lib/util.js +@@ -19,425 +19,6 @@ + // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + // USE OR OTHER DEALINGS IN THE SOFTWARE. + +-var formatRegExp = /%[sdj%]/g; +-exports.format = function(f) { +- if (!isString(f)) { +- var objects = []; +- for (var i = 0; i < arguments.length; i++) { +- objects.push(inspect(arguments[i])); +- } +- return objects.join(' '); +- } +- +- var i = 1; +- var args = arguments; +- var len = args.length; +- var str = String(f).replace(formatRegExp, function(x) { +- if (x === '%%') return '%'; +- if (i >= len) return x; +- switch (x) { +- case '%s': return String(args[i++]); +- case '%d': return Number(args[i++]); +- case '%j': +- try { +- return JSON.stringify(args[i++]); +- } catch (_) { +- return '[Circular]'; +- } +- default: +- return x; +- } +- }); +- for (var x = args[i]; i < len; x = args[++i]) { +- if (isNull(x) || !isObject(x)) { +- str += ' ' + x; +- } else { +- str += ' ' + inspect(x); +- } +- } +- return str; +-}; +- +- +-// Mark that a method should not be used. +-// Returns a modified function which warns once by default. +-// If --no-deprecation is set, then it is a no-op. +-exports.deprecate = function(fn, msg) { +- // Allow for deprecating things in the process of starting up. +- if (isUndefined(global.process)) { +- return function() { +- return exports.deprecate(fn, msg).apply(this, arguments); +- }; +- } +- +- if (process.noDeprecation === true) { +- return fn; +- } +- +- var warned = false; +- function deprecated() { +- if (!warned) { +- if (process.throwDeprecation) { +- throw new Error(msg); +- } else if (process.traceDeprecation) { +- console.trace(msg); +- } else { +- console.error(msg); +- } +- warned = true; +- } +- return fn.apply(this, arguments); +- } +- +- return deprecated; +-}; +- +- +-var debugs = {}; +-var debugEnviron; +-exports.debuglog = function(set) { +- if (isUndefined(debugEnviron)) +- debugEnviron = process.env.NODE_DEBUG || ''; +- set = set.toUpperCase(); +- if (!debugs[set]) { +- if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { +- var pid = process.pid; +- debugs[set] = function() { +- var msg = exports.format.apply(exports, arguments); +- console.error('%s %d: %s', set, pid, msg); +- }; +- } else { +- debugs[set] = function() {}; +- } +- } +- return debugs[set]; +-}; +- +- +-/** +- * Echos the value of a value. Trys to print the value out +- * in the best way possible given the different types. +- * +- * @param {Object} obj The object to print out. +- * @param {Object} opts Optional options object that alters the output. +- */ +-/* legacy: obj, showHidden, depth, colors*/ +-function inspect(obj, opts) { +- // default options +- var ctx = { +- seen: [], +- stylize: stylizeNoColor +- }; +- // legacy... +- if (arguments.length >= 3) ctx.depth = arguments[2]; +- if (arguments.length >= 4) ctx.colors = arguments[3]; +- if (isBoolean(opts)) { +- // legacy... +- ctx.showHidden = opts; +- } else if (opts) { +- // got an "options" object +- exports._extend(ctx, opts); +- } +- // set default options +- if (isUndefined(ctx.showHidden)) ctx.showHidden = false; +- if (isUndefined(ctx.depth)) ctx.depth = 2; +- if (isUndefined(ctx.colors)) ctx.colors = false; +- if (isUndefined(ctx.customInspect)) ctx.customInspect = true; +- if (ctx.colors) ctx.stylize = stylizeWithColor; +- return formatValue(ctx, obj, ctx.depth); +-} +-exports.inspect = inspect; +- +- +-// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +-inspect.colors = { +- 'bold' : [1, 22], +- 'italic' : [3, 23], +- 'underline' : [4, 24], +- 'inverse' : [7, 27], +- 'white' : [37, 39], +- 'grey' : [90, 39], +- 'black' : [30, 39], +- 'blue' : [34, 39], +- 'cyan' : [36, 39], +- 'green' : [32, 39], +- 'magenta' : [35, 39], +- 'red' : [31, 39], +- 'yellow' : [33, 39] +-}; +- +-// Don't use 'blue' not visible on cmd.exe +-inspect.styles = { +- 'special': 'cyan', +- 'number': 'yellow', +- 'boolean': 'yellow', +- 'undefined': 'grey', +- 'null': 'bold', +- 'string': 'green', +- 'date': 'magenta', +- // "name": intentionally not styling +- 'regexp': 'red' +-}; +- +- +-function stylizeWithColor(str, styleType) { +- var style = inspect.styles[styleType]; +- +- if (style) { +- return '\u001b[' + inspect.colors[style][0] + 'm' + str + +- '\u001b[' + inspect.colors[style][1] + 'm'; +- } else { +- return str; +- } +-} +- +- +-function stylizeNoColor(str, styleType) { +- return str; +-} +- +- +-function arrayToHash(array) { +- var hash = {}; +- +- array.forEach(function(val, idx) { +- hash[val] = true; +- }); +- +- return hash; +-} +- +- +-function formatValue(ctx, value, recurseTimes) { +- // Provide a hook for user-specified inspect functions. +- // Check that value is an object with an inspect function on it +- if (ctx.customInspect && +- value && +- isFunction(value.inspect) && +- // Filter out the util module, it's inspect function is special +- value.inspect !== exports.inspect && +- // Also filter out any prototype objects using the circular check. +- !(value.constructor && value.constructor.prototype === value)) { +- var ret = value.inspect(recurseTimes, ctx); +- if (!isString(ret)) { +- ret = formatValue(ctx, ret, recurseTimes); +- } +- return ret; +- } +- +- // Primitive types cannot have properties +- var primitive = formatPrimitive(ctx, value); +- if (primitive) { +- return primitive; +- } +- +- // Look up the keys of the object. +- var keys = Object.keys(value); +- var visibleKeys = arrayToHash(keys); +- +- if (ctx.showHidden) { +- keys = Object.getOwnPropertyNames(value); +- } +- +- // Some type of object without properties can be shortcutted. +- if (keys.length === 0) { +- if (isFunction(value)) { +- var name = value.name ? ': ' + value.name : ''; +- return ctx.stylize('[Function' + name + ']', 'special'); +- } +- if (isRegExp(value)) { +- return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); +- } +- if (isDate(value)) { +- return ctx.stylize(Date.prototype.toString.call(value), 'date'); +- } +- if (isError(value)) { +- return formatError(value); +- } +- } +- +- var base = '', array = false, braces = ['{', '}']; +- +- // Make Array say that they are Array +- if (isArray(value)) { +- array = true; +- braces = ['[', ']']; +- } +- +- // Make functions say that they are functions +- if (isFunction(value)) { +- var n = value.name ? ': ' + value.name : ''; +- base = ' [Function' + n + ']'; +- } +- +- // Make RegExps say that they are RegExps +- if (isRegExp(value)) { +- base = ' ' + RegExp.prototype.toString.call(value); +- } +- +- // Make dates with properties first say the date +- if (isDate(value)) { +- base = ' ' + Date.prototype.toUTCString.call(value); +- } +- +- // Make error with message first say the error +- if (isError(value)) { +- base = ' ' + formatError(value); +- } +- +- if (keys.length === 0 && (!array || value.length == 0)) { +- return braces[0] + base + braces[1]; +- } +- +- if (recurseTimes < 0) { +- if (isRegExp(value)) { +- return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); +- } else { +- return ctx.stylize('[Object]', 'special'); +- } +- } +- +- ctx.seen.push(value); +- +- var output; +- if (array) { +- output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); +- } else { +- output = keys.map(function(key) { +- return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); +- }); +- } +- +- ctx.seen.pop(); +- +- return reduceToSingleString(output, base, braces); +-} +- +- +-function formatPrimitive(ctx, value) { +- if (isUndefined(value)) +- return ctx.stylize('undefined', 'undefined'); +- if (isString(value)) { +- var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') +- .replace(/'/g, "\\'") +- .replace(/\\"/g, '"') + '\''; +- return ctx.stylize(simple, 'string'); +- } +- if (isNumber(value)) +- return ctx.stylize('' + value, 'number'); +- if (isBoolean(value)) +- return ctx.stylize('' + value, 'boolean'); +- // For some reason typeof null is "object", so special case here. +- if (isNull(value)) +- return ctx.stylize('null', 'null'); +-} +- +- +-function formatError(value) { +- return '[' + Error.prototype.toString.call(value) + ']'; +-} +- +- +-function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { +- var output = []; +- for (var i = 0, l = value.length; i < l; ++i) { +- if (hasOwnProperty(value, String(i))) { +- output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, +- String(i), true)); +- } else { +- output.push(''); +- } +- } +- keys.forEach(function(key) { +- if (!key.match(/^\d+$/)) { +- output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, +- key, true)); +- } +- }); +- return output; +-} +- +- +-function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { +- var name, str, desc; +- desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; +- if (desc.get) { +- if (desc.set) { +- str = ctx.stylize('[Getter/Setter]', 'special'); +- } else { +- str = ctx.stylize('[Getter]', 'special'); +- } +- } else { +- if (desc.set) { +- str = ctx.stylize('[Setter]', 'special'); +- } +- } +- if (!hasOwnProperty(visibleKeys, key)) { +- name = '[' + key + ']'; +- } +- if (!str) { +- if (ctx.seen.indexOf(desc.value) < 0) { +- if (isNull(recurseTimes)) { +- str = formatValue(ctx, desc.value, null); +- } else { +- str = formatValue(ctx, desc.value, recurseTimes - 1); +- } +- if (str.indexOf('\n') > -1) { +- if (array) { +- str = str.split('\n').map(function(line) { +- return ' ' + line; +- }).join('\n').substr(2); +- } else { +- str = '\n' + str.split('\n').map(function(line) { +- return ' ' + line; +- }).join('\n'); +- } +- } +- } else { +- str = ctx.stylize('[Circular]', 'special'); +- } +- } +- if (isUndefined(name)) { +- if (array && key.match(/^\d+$/)) { +- return str; +- } +- name = JSON.stringify('' + key); +- if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { +- name = name.substr(1, name.length - 2); +- name = ctx.stylize(name, 'name'); +- } else { +- name = name.replace(/'/g, "\\'") +- .replace(/\\"/g, '"') +- .replace(/(^"|"$)/g, "'"); +- name = ctx.stylize(name, 'string'); +- } +- } +- +- return name + ': ' + str; +-} +- +- +-function reduceToSingleString(output, base, braces) { +- var numLinesEst = 0; +- var length = output.reduce(function(prev, cur) { +- numLinesEst++; +- if (cur.indexOf('\n') >= 0) numLinesEst++; +- return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; +- }, 0); +- +- if (length > 60) { +- return braces[0] + +- (base === '' ? '' : base + '\n ') + +- ' ' + +- output.join(',\n ') + +- ' ' + +- braces[1]; +- } +- +- return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +-} +- +- + // NOTE: These type checking functions intentionally don't use `instanceof` + // because it is fragile and can be easily faked with `Object.create()`. + function isArray(ar) { +@@ -523,159 +104,3 @@ exports.isBuffer = isBuffer; + function objectToString(o) { + return Object.prototype.toString.call(o); + } +- +- +-function pad(n) { +- return n < 10 ? '0' + n.toString(10) : n.toString(10); +-} +- +- +-var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', +- 'Oct', 'Nov', 'Dec']; +- +-// 26 Feb 16:19:34 +-function timestamp() { +- var d = new Date(); +- var time = [pad(d.getHours()), +- pad(d.getMinutes()), +- pad(d.getSeconds())].join(':'); +- return [d.getDate(), months[d.getMonth()], time].join(' '); +-} +- +- +-// log is just a thin wrapper to console.log that prepends a timestamp +-exports.log = function() { +- console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); +-}; +- +- +-/** +- * Inherit the prototype methods from one constructor into another. +- * +- * The Function.prototype.inherits from lang.js rewritten as a standalone +- * function (not on Function.prototype). NOTE: If this file is to be loaded +- * during bootstrapping this function needs to be rewritten using some native +- * functions as prototype setup using normal JavaScript does not work as +- * expected during bootstrapping (see mirror.js in r114903). +- * +- * @param {function} ctor Constructor function which needs to inherit the +- * prototype. +- * @param {function} superCtor Constructor function to inherit prototype from. +- */ +-exports.inherits = function(ctor, superCtor) { +- ctor.super_ = superCtor; +- ctor.prototype = Object.create(superCtor.prototype, { +- constructor: { +- value: ctor, +- enumerable: false, +- writable: true, +- configurable: true +- } +- }); +-}; +- +-exports._extend = function(origin, add) { +- // Don't do anything if add isn't an object +- if (!add || !isObject(add)) return origin; +- +- var keys = Object.keys(add); +- var i = keys.length; +- while (i--) { +- origin[keys[i]] = add[keys[i]]; +- } +- return origin; +-}; +- +-function hasOwnProperty(obj, prop) { +- return Object.prototype.hasOwnProperty.call(obj, prop); +-} +- +- +-// Deprecated old stuff. +- +-exports.p = exports.deprecate(function() { +- for (var i = 0, len = arguments.length; i < len; ++i) { +- console.error(exports.inspect(arguments[i])); +- } +-}, 'util.p: Use console.error() instead'); +- +- +-exports.exec = exports.deprecate(function() { +- return require('child_process').exec.apply(this, arguments); +-}, 'util.exec is now called `child_process.exec`.'); +- +- +-exports.print = exports.deprecate(function() { +- for (var i = 0, len = arguments.length; i < len; ++i) { +- process.stdout.write(String(arguments[i])); +- } +-}, 'util.print: Use console.log instead'); +- +- +-exports.puts = exports.deprecate(function() { +- for (var i = 0, len = arguments.length; i < len; ++i) { +- process.stdout.write(arguments[i] + '\n'); +- } +-}, 'util.puts: Use console.log instead'); +- +- +-exports.debug = exports.deprecate(function(x) { +- process.stderr.write('DEBUG: ' + x + '\n'); +-}, 'util.debug: Use console.error instead'); +- +- +-exports.error = exports.deprecate(function(x) { +- for (var i = 0, len = arguments.length; i < len; ++i) { +- process.stderr.write(arguments[i] + '\n'); +- } +-}, 'util.error: Use console.error instead'); +- +- +-exports.pump = exports.deprecate(function(readStream, writeStream, callback) { +- var callbackCalled = false; +- +- function call(a, b, c) { +- if (callback && !callbackCalled) { +- callback(a, b, c); +- callbackCalled = true; +- } +- } +- +- readStream.addListener('data', function(chunk) { +- if (writeStream.write(chunk) === false) readStream.pause(); +- }); +- +- writeStream.addListener('drain', function() { +- readStream.resume(); +- }); +- +- readStream.addListener('end', function() { +- writeStream.end(); +- }); +- +- readStream.addListener('close', function() { +- call(); +- }); +- +- readStream.addListener('error', function(err) { +- writeStream.end(); +- call(err); +- }); +- +- writeStream.addListener('error', function(err) { +- readStream.destroy(); +- call(err); +- }); +-}, 'util.pump(): Use readableStream.pipe() instead'); +- +- +-var uv; +-exports._errnoException = function(err, syscall) { +- if (isUndefined(uv)) uv = process.binding('uv'); +- var errname = uv.errname(err); +- var e = new Error(syscall + ' ' + errname); +- e.code = errname; +- e.errno = errname; +- e.syscall = syscall; +- return e; +-}; diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/core-util-is/lib/util.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/core-util-is/lib/util.js new file mode 100644 index 0000000..007fa10 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/core-util-is/lib/util.js @@ -0,0 +1,106 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar); +} +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; + +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; +} +exports.isNullOrUndefined = isNullOrUndefined; + +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; + +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; + +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; + +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; + +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} +exports.isObject = isObject; + +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; + +function isError(e) { + return isObject(e) && objectToString(e) === '[object Error]'; +} +exports.isError = isError; + +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; + +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; + +function isBuffer(arg) { + return arg instanceof Buffer; +} +exports.isBuffer = isBuffer; + +function objectToString(o) { + return Object.prototype.toString.call(o); +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/core-util-is/package.json b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/core-util-is/package.json new file mode 100644 index 0000000..5870349 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/core-util-is/package.json @@ -0,0 +1,38 @@ +{ + "name": "core-util-is", + "version": "1.0.0", + "description": "The `util.is*` functions introduced in Node v0.12.", + "main": "lib/util.js", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/core-util-is" + }, + "keywords": [ + "util", + "isBuffer", + "isArray", + "isNumber", + "isString", + "isRegExp", + "isThis", + "isThat", + "polyfill" + ], + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me/" + }, + "license": "MIT", + "bugs": { + "url": "https://github.com/isaacs/core-util-is/issues" + }, + "readme": "# core-util-is\n\nThe `util.is*` functions introduced in Node v0.12.\n", + "readmeFilename": "README.md", + "_id": "core-util-is@1.0.0", + "dist": { + "shasum": "152a6bee4ee9d74c2b90ded347ae32dc2d48eb56" + }, + "_from": "core-util-is@~1.0.0", + "_resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.0.tgz" +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/core-util-is/util.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/core-util-is/util.js new file mode 100644 index 0000000..007fa10 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/core-util-is/util.js @@ -0,0 +1,106 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar); +} +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; + +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; +} +exports.isNullOrUndefined = isNullOrUndefined; + +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; + +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; + +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; + +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; + +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} +exports.isObject = isObject; + +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; + +function isError(e) { + return isObject(e) && objectToString(e) === '[object Error]'; +} +exports.isError = isError; + +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; + +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; + +function isBuffer(arg) { + return arg instanceof Buffer; +} +exports.isBuffer = isBuffer; + +function objectToString(o) { + return Object.prototype.toString.call(o); +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/debuglog/LICENSE b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/debuglog/LICENSE new file mode 100644 index 0000000..a3187cc --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/debuglog/LICENSE @@ -0,0 +1,19 @@ +Copyright Joyent, Inc. and other Node contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/debuglog/README.md b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/debuglog/README.md new file mode 100644 index 0000000..dc6fcce --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/debuglog/README.md @@ -0,0 +1,40 @@ +# debuglog - backport of util.debuglog() from node v0.11 + +To facilitate using the `util.debuglog()` function that will be available when +node v0.12 is released now, this is a copy extracted from the source. + +## require('debuglog') + +Return `util.debuglog`, if it exists, otherwise it will return an internal copy +of the implementation from node v0.11. + +## debuglog(section) + +* `section` {String} The section of the program to be debugged +* Returns: {Function} The logging function + +This is used to create a function which conditionally writes to stderr +based on the existence of a `NODE_DEBUG` environment variable. If the +`section` name appears in that environment variable, then the returned +function will be similar to `console.error()`. If not, then the +returned function is a no-op. + +For example: + +```javascript +var debuglog = util.debuglog('foo'); + +var bar = 123; +debuglog('hello from foo [%d]', bar); +``` + +If this program is run with `NODE_DEBUG=foo` in the environment, then +it will output something like: + + FOO 3245: hello from foo [123] + +where `3245` is the process id. If it is not run with that +environment variable set, then it will not print anything. + +You may separate multiple `NODE_DEBUG` environment variables with a +comma. For example, `NODE_DEBUG=fs,net,tls`. diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/debuglog/debuglog.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/debuglog/debuglog.js new file mode 100644 index 0000000..da465c2 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/debuglog/debuglog.js @@ -0,0 +1,22 @@ +var util = require('util'); + +module.exports = util.debuglog || debuglog; + +var debugs = {}; +var debugEnviron = process.env.NODE_DEBUG || ''; + +function debuglog(set) { + set = set.toUpperCase(); + if (!debugs[set]) { + if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { + var pid = process.pid; + debugs[set] = function() { + var msg = util.format.apply(exports, arguments); + console.error('%s %d: %s', set, pid, msg); + }; + } else { + debugs[set] = function() {}; + } + } + return debugs[set]; +}; diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/debuglog/package.json b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/debuglog/package.json new file mode 100644 index 0000000..87f069a --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/node_modules/debuglog/package.json @@ -0,0 +1,29 @@ +{ + "name": "debuglog", + "version": "0.0.2", + "description": "backport of util.debuglog from node v0.11", + "license": "MIT", + "main": "debuglog.js", + "repository": { + "type": "git", + "url": "https://github.com/sam-github/node-debuglog.git" + }, + "author": { + "name": "Sam Roberts", + "email": "sam@strongloop.com" + }, + "engines": { + "node": "*" + }, + "readme": "# debuglog - backport of util.debuglog() from node v0.11\n\nTo facilitate using the `util.debuglog()` function that will be available when\nnode v0.12 is released now, this is a copy extracted from the source.\n\n## require('debuglog')\n\nReturn `util.debuglog`, if it exists, otherwise it will return an internal copy\nof the implementation from node v0.11.\n\n## debuglog(section)\n\n* `section` {String} The section of the program to be debugged\n* Returns: {Function} The logging function\n\nThis is used to create a function which conditionally writes to stderr\nbased on the existence of a `NODE_DEBUG` environment variable. If the\n`section` name appears in that environment variable, then the returned\nfunction will be similar to `console.error()`. If not, then the\nreturned function is a no-op.\n\nFor example:\n\n```javascript\nvar debuglog = util.debuglog('foo');\n\nvar bar = 123;\ndebuglog('hello from foo [%d]', bar);\n```\n\nIf this program is run with `NODE_DEBUG=foo` in the environment, then\nit will output something like:\n\n FOO 3245: hello from foo [123]\n\nwhere `3245` is the process id. If it is not run with that\nenvironment variable set, then it will not print anything.\n\nYou may separate multiple `NODE_DEBUG` environment variables with a\ncomma. For example, `NODE_DEBUG=fs,net,tls`.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/sam-github/node-debuglog/issues" + }, + "_id": "debuglog@0.0.2", + "dist": { + "shasum": "a0e439ca87738aff3813659190fd30842ffea6f4" + }, + "_from": "debuglog@0.0.2", + "_resolved": "https://registry.npmjs.org/debuglog/-/debuglog-0.0.2.tgz" +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/package.json b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/package.json new file mode 100644 index 0000000..2f1b958 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/package.json @@ -0,0 +1,45 @@ +{ + "name": "readable-stream", + "version": "1.1.9", + "description": "An exploration of a new kind of readable streams for Node.js", + "main": "readable.js", + "dependencies": { + "core-util-is": "~1.0.0", + "debuglog": "0.0.2" + }, + "devDependencies": { + "tap": "~0.2.6" + }, + "scripts": { + "test": "tap test/simple/*.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/isaacs/readable-stream" + }, + "keywords": [ + "readable", + "stream", + "pipe" + ], + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me/" + }, + "license": "MIT", + "optionalDependencies": { + "debuglog": "0.0.2" + }, + "readme": "# readable-stream\n\nA new class of streams for Node.js\n\nThis module provides the new Stream base classes introduced in Node\nv0.10, for use in Node v0.8. You can use it to have programs that\nhave to work with node v0.8, while being forward-compatible for v0.10\nand beyond. When you drop support for v0.8, you can remove this\nmodule, and only use the native streams.\n\nThis is almost exactly the same codebase as appears in Node v0.10.\nHowever:\n\n1. The exported object is actually the Readable class. Decorating the\n native `stream` module would be global pollution.\n2. In v0.10, you can safely use `base64` as an argument to\n `setEncoding` in Readable streams. However, in v0.8, the\n StringDecoder class has no `end()` method, which is problematic for\n Base64. So, don't use that, because it'll break and be weird.\n\nOther than that, the API is the same as `require('stream')` in v0.10,\nso the API docs are reproduced below.\n\n----------\n\n Stability: 2 - Unstable\n\nA stream is an abstract interface implemented by various objects in\nNode. For example a request to an HTTP server is a stream, as is\nstdout. Streams are readable, writable, or both. All streams are\ninstances of [EventEmitter][]\n\nYou can load the Stream base classes by doing `require('stream')`.\nThere are base classes provided for Readable streams, Writable\nstreams, Duplex streams, and Transform streams.\n\n## Compatibility\n\nIn earlier versions of Node, the Readable stream interface was\nsimpler, but also less powerful and less useful.\n\n* Rather than waiting for you to call the `read()` method, `'data'`\n events would start emitting immediately. If you needed to do some\n I/O to decide how to handle data, then you had to store the chunks\n in some kind of buffer so that they would not be lost.\n* The `pause()` method was advisory, rather than guaranteed. This\n meant that you still had to be prepared to receive `'data'` events\n even when the stream was in a paused state.\n\nIn Node v0.10, the Readable class described below was added. For\nbackwards compatibility with older Node programs, Readable streams\nswitch into \"old mode\" when a `'data'` event handler is added, or when\nthe `pause()` or `resume()` methods are called. The effect is that,\neven if you are not using the new `read()` method and `'readable'`\nevent, you no longer have to worry about losing `'data'` chunks.\n\nMost programs will continue to function normally. However, this\nintroduces an edge case in the following conditions:\n\n* No `'data'` event handler is added.\n* The `pause()` and `resume()` methods are never called.\n\nFor example, consider the following code:\n\n```javascript\n// WARNING! BROKEN!\nnet.createServer(function(socket) {\n\n // we add an 'end' method, but never consume the data\n socket.on('end', function() {\n // It will never get here.\n socket.end('I got your message (but didnt read it)\\n');\n });\n\n}).listen(1337);\n```\n\nIn versions of node prior to v0.10, the incoming message data would be\nsimply discarded. However, in Node v0.10 and beyond, the socket will\nremain paused forever.\n\nThe workaround in this situation is to call the `resume()` method to\ntrigger \"old mode\" behavior:\n\n```javascript\n// Workaround\nnet.createServer(function(socket) {\n\n socket.on('end', function() {\n socket.end('I got your message (but didnt read it)\\n');\n });\n\n // start the flow of data, discarding it.\n socket.resume();\n\n}).listen(1337);\n```\n\nIn addition to new Readable streams switching into old-mode, pre-v0.10\nstyle streams can be wrapped in a Readable class using the `wrap()`\nmethod.\n\n## Class: stream.Readable\n\n\n\nA `Readable Stream` has the following methods, members, and events.\n\nNote that `stream.Readable` is an abstract class designed to be\nextended with an underlying implementation of the `_read(size)`\nmethod. (See below.)\n\n### new stream.Readable([options])\n\n* `options` {Object}\n * `highWaterMark` {Number} The maximum number of bytes to store in\n the internal buffer before ceasing to read from the underlying\n resource. Default=16kb\n * `encoding` {String} If specified, then buffers will be decoded to\n strings using the specified encoding. Default=null\n * `objectMode` {Boolean} Whether this stream should behave\n as a stream of objects. Meaning that stream.read(n) returns\n a single value instead of a Buffer of size n\n\nIn classes that extend the Readable class, make sure to call the\nconstructor so that the buffering settings can be properly\ninitialized.\n\n### readable.\\_read(size)\n\n* `size` {Number} Number of bytes to read asynchronously\n\nNote: **This function should NOT be called directly.** It should be\nimplemented by child classes, and called by the internal Readable\nclass methods only.\n\nAll Readable stream implementations must provide a `_read` method\nto fetch data from the underlying resource.\n\nThis method is prefixed with an underscore because it is internal to\nthe class that defines it, and should not be called directly by user\nprograms. However, you **are** expected to override this method in\nyour own extension classes.\n\nWhen data is available, put it into the read queue by calling\n`readable.push(chunk)`. If `push` returns false, then you should stop\nreading. When `_read` is called again, you should start pushing more\ndata.\n\nThe `size` argument is advisory. Implementations where a \"read\" is a\nsingle call that returns data can use this to know how much data to\nfetch. Implementations where that is not relevant, such as TCP or\nTLS, may ignore this argument, and simply provide data whenever it\nbecomes available. There is no need, for example to \"wait\" until\n`size` bytes are available before calling `stream.push(chunk)`.\n\n### readable.push(chunk)\n\n* `chunk` {Buffer | null | String} Chunk of data to push into the read queue\n* return {Boolean} Whether or not more pushes should be performed\n\nNote: **This function should be called by Readable implementors, NOT\nby consumers of Readable subclasses.** The `_read()` function will not\nbe called again until at least one `push(chunk)` call is made. If no\ndata is available, then you MAY call `push('')` (an empty string) to\nallow a future `_read` call, without adding any data to the queue.\n\nThe `Readable` class works by putting data into a read queue to be\npulled out later by calling the `read()` method when the `'readable'`\nevent fires.\n\nThe `push()` method will explicitly insert some data into the read\nqueue. If it is called with `null` then it will signal the end of the\ndata.\n\nIn some cases, you may be wrapping a lower-level source which has some\nsort of pause/resume mechanism, and a data callback. In those cases,\nyou could wrap the low-level source object by doing something like\nthis:\n\n```javascript\n// source is an object with readStop() and readStart() methods,\n// and an `ondata` member that gets called when it has data, and\n// an `onend` member that gets called when the data is over.\n\nvar stream = new Readable();\n\nsource.ondata = function(chunk) {\n // if push() returns false, then we need to stop reading from source\n if (!stream.push(chunk))\n source.readStop();\n};\n\nsource.onend = function() {\n stream.push(null);\n};\n\n// _read will be called when the stream wants to pull more data in\n// the advisory size argument is ignored in this case.\nstream._read = function(n) {\n source.readStart();\n};\n```\n\n### readable.unshift(chunk)\n\n* `chunk` {Buffer | null | String} Chunk of data to unshift onto the read queue\n* return {Boolean} Whether or not more pushes should be performed\n\nThis is the corollary of `readable.push(chunk)`. Rather than putting\nthe data at the *end* of the read queue, it puts it at the *front* of\nthe read queue.\n\nThis is useful in certain use-cases where a stream is being consumed\nby a parser, which needs to \"un-consume\" some data that it has\noptimistically pulled out of the source.\n\n```javascript\n// A parser for a simple data protocol.\n// The \"header\" is a JSON object, followed by 2 \\n characters, and\n// then a message body.\n//\n// Note: This can be done more simply as a Transform stream. See below.\n\nfunction SimpleProtocol(source, options) {\n if (!(this instanceof SimpleProtocol))\n return new SimpleProtocol(options);\n\n Readable.call(this, options);\n this._inBody = false;\n this._sawFirstCr = false;\n\n // source is a readable stream, such as a socket or file\n this._source = source;\n\n var self = this;\n source.on('end', function() {\n self.push(null);\n });\n\n // give it a kick whenever the source is readable\n // read(0) will not consume any bytes\n source.on('readable', function() {\n self.read(0);\n });\n\n this._rawHeader = [];\n this.header = null;\n}\n\nSimpleProtocol.prototype = Object.create(\n Readable.prototype, { constructor: { value: SimpleProtocol }});\n\nSimpleProtocol.prototype._read = function(n) {\n if (!this._inBody) {\n var chunk = this._source.read();\n\n // if the source doesn't have data, we don't have data yet.\n if (chunk === null)\n return this.push('');\n\n // check if the chunk has a \\n\\n\n var split = -1;\n for (var i = 0; i < chunk.length; i++) {\n if (chunk[i] === 10) { // '\\n'\n if (this._sawFirstCr) {\n split = i;\n break;\n } else {\n this._sawFirstCr = true;\n }\n } else {\n this._sawFirstCr = false;\n }\n }\n\n if (split === -1) {\n // still waiting for the \\n\\n\n // stash the chunk, and try again.\n this._rawHeader.push(chunk);\n this.push('');\n } else {\n this._inBody = true;\n var h = chunk.slice(0, split);\n this._rawHeader.push(h);\n var header = Buffer.concat(this._rawHeader).toString();\n try {\n this.header = JSON.parse(header);\n } catch (er) {\n this.emit('error', new Error('invalid simple protocol data'));\n return;\n }\n // now, because we got some extra data, unshift the rest\n // back into the read queue so that our consumer will see it.\n var b = chunk.slice(split);\n this.unshift(b);\n\n // and let them know that we are done parsing the header.\n this.emit('header', this.header);\n }\n } else {\n // from there on, just provide the data to our consumer.\n // careful not to push(null), since that would indicate EOF.\n var chunk = this._source.read();\n if (chunk) this.push(chunk);\n }\n};\n\n// Usage:\nvar parser = new SimpleProtocol(source);\n// Now parser is a readable stream that will emit 'header'\n// with the parsed header data.\n```\n\n### readable.wrap(stream)\n\n* `stream` {Stream} An \"old style\" readable stream\n\nIf you are using an older Node library that emits `'data'` events and\nhas a `pause()` method that is advisory only, then you can use the\n`wrap()` method to create a Readable stream that uses the old stream\nas its data source.\n\nFor example:\n\n```javascript\nvar OldReader = require('./old-api-module.js').OldReader;\nvar oreader = new OldReader;\nvar Readable = require('stream').Readable;\nvar myReader = new Readable().wrap(oreader);\n\nmyReader.on('readable', function() {\n myReader.read(); // etc.\n});\n```\n\n### Event: 'readable'\n\nWhen there is data ready to be consumed, this event will fire.\n\nWhen this event emits, call the `read()` method to consume the data.\n\n### Event: 'end'\n\nEmitted when the stream has received an EOF (FIN in TCP terminology).\nIndicates that no more `'data'` events will happen. If the stream is\nalso writable, it may be possible to continue writing.\n\n### Event: 'data'\n\nThe `'data'` event emits either a `Buffer` (by default) or a string if\n`setEncoding()` was used.\n\nNote that adding a `'data'` event listener will switch the Readable\nstream into \"old mode\", where data is emitted as soon as it is\navailable, rather than waiting for you to call `read()` to consume it.\n\n### Event: 'error'\n\nEmitted if there was an error receiving data.\n\n### Event: 'close'\n\nEmitted when the underlying resource (for example, the backing file\ndescriptor) has been closed. Not all streams will emit this.\n\n### readable.setEncoding(encoding)\n\nMakes the `'data'` event emit a string instead of a `Buffer`. `encoding`\ncan be `'utf8'`, `'utf16le'` (`'ucs2'`), `'ascii'`, or `'hex'`.\n\nThe encoding can also be set by specifying an `encoding` field to the\nconstructor.\n\n### readable.read([size])\n\n* `size` {Number | null} Optional number of bytes to read.\n* Return: {Buffer | String | null}\n\nNote: **This function SHOULD be called by Readable stream users.**\n\nCall this method to consume data once the `'readable'` event is\nemitted.\n\nThe `size` argument will set a minimum number of bytes that you are\ninterested in. If not set, then the entire content of the internal\nbuffer is returned.\n\nIf there is no data to consume, or if there are fewer bytes in the\ninternal buffer than the `size` argument, then `null` is returned, and\na future `'readable'` event will be emitted when more is available.\n\nCalling `stream.read(0)` will always return `null`, and will trigger a\nrefresh of the internal buffer, but otherwise be a no-op.\n\n### readable.pipe(destination, [options])\n\n* `destination` {Writable Stream}\n* `options` {Object} Optional\n * `end` {Boolean} Default=true\n\nConnects this readable stream to `destination` WriteStream. Incoming\ndata on this stream gets written to `destination`. Properly manages\nback-pressure so that a slow destination will not be overwhelmed by a\nfast readable stream.\n\nThis function returns the `destination` stream.\n\nFor example, emulating the Unix `cat` command:\n\n process.stdin.pipe(process.stdout);\n\nBy default `end()` is called on the destination when the source stream\nemits `end`, so that `destination` is no longer writable. Pass `{ end:\nfalse }` as `options` to keep the destination stream open.\n\nThis keeps `writer` open so that \"Goodbye\" can be written at the\nend.\n\n reader.pipe(writer, { end: false });\n reader.on(\"end\", function() {\n writer.end(\"Goodbye\\n\");\n });\n\nNote that `process.stderr` and `process.stdout` are never closed until\nthe process exits, regardless of the specified options.\n\n### readable.unpipe([destination])\n\n* `destination` {Writable Stream} Optional\n\nUndo a previously established `pipe()`. If no destination is\nprovided, then all previously established pipes are removed.\n\n### readable.pause()\n\nSwitches the readable stream into \"old mode\", where data is emitted\nusing a `'data'` event rather than being buffered for consumption via\nthe `read()` method.\n\nCeases the flow of data. No `'data'` events are emitted while the\nstream is in a paused state.\n\n### readable.resume()\n\nSwitches the readable stream into \"old mode\", where data is emitted\nusing a `'data'` event rather than being buffered for consumption via\nthe `read()` method.\n\nResumes the incoming `'data'` events after a `pause()`.\n\n\n## Class: stream.Writable\n\n\n\nA `Writable` Stream has the following methods, members, and events.\n\nNote that `stream.Writable` is an abstract class designed to be\nextended with an underlying implementation of the\n`_write(chunk, encoding, cb)` method. (See below.)\n\n### new stream.Writable([options])\n\n* `options` {Object}\n * `highWaterMark` {Number} Buffer level when `write()` starts\n returning false. Default=16kb\n * `decodeStrings` {Boolean} Whether or not to decode strings into\n Buffers before passing them to `_write()`. Default=true\n\nIn classes that extend the Writable class, make sure to call the\nconstructor so that the buffering settings can be properly\ninitialized.\n\n### writable.\\_write(chunk, encoding, callback)\n\n* `chunk` {Buffer | String} The chunk to be written. Will always\n be a buffer unless the `decodeStrings` option was set to `false`.\n* `encoding` {String} If the chunk is a string, then this is the\n encoding type. Ignore chunk is a buffer. Note that chunk will\n **always** be a buffer unless the `decodeStrings` option is\n explicitly set to `false`.\n* `callback` {Function} Call this function (optionally with an error\n argument) when you are done processing the supplied chunk.\n\nAll Writable stream implementations must provide a `_write` method to\nsend data to the underlying resource.\n\nNote: **This function MUST NOT be called directly.** It should be\nimplemented by child classes, and called by the internal Writable\nclass methods only.\n\nCall the callback using the standard `callback(error)` pattern to\nsignal that the write completed successfully or with an error.\n\nIf the `decodeStrings` flag is set in the constructor options, then\n`chunk` may be a string rather than a Buffer, and `encoding` will\nindicate the sort of string that it is. This is to support\nimplementations that have an optimized handling for certain string\ndata encodings. If you do not explicitly set the `decodeStrings`\noption to `false`, then you can safely ignore the `encoding` argument,\nand assume that `chunk` will always be a Buffer.\n\nThis method is prefixed with an underscore because it is internal to\nthe class that defines it, and should not be called directly by user\nprograms. However, you **are** expected to override this method in\nyour own extension classes.\n\n\n### writable.write(chunk, [encoding], [callback])\n\n* `chunk` {Buffer | String} Data to be written\n* `encoding` {String} Optional. If `chunk` is a string, then encoding\n defaults to `'utf8'`\n* `callback` {Function} Optional. Called when this chunk is\n successfully written.\n* Returns {Boolean}\n\nWrites `chunk` to the stream. Returns `true` if the data has been\nflushed to the underlying resource. Returns `false` to indicate that\nthe buffer is full, and the data will be sent out in the future. The\n`'drain'` event will indicate when the buffer is empty again.\n\nThe specifics of when `write()` will return false, is determined by\nthe `highWaterMark` option provided to the constructor.\n\n### writable.end([chunk], [encoding], [callback])\n\n* `chunk` {Buffer | String} Optional final data to be written\n* `encoding` {String} Optional. If `chunk` is a string, then encoding\n defaults to `'utf8'`\n* `callback` {Function} Optional. Called when the final chunk is\n successfully written.\n\nCall this method to signal the end of the data being written to the\nstream.\n\n### Event: 'drain'\n\nEmitted when the stream's write queue empties and it's safe to write\nwithout buffering again. Listen for it when `stream.write()` returns\n`false`.\n\n### Event: 'close'\n\nEmitted when the underlying resource (for example, the backing file\ndescriptor) has been closed. Not all streams will emit this.\n\n### Event: 'finish'\n\nWhen `end()` is called and there are no more chunks to write, this\nevent is emitted.\n\n### Event: 'pipe'\n\n* `source` {Readable Stream}\n\nEmitted when the stream is passed to a readable stream's pipe method.\n\n### Event 'unpipe'\n\n* `source` {Readable Stream}\n\nEmitted when a previously established `pipe()` is removed using the\nsource Readable stream's `unpipe()` method.\n\n## Class: stream.Duplex\n\n\n\nA \"duplex\" stream is one that is both Readable and Writable, such as a\nTCP socket connection.\n\nNote that `stream.Duplex` is an abstract class designed to be\nextended with an underlying implementation of the `_read(size)`\nand `_write(chunk, encoding, callback)` methods as you would with a Readable or\nWritable stream class.\n\nSince JavaScript doesn't have multiple prototypal inheritance, this\nclass prototypally inherits from Readable, and then parasitically from\nWritable. It is thus up to the user to implement both the lowlevel\n`_read(n)` method as well as the lowlevel `_write(chunk, encoding, cb)` method\non extension duplex classes.\n\n### new stream.Duplex(options)\n\n* `options` {Object} Passed to both Writable and Readable\n constructors. Also has the following fields:\n * `allowHalfOpen` {Boolean} Default=true. If set to `false`, then\n the stream will automatically end the readable side when the\n writable side ends and vice versa.\n\nIn classes that extend the Duplex class, make sure to call the\nconstructor so that the buffering settings can be properly\ninitialized.\n\n## Class: stream.Transform\n\nA \"transform\" stream is a duplex stream where the output is causally\nconnected in some way to the input, such as a zlib stream or a crypto\nstream.\n\nThere is no requirement that the output be the same size as the input,\nthe same number of chunks, or arrive at the same time. For example, a\nHash stream will only ever have a single chunk of output which is\nprovided when the input is ended. A zlib stream will either produce\nmuch smaller or much larger than its input.\n\nRather than implement the `_read()` and `_write()` methods, Transform\nclasses must implement the `_transform()` method, and may optionally\nalso implement the `_flush()` method. (See below.)\n\n### new stream.Transform([options])\n\n* `options` {Object} Passed to both Writable and Readable\n constructors.\n\nIn classes that extend the Transform class, make sure to call the\nconstructor so that the buffering settings can be properly\ninitialized.\n\n### transform.\\_transform(chunk, encoding, callback)\n\n* `chunk` {Buffer | String} The chunk to be transformed. Will always\n be a buffer unless the `decodeStrings` option was set to `false`.\n* `encoding` {String} If the chunk is a string, then this is the\n encoding type. (Ignore if `decodeStrings` chunk is a buffer.)\n* `callback` {Function} Call this function (optionally with an error\n argument) when you are done processing the supplied chunk.\n\nNote: **This function MUST NOT be called directly.** It should be\nimplemented by child classes, and called by the internal Transform\nclass methods only.\n\nAll Transform stream implementations must provide a `_transform`\nmethod to accept input and produce output.\n\n`_transform` should do whatever has to be done in this specific\nTransform class, to handle the bytes being written, and pass them off\nto the readable portion of the interface. Do asynchronous I/O,\nprocess things, and so on.\n\nCall `transform.push(outputChunk)` 0 or more times to generate output\nfrom this input chunk, depending on how much data you want to output\nas a result of this chunk.\n\nCall the callback function only when the current chunk is completely\nconsumed. Note that there may or may not be output as a result of any\nparticular input chunk.\n\nThis method is prefixed with an underscore because it is internal to\nthe class that defines it, and should not be called directly by user\nprograms. However, you **are** expected to override this method in\nyour own extension classes.\n\n### transform.\\_flush(callback)\n\n* `callback` {Function} Call this function (optionally with an error\n argument) when you are done flushing any remaining data.\n\nNote: **This function MUST NOT be called directly.** It MAY be implemented\nby child classes, and if so, will be called by the internal Transform\nclass methods only.\n\nIn some cases, your transform operation may need to emit a bit more\ndata at the end of the stream. For example, a `Zlib` compression\nstream will store up some internal state so that it can optimally\ncompress the output. At the end, however, it needs to do the best it\ncan with what is left, so that the data will be complete.\n\nIn those cases, you can implement a `_flush` method, which will be\ncalled at the very end, after all the written data is consumed, but\nbefore emitting `end` to signal the end of the readable side. Just\nlike with `_transform`, call `transform.push(chunk)` zero or more\ntimes, as appropriate, and call `callback` when the flush operation is\ncomplete.\n\nThis method is prefixed with an underscore because it is internal to\nthe class that defines it, and should not be called directly by user\nprograms. However, you **are** expected to override this method in\nyour own extension classes.\n\n### Example: `SimpleProtocol` parser\n\nThe example above of a simple protocol parser can be implemented much\nmore simply by using the higher level `Transform` stream class.\n\nIn this example, rather than providing the input as an argument, it\nwould be piped into the parser, which is a more idiomatic Node stream\napproach.\n\n```javascript\nfunction SimpleProtocol(options) {\n if (!(this instanceof SimpleProtocol))\n return new SimpleProtocol(options);\n\n Transform.call(this, options);\n this._inBody = false;\n this._sawFirstCr = false;\n this._rawHeader = [];\n this.header = null;\n}\n\nSimpleProtocol.prototype = Object.create(\n Transform.prototype, { constructor: { value: SimpleProtocol }});\n\nSimpleProtocol.prototype._transform = function(chunk, encoding, done) {\n if (!this._inBody) {\n // check if the chunk has a \\n\\n\n var split = -1;\n for (var i = 0; i < chunk.length; i++) {\n if (chunk[i] === 10) { // '\\n'\n if (this._sawFirstCr) {\n split = i;\n break;\n } else {\n this._sawFirstCr = true;\n }\n } else {\n this._sawFirstCr = false;\n }\n }\n\n if (split === -1) {\n // still waiting for the \\n\\n\n // stash the chunk, and try again.\n this._rawHeader.push(chunk);\n } else {\n this._inBody = true;\n var h = chunk.slice(0, split);\n this._rawHeader.push(h);\n var header = Buffer.concat(this._rawHeader).toString();\n try {\n this.header = JSON.parse(header);\n } catch (er) {\n this.emit('error', new Error('invalid simple protocol data'));\n return;\n }\n // and let them know that we are done parsing the header.\n this.emit('header', this.header);\n\n // now, because we got some extra data, emit this first.\n this.push(b);\n }\n } else {\n // from there on, just provide the data to our consumer as-is.\n this.push(b);\n }\n done();\n};\n\nvar parser = new SimpleProtocol();\nsource.pipe(parser)\n\n// Now parser is a readable stream that will emit 'header'\n// with the parsed header data.\n```\n\n\n## Class: stream.PassThrough\n\nThis is a trivial implementation of a `Transform` stream that simply\npasses the input bytes across to the output. Its purpose is mainly\nfor examples and testing, but there are occasionally use cases where\nit can come in handy.\n\n\n[EventEmitter]: events.html#events_class_events_eventemitter\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/readable-stream/issues" + }, + "_id": "readable-stream@1.1.9", + "dist": { + "shasum": "498a54a8d00748fa5e4456da4dc58f8515c3cd67" + }, + "_from": "readable-stream@~1.1.9", + "_resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.9.tgz" +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/passthrough.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/passthrough.js new file mode 100644 index 0000000..27e8d8a --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/passthrough.js @@ -0,0 +1 @@ +module.exports = require("./lib/_stream_passthrough.js") diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/readable.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/readable.js new file mode 100644 index 0000000..09b8bf5 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/readable.js @@ -0,0 +1,7 @@ +exports = module.exports = require('./lib/_stream_readable.js'); +exports.Stream = require('stream'); +exports.Readable = exports; +exports.Writable = require('./lib/_stream_writable.js'); +exports.Duplex = require('./lib/_stream_duplex.js'); +exports.Transform = require('./lib/_stream_transform.js'); +exports.PassThrough = require('./lib/_stream_passthrough.js'); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/common.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/common.js new file mode 100644 index 0000000..28faaf9 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/common.js @@ -0,0 +1,200 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var path = require('path'); +var assert = require('assert'); + +exports.testDir = path.dirname(__filename); +exports.fixturesDir = path.join(exports.testDir, 'fixtures'); +exports.libDir = path.join(exports.testDir, '../lib'); +exports.tmpDir = path.join(exports.testDir, 'tmp'); +exports.PORT = +process.env.NODE_COMMON_PORT || 12346; + +if (process.platform === 'win32') { + exports.PIPE = '\\\\.\\pipe\\libuv-test'; +} else { + exports.PIPE = exports.tmpDir + '/test.sock'; +} + +var util = require('util'); +for (var i in util) exports[i] = util[i]; +//for (var i in exports) global[i] = exports[i]; + +function protoCtrChain(o) { + var result = []; + for (; o; o = o.__proto__) { result.push(o.constructor); } + return result.join(); +} + +exports.indirectInstanceOf = function(obj, cls) { + if (obj instanceof cls) { return true; } + var clsChain = protoCtrChain(cls.prototype); + var objChain = protoCtrChain(obj); + return objChain.slice(-clsChain.length) === clsChain; +}; + + +exports.ddCommand = function(filename, kilobytes) { + if (process.platform === 'win32') { + var p = path.resolve(exports.fixturesDir, 'create-file.js'); + return '"' + process.argv[0] + '" "' + p + '" "' + + filename + '" ' + (kilobytes * 1024); + } else { + return 'dd if=/dev/zero of="' + filename + '" bs=1024 count=' + kilobytes; + } +}; + + +exports.spawnCat = function(options) { + var spawn = require('child_process').spawn; + + if (process.platform === 'win32') { + return spawn('more', [], options); + } else { + return spawn('cat', [], options); + } +}; + + +exports.spawnPwd = function(options) { + var spawn = require('child_process').spawn; + + if (process.platform === 'win32') { + return spawn('cmd.exe', ['/c', 'cd'], options); + } else { + return spawn('pwd', [], options); + } +}; + + +// Turn this off if the test should not check for global leaks. +exports.globalCheck = true; + +process.on('exit', function() { + if (!exports.globalCheck) return; + var knownGlobals = [setTimeout, + setInterval, + setImmediate, + clearTimeout, + clearInterval, + clearImmediate, + console, + Buffer, + process, + global]; + + if (global.gc) { + knownGlobals.push(gc); + } + + if (global.DTRACE_HTTP_SERVER_RESPONSE) { + knownGlobals.push(DTRACE_HTTP_SERVER_RESPONSE); + knownGlobals.push(DTRACE_HTTP_SERVER_REQUEST); + knownGlobals.push(DTRACE_HTTP_CLIENT_RESPONSE); + knownGlobals.push(DTRACE_HTTP_CLIENT_REQUEST); + knownGlobals.push(DTRACE_NET_STREAM_END); + knownGlobals.push(DTRACE_NET_SERVER_CONNECTION); + knownGlobals.push(DTRACE_NET_SOCKET_READ); + knownGlobals.push(DTRACE_NET_SOCKET_WRITE); + } + if (global.COUNTER_NET_SERVER_CONNECTION) { + knownGlobals.push(COUNTER_NET_SERVER_CONNECTION); + knownGlobals.push(COUNTER_NET_SERVER_CONNECTION_CLOSE); + knownGlobals.push(COUNTER_HTTP_SERVER_REQUEST); + knownGlobals.push(COUNTER_HTTP_SERVER_RESPONSE); + knownGlobals.push(COUNTER_HTTP_CLIENT_REQUEST); + knownGlobals.push(COUNTER_HTTP_CLIENT_RESPONSE); + } + + if (global.ArrayBuffer) { + knownGlobals.push(ArrayBuffer); + knownGlobals.push(Int8Array); + knownGlobals.push(Uint8Array); + knownGlobals.push(Uint8ClampedArray); + knownGlobals.push(Int16Array); + knownGlobals.push(Uint16Array); + knownGlobals.push(Int32Array); + knownGlobals.push(Uint32Array); + knownGlobals.push(Float32Array); + knownGlobals.push(Float64Array); + knownGlobals.push(DataView); + } + + for (var x in global) { + var found = false; + + for (var y in knownGlobals) { + if (global[x] === knownGlobals[y]) { + found = true; + break; + } + } + + if (!found) { + console.error('Unknown global: %s', x); + assert.ok(false, 'Unknown global found'); + } + } +}); + + +var mustCallChecks = []; + + +function runCallChecks(exitCode) { + if (exitCode !== 0) return; + + var failed = mustCallChecks.filter(function(context) { + return context.actual !== context.expected; + }); + + failed.forEach(function(context) { + console.log('Mismatched %s function calls. Expected %d, actual %d.', + context.name, + context.expected, + context.actual); + console.log(context.stack.split('\n').slice(2).join('\n')); + }); + + if (failed.length) process.exit(1); +} + + +exports.mustCall = function(fn, expected) { + if (typeof expected !== 'number') expected = 1; + + var context = { + expected: expected, + actual: 0, + stack: (new Error).stack, + name: fn.name || '' + }; + + // add the exit listener only once to avoid listener leak warnings + if (mustCallChecks.length === 0) process.on('exit', runCallChecks); + + mustCallChecks.push(context); + + return function() { + context.actual++; + return fn.apply(this, arguments); + }; +}; diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/fixtures/x1024.txt b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/fixtures/x1024.txt new file mode 100644 index 0000000..c6a9d2f --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/fixtures/x1024.txt @@ -0,0 +1 @@ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-GH-64.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-GH-64.js new file mode 100644 index 0000000..a51567f --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-GH-64.js @@ -0,0 +1,18 @@ +var assert = require('assert'); +var http = require('http'); +var net = require('net'); +var stream = require('readable-stream'); +var PORT = require('../common.js').PORT; + +var server = http.createServer(function (req, res) { + res.end('ok'); + server.close(function() { + console.log('ok'); + }); +}).listen(PORT, 'localhost', function () { + var client = net.connect(PORT); + client.write( + "GET / HTTP/1.1\r\n" + + "Host: localhost\r\n\r\n") + client.end(); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-GH-66.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-GH-66.js new file mode 100644 index 0000000..a51567f --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-GH-66.js @@ -0,0 +1,18 @@ +var assert = require('assert'); +var http = require('http'); +var net = require('net'); +var stream = require('readable-stream'); +var PORT = require('../common.js').PORT; + +var server = http.createServer(function (req, res) { + res.end('ok'); + server.close(function() { + console.log('ok'); + }); +}).listen(PORT, 'localhost', function () { + var client = net.connect(PORT); + client.write( + "GET / HTTP/1.1\r\n" + + "Host: localhost\r\n\r\n") + client.end(); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-big-push.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-big-push.js new file mode 100644 index 0000000..8cd2127 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-big-push.js @@ -0,0 +1,84 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); +var stream = require('../../'); +var str = 'asdfasdfasdfasdfasdf'; + +var r = new stream.Readable({ + highWaterMark: 5, + encoding: 'utf8' +}); + +var reads = 0; +var eofed = false; +var ended = false; + +r._read = function(n) { + if (reads === 0) { + setTimeout(function() { + r.push(str); + }); + reads++; + } else if (reads === 1) { + var ret = r.push(str); + assert.equal(ret, false); + reads++; + } else { + assert(!eofed); + eofed = true; + r.push(null); + } +}; + +r.on('end', function() { + ended = true; +}); + +// push some data in to start. +// we've never gotten any read event at this point. +var ret = r.push(str); +// should be false. > hwm +assert(!ret); +var chunk = r.read(); +assert.equal(chunk, str); +chunk = r.read(); +assert.equal(chunk, null); + +r.once('readable', function() { + // this time, we'll get *all* the remaining data, because + // it's been added synchronously, as the read WOULD take + // us below the hwm, and so it triggered a _read() again, + // which synchronously added more, which we then return. + chunk = r.read(); + assert.equal(chunk, str + str); + + chunk = r.read(); + assert.equal(chunk, null); +}); + +process.on('exit', function() { + assert(eofed); + assert(ended); + assert.equal(reads, 2); + console.log('ok'); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-end-paused.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-end-paused.js new file mode 100644 index 0000000..d40efc7 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-end-paused.js @@ -0,0 +1,53 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); +var gotEnd = false; + +// Make sure we don't miss the end event for paused 0-length streams + +var Readable = require('../../').Readable; +var stream = new Readable(); +var calledRead = false; +stream._read = function() { + assert(!calledRead); + calledRead = true; + this.push(null); +}; + +stream.on('data', function() { + throw new Error('should not ever get data'); +}); +stream.pause(); + +setTimeout(function() { + stream.on('end', function() { + gotEnd = true; + }); + stream.resume(); +}); + +process.on('exit', function() { + assert(gotEnd); + assert(calledRead); + console.log('ok'); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-pipe-after-end.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-pipe-after-end.js new file mode 100644 index 0000000..0be8366 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-pipe-after-end.js @@ -0,0 +1,86 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); + +var Readable = require('../../lib/_stream_readable'); +var Writable = require('../../lib/_stream_writable'); +var util = require('util'); + +util.inherits(TestReadable, Readable); +function TestReadable(opt) { + if (!(this instanceof TestReadable)) + return new TestReadable(opt); + Readable.call(this, opt); + this._ended = false; +} + +TestReadable.prototype._read = function(n) { + if (this._ended) + this.emit('error', new Error('_read called twice')); + this._ended = true; + this.push(null); +}; + +util.inherits(TestWritable, Writable); +function TestWritable(opt) { + if (!(this instanceof TestWritable)) + return new TestWritable(opt); + Writable.call(this, opt); + this._written = []; +} + +TestWritable.prototype._write = function(chunk, encoding, cb) { + this._written.push(chunk); + cb(); +}; + +// this one should not emit 'end' until we read() from it later. +var ender = new TestReadable(); +var enderEnded = false; + +// what happens when you pipe() a Readable that's already ended? +var piper = new TestReadable(); +// pushes EOF null, and length=0, so this will trigger 'end' +piper.read(); + +setTimeout(function() { + ender.on('end', function() { + enderEnded = true; + }); + assert(!enderEnded); + var c = ender.read(); + assert.equal(c, null); + + var w = new TestWritable(); + var writableFinished = false; + w.on('finish', function() { + writableFinished = true; + }); + piper.pipe(w); + + process.on('exit', function() { + assert(enderEnded); + assert(writableFinished); + console.log('ok'); + }); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-pipe-error-handling.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-pipe-error-handling.js new file mode 100644 index 0000000..c7d6b7d --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-pipe-error-handling.js @@ -0,0 +1,131 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); +var Stream = require('../../').Stream; + +(function testErrorListenerCatches() { + var source = new Stream(); + var dest = new Stream(); + + source.pipe(dest); + + var gotErr = null; + source.on('error', function(err) { + gotErr = err; + }); + + var err = new Error('This stream turned into bacon.'); + source.emit('error', err); + assert.strictEqual(gotErr, err); +})(); + +(function testErrorWithoutListenerThrows() { + var source = new Stream(); + var dest = new Stream(); + + source.pipe(dest); + + var err = new Error('This stream turned into bacon.'); + + var gotErr = null; + try { + source.emit('error', err); + } catch (e) { + gotErr = e; + } + + assert.strictEqual(gotErr, err); +})(); + +(function testErrorWithRemovedListenerThrows() { + var EE = require('events').EventEmitter; + var R = Stream.Readable; + var W = Stream.Writable; + + var r = new R; + var w = new W; + var removed = false; + var didTest = false; + + process.on('exit', function() { + assert(didTest); + console.log('ok'); + }); + + r._read = function() { + setTimeout(function() { + assert(removed); + assert.throws(function() { + w.emit('error', new Error('fail')); + }); + didTest = true; + }); + }; + + w.on('error', myOnError); + r.pipe(w); + w.removeListener('error', myOnError); + removed = true; + + function myOnError(er) { + throw new Error('this should not happen'); + } +})(); + +(function testErrorWithRemovedListenerThrows() { + var EE = require('events').EventEmitter; + var R = Stream.Readable; + var W = Stream.Writable; + + var r = new R; + var w = new W; + var removed = false; + var didTest = false; + var caught = false; + + process.on('exit', function() { + assert(didTest); + console.log('ok'); + }); + + r._read = function() { + setTimeout(function() { + assert(removed); + w.emit('error', new Error('fail')); + didTest = true; + }); + }; + + w.on('error', myOnError); + w._write = function() {}; + + r.pipe(w); + // Removing some OTHER random listener should not do anything + w.removeListener('error', function() {}); + removed = true; + + function myOnError(er) { + assert(!caught); + caught = true; + } +})(); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-pipe-event.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-pipe-event.js new file mode 100644 index 0000000..56f8d61 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-pipe-event.js @@ -0,0 +1,49 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var stream = require('../../'); +var assert = require('assert'); +var util = require('util'); + +function Writable() { + this.writable = true; + stream.Stream.call(this); +} +util.inherits(Writable, stream.Stream); + +function Readable() { + this.readable = true; + stream.Stream.call(this); +} +util.inherits(Readable, stream.Stream); + +var passed = false; + +var w = new Writable(); +w.on('pipe', function(src) { + passed = true; +}); + +var r = new Readable(); +r.pipe(w); + +assert.ok(passed); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-push-order.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-push-order.js new file mode 100644 index 0000000..a5c9bf9 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-push-order.js @@ -0,0 +1,52 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common.js'); +var Readable = require('../../').Readable; +var assert = require('assert'); + +var s = new Readable({ + highWaterMark: 20, + encoding: 'ascii' +}); + +var list = ['1', '2', '3', '4', '5', '6']; + +s._read = function (n) { + var one = list.shift(); + if (!one) { + s.push(null); + } else { + var two = list.shift(); + s.push(one); + s.push(two); + } +}; + +var v = s.read(0); + +// ACTUALLY [1, 3, 5, 6, 4, 2] + +process.on("exit", function () { + assert.deepEqual(s._readableState.buffer, + ['1', '2', '3', '4', '5', '6']); + console.log("ok"); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-push-strings.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-push-strings.js new file mode 100644 index 0000000..1701a9a --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-push-strings.js @@ -0,0 +1,66 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); + +var Readable = require('../../').Readable; +var util = require('util'); + +util.inherits(MyStream, Readable); +function MyStream(options) { + Readable.call(this, options); + this._chunks = 3; +} + +MyStream.prototype._read = function(n) { + switch (this._chunks--) { + case 0: + return this.push(null); + case 1: + return setTimeout(function() { + this.push('last chunk'); + }.bind(this), 100); + case 2: + return this.push('second to last chunk'); + case 3: + return process.nextTick(function() { + this.push('first chunk'); + }.bind(this)); + default: + throw new Error('?'); + } +}; + +var ms = new MyStream(); +var results = []; +ms.on('readable', function() { + var chunk; + while (null !== (chunk = ms.read())) + results.push(chunk + ''); +}); + +var expect = [ 'first chunksecond to last chunk', 'last chunk' ]; +process.on('exit', function() { + assert.equal(ms._chunks, -1); + assert.deepEqual(results, expect); + console.log('ok'); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-readable-event.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-readable-event.js new file mode 100644 index 0000000..a8e6f7b --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-readable-event.js @@ -0,0 +1,126 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); + +var Readable = require('../../').Readable; + +(function first() { + // First test, not reading when the readable is added. + // make sure that on('readable', ...) triggers a readable event. + var r = new Readable({ + highWaterMark: 3 + }); + + var _readCalled = false; + r._read = function(n) { + _readCalled = true; + }; + + // This triggers a 'readable' event, which is lost. + r.push(new Buffer('blerg')); + + var caughtReadable = false; + setTimeout(function() { + // we're testing what we think we are + assert(!r._readableState.reading); + r.on('readable', function() { + caughtReadable = true; + }); + }); + + process.on('exit', function() { + // we're testing what we think we are + assert(!_readCalled); + + assert(caughtReadable); + console.log('ok 1'); + }); +})(); + +(function second() { + // second test, make sure that readable is re-emitted if there's + // already a length, while it IS reading. + + var r = new Readable({ + highWaterMark: 3 + }); + + var _readCalled = false; + r._read = function(n) { + _readCalled = true; + }; + + // This triggers a 'readable' event, which is lost. + r.push(new Buffer('bl')); + + var caughtReadable = false; + setTimeout(function() { + // assert we're testing what we think we are + assert(r._readableState.reading); + r.on('readable', function() { + caughtReadable = true; + }); + }); + + process.on('exit', function() { + // we're testing what we think we are + assert(_readCalled); + + assert(caughtReadable); + console.log('ok 2'); + }); +})(); + +(function third() { + // Third test, not reading when the stream has not passed + // the highWaterMark but *has* reached EOF. + var r = new Readable({ + highWaterMark: 30 + }); + + var _readCalled = false; + r._read = function(n) { + _readCalled = true; + }; + + // This triggers a 'readable' event, which is lost. + r.push(new Buffer('blerg')); + r.push(null); + + var caughtReadable = false; + setTimeout(function() { + // assert we're testing what we think we are + assert(!r._readableState.reading); + r.on('readable', function() { + caughtReadable = true; + }); + }); + + process.on('exit', function() { + // we're testing what we think we are + assert(!_readCalled); + + assert(caughtReadable); + console.log('ok 3'); + }); +})(); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-readable-flow-recursion.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-readable-flow-recursion.js new file mode 100644 index 0000000..11689ba --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-readable-flow-recursion.js @@ -0,0 +1,76 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); + +// this test verifies that passing a huge number to read(size) +// will push up the highWaterMark, and cause the stream to read +// more data continuously, but without triggering a nextTick +// warning or RangeError. + +var Readable = require('../../').Readable; + +// throw an error if we trigger a nextTick warning. +process.throwDeprecation = true; + +var stream = new Readable({ highWaterMark: 2 }); +var reads = 0; +var total = 5000; +stream._read = function(size) { + reads++; + size = Math.min(size, total); + total -= size; + if (size === 0) + stream.push(null); + else + stream.push(new Buffer(size)); +}; + +var depth = 0; + +function flow(stream, size, callback) { + depth += 1; + var chunk = stream.read(size); + + if (!chunk) + stream.once('readable', flow.bind(null, stream, size, callback)); + else + callback(chunk); + + depth -= 1; + console.log('flow(' + depth + '): exit'); +} + +flow(stream, 5000, function() { + console.log('complete (' + depth + ')'); +}); + +process.on('exit', function(code) { + assert.equal(reads, 2); + // we pushed up the high water mark + assert.equal(stream._readableState.highWaterMark, 8192); + // length is 0 right now, because we pulled it all out. + assert.equal(stream._readableState.length, 0); + assert(!code); + assert.equal(depth, 0); + console.log('ok'); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-unshift-empty-chunk.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-unshift-empty-chunk.js new file mode 100644 index 0000000..7827538 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-unshift-empty-chunk.js @@ -0,0 +1,81 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); + +// This test verifies that stream.unshift(Buffer(0)) or +// stream.unshift('') does not set state.reading=false. +var Readable = require('../../').Readable; + +var r = new Readable(); +var nChunks = 10; +var chunk = new Buffer(10); +chunk.fill('x'); + +r._read = function(n) { + setTimeout(function() { + r.push(--nChunks === 0 ? null : chunk); + }); +}; + +var readAll = false; +var seen = []; +r.on('readable', function() { + var chunk; + while (chunk = r.read()) { + seen.push(chunk.toString()); + // simulate only reading a certain amount of the data, + // and then putting the rest of the chunk back into the + // stream, like a parser might do. We just fill it with + // 'y' so that it's easy to see which bits were touched, + // and which were not. + var putBack = new Buffer(readAll ? 0 : 5); + putBack.fill('y'); + readAll = !readAll; + r.unshift(putBack); + } +}); + +var expect = + [ 'xxxxxxxxxx', + 'yyyyy', + 'xxxxxxxxxx', + 'yyyyy', + 'xxxxxxxxxx', + 'yyyyy', + 'xxxxxxxxxx', + 'yyyyy', + 'xxxxxxxxxx', + 'yyyyy', + 'xxxxxxxxxx', + 'yyyyy', + 'xxxxxxxxxx', + 'yyyyy', + 'xxxxxxxxxx', + 'yyyyy', + 'xxxxxxxxxx', + 'yyyyy' ]; + +r.on('end', function() { + assert.deepEqual(seen, expect); + console.log('ok'); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-unshift-read-race.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-unshift-read-race.js new file mode 100644 index 0000000..17c18aa --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-unshift-read-race.js @@ -0,0 +1,140 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); + +// This test verifies that: +// 1. unshift() does not cause colliding _read() calls. +// 2. unshift() after the 'end' event is an error, but after the EOF +// signalling null, it is ok, and just creates a new readable chunk. +// 3. push() after the EOF signaling null is an error. +// 4. _read() is not called after pushing the EOF null chunk. + +var stream = require('../../'); +var hwm = 10; +var r = stream.Readable({ highWaterMark: hwm }); +var chunks = 10; +var t = (chunks * 5); + +var data = new Buffer(chunks * hwm + Math.ceil(hwm / 2)); +for (var i = 0; i < data.length; i++) { + var c = 'asdf'.charCodeAt(i % 4); + data[i] = c; +} + +var pos = 0; +var pushedNull = false; +r._read = function(n) { + assert(!pushedNull, '_read after null push'); + + // every third chunk is fast + push(!(chunks % 3)); + + function push(fast) { + assert(!pushedNull, 'push() after null push'); + var c; + if (pos >= data.length) + c = null; + else { + if (n + pos > data.length) + n = data.length - pos; + c = data.slice(pos, pos + n); + } + pushedNull = c === null; + if (fast) { + pos += n; + r.push(c); + if (c === null) pushError(); + } else { + setTimeout(function() { + pos += n; + r.push(c); + if (c === null) pushError(); + }); + } + } +}; + +function pushError() { + assert.throws(function() { + r.push(new Buffer(1)); + }); +} + + +var w = stream.Writable(); +var written = []; +w._write = function(chunk, encoding, cb) { + written.push(chunk.toString()); + cb(); +}; + +var ended = false; +r.on('end', function() { + assert(!ended, 'end emitted more than once'); + assert.throws(function() { + r.unshift(new Buffer(1)); + }); + ended = true; + w.end(); +}); + +r.on('readable', function() { + var chunk; + while (null !== (chunk = r.read(10))) { + w.write(chunk); + if (chunk.length > 4) + r.unshift(new Buffer('1234')); + } +}); + +var finished = false; +w.on('finish', function() { + finished = true; + // each chunk should start with 1234, and then be asfdasdfasdf... + // The first got pulled out before the first unshift('1234'), so it's + // lacking that piece. + assert.equal(written[0], 'asdfasdfas'); + var asdf = 'd'; + console.error('0: %s', written[0]); + for (var i = 1; i < written.length; i++) { + console.error('%s: %s', i.toString(32), written[i]); + assert.equal(written[i].slice(0, 4), '1234'); + for (var j = 4; j < written[i].length; j++) { + var c = written[i].charAt(j); + assert.equal(c, asdf); + switch (asdf) { + case 'a': asdf = 's'; break; + case 's': asdf = 'd'; break; + case 'd': asdf = 'f'; break; + case 'f': asdf = 'a'; break; + } + } + } +}); + +process.on('exit', function() { + assert.equal(written.length, 18); + assert(ended, 'stream ended'); + assert(finished, 'stream finished'); + console.log('ok'); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-writev.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-writev.js new file mode 100644 index 0000000..b5321f3 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream-writev.js @@ -0,0 +1,121 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); + +var stream = require('../../'); + +var queue = []; +for (var decode = 0; decode < 2; decode++) { + for (var uncork = 0; uncork < 2; uncork++) { + for (var multi = 0; multi < 2; multi++) { + queue.push([!!decode, !!uncork, !!multi]); + } + } +} + +run(); + +function run() { + var t = queue.pop(); + if (t) + test(t[0], t[1], t[2], run); + else + console.log('ok'); +} + +function test(decode, uncork, multi, next) { + console.log('# decode=%j uncork=%j multi=%j', decode, uncork, multi); + var counter = 0; + var expectCount = 0; + function cnt(msg) { + expectCount++; + var expect = expectCount; + var called = false; + return function(er) { + if (er) + throw er; + called = true; + counter++; + assert.equal(counter, expect); + }; + } + + var w = new stream.Writable({ decodeStrings: decode }); + w._write = function(chunk, e, cb) { + assert(false, 'Should not call _write'); + }; + + var expectChunks = decode ? + [{ encoding: 'buffer', + chunk: [104, 101, 108, 108, 111, 44, 32] }, + { encoding: 'buffer', chunk: [119, 111, 114, 108, 100] }, + { encoding: 'buffer', chunk: [33] }, + { encoding: 'buffer', + chunk: [10, 97, 110, 100, 32, 116, 104, 101, 110, 46, 46, 46] }, + { encoding: 'buffer', + chunk: [250, 206, 190, 167, 222, 173, 190, 239, 222, 202, 251, 173] }] : + [{ encoding: 'ascii', chunk: 'hello, ' }, + { encoding: 'utf8', chunk: 'world' }, + { encoding: 'buffer', chunk: [33] }, + { encoding: 'binary', chunk: '\nand then...' }, + { encoding: 'hex', chunk: 'facebea7deadbeefdecafbad' }]; + + var actualChunks; + w._writev = function(chunks, cb) { + actualChunks = chunks.map(function(chunk) { + return { + encoding: chunk.encoding, + chunk: Buffer.isBuffer(chunk.chunk) ? + Array.prototype.slice.call(chunk.chunk) : chunk.chunk + }; + }); + cb(); + }; + + w.cork(); + w.write('hello, ', 'ascii', cnt('hello')); + w.write('world', 'utf8', cnt('world')); + + if (multi) + w.cork(); + + w.write(new Buffer('!'), 'buffer', cnt('!')); + w.write('\nand then...', 'binary', cnt('and then')); + + if (multi) + w.uncork(); + + w.write('facebea7deadbeefdecafbad', 'hex', cnt('hex')); + + if (uncork) + w.uncork(); + + w.end(cnt('end')); + + w.on('finish', function() { + // make sure finish comes after all the write cb + cnt('finish')(); + assert.deepEqual(expectChunks, actualChunks); + next(); + }); +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-basic.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-basic.js new file mode 100644 index 0000000..248c1be --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-basic.js @@ -0,0 +1,475 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + +var common = require('../common.js'); +var R = require('../../lib/_stream_readable'); +var assert = require('assert'); + +var util = require('util'); +var EE = require('events').EventEmitter; + +function TestReader(n) { + R.apply(this); + this._buffer = new Buffer(n || 100); + this._buffer.fill('x'); + this._pos = 0; + this._bufs = 10; +} + +util.inherits(TestReader, R); + +TestReader.prototype._read = function(n) { + var max = this._buffer.length - this._pos; + n = Math.max(n, 0); + var toRead = Math.min(n, max); + if (toRead === 0) { + // simulate the read buffer filling up with some more bytes some time + // in the future. + setTimeout(function() { + this._pos = 0; + this._bufs -= 1; + if (this._bufs <= 0) { + // read them all! + if (!this.ended) + this.push(null); + } else { + // now we have more. + // kinda cheating by calling _read, but whatever, + // it's just fake anyway. + this._read(n); + } + }.bind(this), 10); + return; + } + + var ret = this._buffer.slice(this._pos, this._pos + toRead); + this._pos += toRead; + this.push(ret); +}; + +///// + +function TestWriter() { + EE.apply(this); + this.received = []; + this.flush = false; +} + +util.inherits(TestWriter, EE); + +TestWriter.prototype.write = function(c) { + this.received.push(c.toString()); + this.emit('write', c); + return true; +}; + +TestWriter.prototype.end = function(c) { + if (c) this.write(c); + this.emit('end', this.received); +}; + +//////// + +// tiny node-tap lookalike. +var tests = []; +var count = 0; + +function test(name, fn) { + count++; + tests.push([name, fn]); +} + +function run() { + var next = tests.shift(); + if (!next) + return console.error('ok'); + + var name = next[0]; + var fn = next[1]; + console.log('# %s', name); + fn({ + same: assert.deepEqual, + ok: assert, + equal: assert.equal, + end: function () { + count--; + run(); + } + }); +} + +// ensure all tests have run +process.on("exit", function () { + assert.equal(count, 0); +}); + +process.nextTick(run); + + +test('a most basic test', function(t) { + var r = new TestReader(20); + + var reads = []; + var expect = [ 'x', + 'xx', + 'xxx', + 'xxxx', + 'xxxxx', + 'xxxxxxxxx', + 'xxxxxxxxxx', + 'xxxxxxxxxxxx', + 'xxxxxxxxxxxxx', + 'xxxxxxxxxxxxxxx', + 'xxxxxxxxxxxxxxxxx', + 'xxxxxxxxxxxxxxxxxxx', + 'xxxxxxxxxxxxxxxxxxxxx', + 'xxxxxxxxxxxxxxxxxxxxxxx', + 'xxxxxxxxxxxxxxxxxxxxxxxxx', + 'xxxxxxxxxxxxxxxxxxxxx' ]; + + r.on('end', function() { + t.same(reads, expect); + t.end(); + }); + + var readSize = 1; + function flow() { + var res; + while (null !== (res = r.read(readSize++))) { + reads.push(res.toString()); + } + r.once('readable', flow); + } + + flow(); +}); + +test('pipe', function(t) { + var r = new TestReader(5); + + var expect = [ 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx' ] + + var w = new TestWriter; + var flush = true; + + w.on('end', function(received) { + t.same(received, expect); + t.end(); + }); + + r.pipe(w); +}); + + + +[1,2,3,4,5,6,7,8,9].forEach(function(SPLIT) { + test('unpipe', function(t) { + var r = new TestReader(5); + + // unpipe after 3 writes, then write to another stream instead. + var expect = [ 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx' ]; + expect = [ expect.slice(0, SPLIT), expect.slice(SPLIT) ]; + + var w = [ new TestWriter(), new TestWriter() ]; + + var writes = SPLIT; + w[0].on('write', function() { + if (--writes === 0) { + r.unpipe(); + t.equal(r._readableState.pipes, null); + w[0].end(); + r.pipe(w[1]); + t.equal(r._readableState.pipes, w[1]); + } + }); + + var ended = 0; + + var ended0 = false; + var ended1 = false; + w[0].on('end', function(results) { + t.equal(ended0, false); + ended0 = true; + ended++; + t.same(results, expect[0]); + }); + + w[1].on('end', function(results) { + t.equal(ended1, false); + ended1 = true; + ended++; + t.equal(ended, 2); + t.same(results, expect[1]); + t.end(); + }); + + r.pipe(w[0]); + }); +}); + + +// both writers should get the same exact data. +test('multipipe', function(t) { + var r = new TestReader(5); + var w = [ new TestWriter, new TestWriter ]; + + var expect = [ 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx' ]; + + var c = 2; + w[0].on('end', function(received) { + t.same(received, expect, 'first'); + if (--c === 0) t.end(); + }); + w[1].on('end', function(received) { + t.same(received, expect, 'second'); + if (--c === 0) t.end(); + }); + + r.pipe(w[0]); + r.pipe(w[1]); +}); + + +[1,2,3,4,5,6,7,8,9].forEach(function(SPLIT) { + test('multi-unpipe', function(t) { + var r = new TestReader(5); + + // unpipe after 3 writes, then write to another stream instead. + var expect = [ 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx', + 'xxxxx' ]; + expect = [ expect.slice(0, SPLIT), expect.slice(SPLIT) ]; + + var w = [ new TestWriter(), new TestWriter(), new TestWriter() ]; + + var writes = SPLIT; + w[0].on('write', function() { + if (--writes === 0) { + r.unpipe(); + w[0].end(); + r.pipe(w[1]); + } + }); + + var ended = 0; + + w[0].on('end', function(results) { + ended++; + t.same(results, expect[0]); + }); + + w[1].on('end', function(results) { + ended++; + t.equal(ended, 2); + t.same(results, expect[1]); + t.end(); + }); + + r.pipe(w[0]); + r.pipe(w[2]); + }); +}); + +test('back pressure respected', function (t) { + function noop() {} + + var r = new R({ objectMode: true }); + r._read = noop; + var counter = 0; + r.push(["one"]); + r.push(["two"]); + r.push(["three"]); + r.push(["four"]); + r.push(null); + + var w1 = new R(); + w1.write = function (chunk) { + console.error('w1.emit("close")'); + assert.equal(chunk[0], "one"); + w1.emit("close"); + process.nextTick(function () { + r.pipe(w2); + r.pipe(w3); + }) + }; + w1.end = noop; + + r.pipe(w1); + + var expected = ["two", "two", "three", "three", "four", "four"]; + + var w2 = new R(); + w2.write = function (chunk) { + console.error('w2 write', chunk, counter); + assert.equal(chunk[0], expected.shift()); + assert.equal(counter, 0); + + counter++; + + if (chunk[0] === "four") { + return true; + } + + setTimeout(function () { + counter--; + console.error("w2 drain"); + w2.emit("drain"); + }, 10); + + return false; + } + w2.end = noop; + + var w3 = new R(); + w3.write = function (chunk) { + console.error('w3 write', chunk, counter); + assert.equal(chunk[0], expected.shift()); + assert.equal(counter, 1); + + counter++; + + if (chunk[0] === "four") { + return true; + } + + setTimeout(function () { + counter--; + console.error("w3 drain"); + w3.emit("drain"); + }, 50); + + return false; + }; + w3.end = function () { + assert.equal(counter, 2); + assert.equal(expected.length, 0); + t.end(); + }; +}); + +test('read(0) for ended streams', function (t) { + var r = new R(); + var written = false; + var ended = false; + r._read = function (n) {}; + + r.push(new Buffer("foo")); + r.push(null); + + var v = r.read(0); + + assert.equal(v, null); + + var w = new R(); + + w.write = function (buffer) { + written = true; + assert.equal(ended, false); + assert.equal(buffer.toString(), "foo") + }; + + w.end = function () { + ended = true; + assert.equal(written, true); + t.end(); + }; + + r.pipe(w); +}) + +test('sync _read ending', function (t) { + var r = new R(); + var called = false; + r._read = function (n) { + r.push(null); + }; + + r.once('end', function () { + called = true; + }) + + r.read(); + + process.nextTick(function () { + assert.equal(called, true); + t.end(); + }) +}); + +test('adding readable triggers data flow', function(t) { + var r = new R({ highWaterMark: 5 }); + var onReadable = false; + var readCalled = 0; + + r._read = function(n) { + if (readCalled++ === 2) + r.push(null); + else + r.push(new Buffer('asdf')); + }; + + var called = false; + r.on('readable', function() { + onReadable = true; + r.read(); + }); + + r.on('end', function() { + t.equal(readCalled, 3); + t.ok(onReadable); + t.end(); + }); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-compatibility.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-compatibility.js new file mode 100644 index 0000000..f0fa84b --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-compatibility.js @@ -0,0 +1,53 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + +var common = require('../common.js'); +var R = require('../../lib/_stream_readable'); +var assert = require('assert'); + +var util = require('util'); +var EE = require('events').EventEmitter; + +var ondataCalled = 0; + +function TestReader() { + R.apply(this); + this._buffer = new Buffer(100); + this._buffer.fill('x'); + + this.on('data', function() { + ondataCalled++; + }); +} + +util.inherits(TestReader, R); + +TestReader.prototype._read = function(n) { + this.push(this._buffer); + this._buffer = new Buffer(0); +}; + +var reader = new TestReader(); +setImmediate(function() { + assert.equal(ondataCalled, 1); + console.log('ok'); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-finish-pipe.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-finish-pipe.js new file mode 100644 index 0000000..006a19b --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-finish-pipe.js @@ -0,0 +1,41 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common.js'); +var stream = require('../../'); +var Buffer = require('buffer').Buffer; + +var r = new stream.Readable(); +r._read = function(size) { + r.push(new Buffer(size)); +}; + +var w = new stream.Writable(); +w._write = function(data, encoding, cb) { + cb(null); +}; + +r.pipe(w); + +// This might sound unrealistic, but it happens in net.js. When +// `socket.allowHalfOpen === false`, EOF will cause `.destroySoon()` call which +// ends the writable side of net.Socket. +w.end(); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-large-read-stall.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-large-read-stall.js new file mode 100644 index 0000000..667985b --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-large-read-stall.js @@ -0,0 +1,82 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common.js'); +var assert = require('assert'); + +// If everything aligns so that you do a read(n) of exactly the +// remaining buffer, then make sure that 'end' still emits. + +var READSIZE = 100; +var PUSHSIZE = 20; +var PUSHCOUNT = 1000; +var HWM = 50; + +var Readable = require('../../').Readable; +var r = new Readable({ + highWaterMark: HWM +}); +var rs = r._readableState; + +r._read = push; + +r.on('readable', function() { + //console.error('>> readable'); + do { + //console.error(' > read(%d)', READSIZE); + var ret = r.read(READSIZE); + //console.error(' < %j (%d remain)', ret && ret.length, rs.length); + } while (ret && ret.length === READSIZE); + + //console.error('<< after read()', + // ret && ret.length, + // rs.needReadable, + // rs.length); +}); + +var endEmitted = false; +r.on('end', function() { + endEmitted = true; + //console.error('end'); +}); + +var pushes = 0; +function push() { + if (pushes > PUSHCOUNT) + return; + + if (pushes++ === PUSHCOUNT) { + //console.error(' push(EOF)'); + return r.push(null); + } + + //console.error(' push #%d', pushes); + if (r.push(new Buffer(PUSHSIZE))) + setTimeout(push); +} + +// start the flow +var ret = r.read(0); + +process.on('exit', function() { + assert.equal(pushes, PUSHCOUNT + 1); + assert(endEmitted); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-objects.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-objects.js new file mode 100644 index 0000000..ff47d89 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-objects.js @@ -0,0 +1,351 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + +var common = require('../common.js'); +var Readable = require('../../lib/_stream_readable'); +var Writable = require('../../lib/_stream_writable'); +var assert = require('assert'); + +// tiny node-tap lookalike. +var tests = []; +var count = 0; + +function test(name, fn) { + count++; + tests.push([name, fn]); +} + +function run() { + var next = tests.shift(); + if (!next) + return console.error('ok'); + + var name = next[0]; + var fn = next[1]; + console.log('# %s', name); + fn({ + same: assert.deepEqual, + equal: assert.equal, + end: function() { + count--; + run(); + } + }); +} + +// ensure all tests have run +process.on('exit', function() { + assert.equal(count, 0); +}); + +process.nextTick(run); + +function toArray(callback) { + var stream = new Writable({ objectMode: true }); + var list = []; + stream.write = function(chunk) { + list.push(chunk); + }; + + stream.end = function() { + callback(list); + }; + + return stream; +} + +function fromArray(list) { + var r = new Readable({ objectMode: true }); + r._read = noop; + list.forEach(function(chunk) { + r.push(chunk); + }); + r.push(null); + + return r; +} + +function noop() {} + +test('can read objects from stream', function(t) { + var r = fromArray([{ one: '1'}, { two: '2' }]); + + var v1 = r.read(); + var v2 = r.read(); + var v3 = r.read(); + + assert.deepEqual(v1, { one: '1' }); + assert.deepEqual(v2, { two: '2' }); + assert.deepEqual(v3, null); + + t.end(); +}); + +test('can pipe objects into stream', function(t) { + var r = fromArray([{ one: '1'}, { two: '2' }]); + + r.pipe(toArray(function(list) { + assert.deepEqual(list, [ + { one: '1' }, + { two: '2' } + ]); + + t.end(); + })); +}); + +test('read(n) is ignored', function(t) { + var r = fromArray([{ one: '1'}, { two: '2' }]); + + var value = r.read(2); + + assert.deepEqual(value, { one: '1' }); + + t.end(); +}); + +test('can read objects from _read (sync)', function(t) { + var r = new Readable({ objectMode: true }); + var list = [{ one: '1'}, { two: '2' }]; + r._read = function(n) { + var item = list.shift(); + r.push(item || null); + }; + + r.pipe(toArray(function(list) { + assert.deepEqual(list, [ + { one: '1' }, + { two: '2' } + ]); + + t.end(); + })); +}); + +test('can read objects from _read (async)', function(t) { + var r = new Readable({ objectMode: true }); + var list = [{ one: '1'}, { two: '2' }]; + r._read = function(n) { + var item = list.shift(); + process.nextTick(function() { + r.push(item || null); + }); + }; + + r.pipe(toArray(function(list) { + assert.deepEqual(list, [ + { one: '1' }, + { two: '2' } + ]); + + t.end(); + })); +}); + +test('can read strings as objects', function(t) { + var r = new Readable({ + objectMode: true + }); + r._read = noop; + var list = ['one', 'two', 'three']; + list.forEach(function(str) { + r.push(str); + }); + r.push(null); + + r.pipe(toArray(function(array) { + assert.deepEqual(array, list); + + t.end(); + })); +}); + +test('read(0) for object streams', function(t) { + var r = new Readable({ + objectMode: true + }); + r._read = noop; + + r.push('foobar'); + r.push(null); + + var v = r.read(0); + + r.pipe(toArray(function(array) { + assert.deepEqual(array, ['foobar']); + + t.end(); + })); +}); + +test('falsey values', function(t) { + var r = new Readable({ + objectMode: true + }); + r._read = noop; + + r.push(false); + r.push(0); + r.push(''); + r.push(null); + + r.pipe(toArray(function(array) { + assert.deepEqual(array, [false, 0, '']); + + t.end(); + })); +}); + +test('high watermark _read', function(t) { + var r = new Readable({ + highWaterMark: 6, + objectMode: true + }); + var calls = 0; + var list = ['1', '2', '3', '4', '5', '6', '7', '8']; + + r._read = function(n) { + calls++; + }; + + list.forEach(function(c) { + r.push(c); + }); + + var v = r.read(); + + assert.equal(calls, 0); + assert.equal(v, '1'); + + var v2 = r.read(); + assert.equal(v2, '2'); + + var v3 = r.read(); + assert.equal(v3, '3'); + + assert.equal(calls, 1); + + t.end(); +}); + +test('high watermark push', function(t) { + var r = new Readable({ + highWaterMark: 6, + objectMode: true + }); + r._read = function(n) {}; + for (var i = 0; i < 6; i++) { + var bool = r.push(i); + assert.equal(bool, i === 5 ? false : true); + } + + t.end(); +}); + +test('can write objects to stream', function(t) { + var w = new Writable({ objectMode: true }); + + w._write = function(chunk, encoding, cb) { + assert.deepEqual(chunk, { foo: 'bar' }); + cb(); + }; + + w.on('finish', function() { + t.end(); + }); + + w.write({ foo: 'bar' }); + w.end(); +}); + +test('can write multiple objects to stream', function(t) { + var w = new Writable({ objectMode: true }); + var list = []; + + w._write = function(chunk, encoding, cb) { + list.push(chunk); + cb(); + }; + + w.on('finish', function() { + assert.deepEqual(list, [0, 1, 2, 3, 4]); + + t.end(); + }); + + w.write(0); + w.write(1); + w.write(2); + w.write(3); + w.write(4); + w.end(); +}); + +test('can write strings as objects', function(t) { + var w = new Writable({ + objectMode: true + }); + var list = []; + + w._write = function(chunk, encoding, cb) { + list.push(chunk); + process.nextTick(cb); + }; + + w.on('finish', function() { + assert.deepEqual(list, ['0', '1', '2', '3', '4']); + + t.end(); + }); + + w.write('0'); + w.write('1'); + w.write('2'); + w.write('3'); + w.write('4'); + w.end(); +}); + +test('buffers finish until cb is called', function(t) { + var w = new Writable({ + objectMode: true + }); + var called = false; + + w._write = function(chunk, encoding, cb) { + assert.equal(chunk, 'foo'); + + process.nextTick(function() { + called = true; + cb(); + }); + }; + + w.on('finish', function() { + assert.equal(called, true); + + t.end(); + }); + + w.write('foo'); + w.end(); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-pipe-error-handling.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-pipe-error-handling.js new file mode 100644 index 0000000..e3f3e4e --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-pipe-error-handling.js @@ -0,0 +1,105 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); +var stream = require('../../'); + +(function testErrorListenerCatches() { + var count = 1000; + + var source = new stream.Readable(); + source._read = function(n) { + n = Math.min(count, n); + count -= n; + source.push(new Buffer(n)); + }; + + var unpipedDest; + source.unpipe = function(dest) { + unpipedDest = dest; + stream.Readable.prototype.unpipe.call(this, dest); + }; + + var dest = new stream.Writable(); + dest._write = function(chunk, encoding, cb) { + cb(); + }; + + source.pipe(dest); + + var gotErr = null; + dest.on('error', function(err) { + gotErr = err; + }); + + var unpipedSource; + dest.on('unpipe', function(src) { + unpipedSource = src; + }); + + var err = new Error('This stream turned into bacon.'); + dest.emit('error', err); + assert.strictEqual(gotErr, err); + assert.strictEqual(unpipedSource, source); + assert.strictEqual(unpipedDest, dest); +})(); + +(function testErrorWithoutListenerThrows() { + var count = 1000; + + var source = new stream.Readable(); + source._read = function(n) { + n = Math.min(count, n); + count -= n; + source.push(new Buffer(n)); + }; + + var unpipedDest; + source.unpipe = function(dest) { + unpipedDest = dest; + stream.Readable.prototype.unpipe.call(this, dest); + }; + + var dest = new stream.Writable(); + dest._write = function(chunk, encoding, cb) { + cb(); + }; + + source.pipe(dest); + + var unpipedSource; + dest.on('unpipe', function(src) { + unpipedSource = src; + }); + + var err = new Error('This stream turned into bacon.'); + + var gotErr = null; + try { + dest.emit('error', err); + } catch (e) { + gotErr = e; + } + assert.strictEqual(gotErr, err); + assert.strictEqual(unpipedSource, source); + assert.strictEqual(unpipedDest, dest); +})(); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-pipe-error-once-listener.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-pipe-error-once-listener.js new file mode 100755 index 0000000..53b2616 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-pipe-error-once-listener.js @@ -0,0 +1,64 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + +var common = require('../common.js'); +var assert = require('assert'); + +var util = require('util'); +var stream = require('../../'); + + +var Read = function() { + stream.Readable.call(this); +}; +util.inherits(Read, stream.Readable); + +Read.prototype._read = function(size) { + this.push('x'); + this.push(null); +}; + + +var Write = function() { + stream.Writable.call(this); +}; +util.inherits(Write, stream.Writable); + +Write.prototype._write = function(buffer, encoding, cb) { + this.emit('error', new Error('boom')); + this.emit('alldone'); +}; + +var read = new Read(); +var write = new Write(); + +write.once('error', function(err) {}); +write.once('alldone', function(err) { + console.log('ok'); +}); + +process.on('exit', function(c) { + console.error('error thrown even with listener'); +}); + +read.pipe(write); + diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-push.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-push.js new file mode 100644 index 0000000..eb2b0e9 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-push.js @@ -0,0 +1,138 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common.js'); +var stream = require('../../'); +var Readable = stream.Readable; +var Writable = stream.Writable; +var assert = require('assert'); + +var util = require('util'); +var EE = require('events').EventEmitter; + + +// a mock thing a bit like the net.Socket/tcp_wrap.handle interaction + +var stream = new Readable({ + highWaterMark: 16, + encoding: 'utf8' +}); + +var source = new EE; + +stream._read = function() { + console.error('stream._read'); + readStart(); +}; + +var ended = false; +stream.on('end', function() { + ended = true; +}); + +source.on('data', function(chunk) { + var ret = stream.push(chunk); + console.error('data', stream._readableState.length); + if (!ret) + readStop(); +}); + +source.on('end', function() { + stream.push(null); +}); + +var reading = false; + +function readStart() { + console.error('readStart'); + reading = true; +} + +function readStop() { + console.error('readStop'); + reading = false; + process.nextTick(function() { + var r = stream.read(); + if (r !== null) + writer.write(r); + }); +} + +var writer = new Writable({ + decodeStrings: false +}); + +var written = []; + +var expectWritten = + [ 'asdfgasdfgasdfgasdfg', + 'asdfgasdfgasdfgasdfg', + 'asdfgasdfgasdfgasdfg', + 'asdfgasdfgasdfgasdfg', + 'asdfgasdfgasdfgasdfg', + 'asdfgasdfgasdfgasdfg' ]; + +writer._write = function(chunk, encoding, cb) { + console.error('WRITE %s', chunk); + written.push(chunk); + process.nextTick(cb); +}; + +writer.on('finish', finish); + + +// now emit some chunks. + +var chunk = "asdfg"; + +var set = 0; +readStart(); +data(); +function data() { + assert(reading); + source.emit('data', chunk); + assert(reading); + source.emit('data', chunk); + assert(reading); + source.emit('data', chunk); + assert(reading); + source.emit('data', chunk); + assert(!reading); + if (set++ < 5) + setTimeout(data, 10); + else + end(); +} + +function finish() { + console.error('finish'); + assert.deepEqual(written, expectWritten); + console.log('ok'); +} + +function end() { + source.emit('end'); + assert(!reading); + writer.end(stream.read()); + setTimeout(function() { + assert(ended); + }); +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-read-sync-stack.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-read-sync-stack.js new file mode 100644 index 0000000..9740a47 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-read-sync-stack.js @@ -0,0 +1,54 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); +var Readable = require('../../').Readable; +var r = new Readable(); +var N = 256 * 1024; + +// Go ahead and allow the pathological case for this test. +// Yes, it's an infinite loop, that's the point. +process.maxTickDepth = N + 2; + +var reads = 0; +r._read = function(n) { + var chunk = reads++ === N ? null : new Buffer(1); + r.push(chunk); +}; + +r.on('readable', function onReadable() { + if (!(r._readableState.length % 256)) + console.error('readable', r._readableState.length); + r.read(N * 2); +}); + +var ended = false; +r.on('end', function onEnd() { + ended = true; +}); + +r.read(0); + +process.on('exit', function() { + assert(ended); + console.log('ok'); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-empty-buffer-no-eof.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-empty-buffer-no-eof.js new file mode 100644 index 0000000..4b1659d --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-empty-buffer-no-eof.js @@ -0,0 +1,89 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); + +var Readable = require('../../').Readable; + +test1(); + +function test1() { + var r = new Readable(); + + // should not end when we get a Buffer(0) or '' as the _read result + // that just means that there is *temporarily* no data, but to go + // ahead and try again later. + // + // note that this is very unusual. it only works for crypto streams + // because the other side of the stream will call read(0) to cycle + // data through openssl. that's why we set the timeouts to call + // r.read(0) again later, otherwise there is no more work being done + // and the process just exits. + + var buf = new Buffer(5); + buf.fill('x'); + var reads = 5; + r._read = function(n) { + switch (reads--) { + case 0: + return r.push(null); // EOF + case 1: + return r.push(buf); + case 2: + setTimeout(r.read.bind(r, 0), 10); + return r.push(new Buffer(0)); // Not-EOF! + case 3: + setTimeout(r.read.bind(r, 0), 10); + return process.nextTick(function() { + return r.push(new Buffer(0)); + }); + case 4: + setTimeout(r.read.bind(r, 0), 10); + return setTimeout(function() { + return r.push(new Buffer(0)); + }); + case 5: + return setTimeout(function() { + return r.push(buf); + }); + default: + throw new Error('unreachable'); + } + }; + + var results = []; + function flow() { + var chunk; + while (null !== (chunk = r.read())) + results.push(chunk + ''); + } + r.on('readable', flow); + r.on('end', function() { + results.push('EOF'); + }); + flow(); + + process.on('exit', function() { + assert.deepEqual(results, [ 'xxxxx', 'xxxxx', 'EOF' ]); + console.log('ok'); + }); +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-from-list.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-from-list.js new file mode 100644 index 0000000..04a96f5 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-from-list.js @@ -0,0 +1,120 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var assert = require('assert'); +var common = require('../common.js'); +var fromList = require('../../lib/_stream_readable')._fromList; + +// tiny node-tap lookalike. +var tests = []; +var count = 0; + +function test(name, fn) { + count++; + tests.push([name, fn]); +} + +function run() { + var next = tests.shift(); + if (!next) + return console.error('ok'); + + var name = next[0]; + var fn = next[1]; + console.log('# %s', name); + fn({ + same: assert.deepEqual, + equal: assert.equal, + end: function () { + count--; + run(); + } + }); +} + +// ensure all tests have run +process.on("exit", function () { + assert.equal(count, 0); +}); + +process.nextTick(run); + + + +test('buffers', function(t) { + // have a length + var len = 16; + var list = [ new Buffer('foog'), + new Buffer('bark'), + new Buffer('bazy'), + new Buffer('kuel') ]; + + // read more than the first element. + var ret = fromList(6, { buffer: list, length: 16 }); + t.equal(ret.toString(), 'foogba'); + + // read exactly the first element. + ret = fromList(2, { buffer: list, length: 10 }); + t.equal(ret.toString(), 'rk'); + + // read less than the first element. + ret = fromList(2, { buffer: list, length: 8 }); + t.equal(ret.toString(), 'ba'); + + // read more than we have. + ret = fromList(100, { buffer: list, length: 6 }); + t.equal(ret.toString(), 'zykuel'); + + // all consumed. + t.same(list, []); + + t.end(); +}); + +test('strings', function(t) { + // have a length + var len = 16; + var list = [ 'foog', + 'bark', + 'bazy', + 'kuel' ]; + + // read more than the first element. + var ret = fromList(6, { buffer: list, length: 16, decoder: true }); + t.equal(ret, 'foogba'); + + // read exactly the first element. + ret = fromList(2, { buffer: list, length: 10, decoder: true }); + t.equal(ret, 'rk'); + + // read less than the first element. + ret = fromList(2, { buffer: list, length: 8, decoder: true }); + t.equal(ret, 'ba'); + + // read more than we have. + ret = fromList(100, { buffer: list, length: 6, decoder: true }); + t.equal(ret, 'zykuel'); + + // all consumed. + t.same(list, []); + + t.end(); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-legacy-drain.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-legacy-drain.js new file mode 100644 index 0000000..51fd3d5 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-legacy-drain.js @@ -0,0 +1,75 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); + +var Stream = require('../../'); +var Readable = Stream.Readable; + +var r = new Readable(); +var N = 256; +var reads = 0; +r._read = function(n) { + return r.push(++reads === N ? null : new Buffer(1)); +}; + +var rended = false; +r.on('end', function() { + rended = true; +}); + +var w = new Stream(); +w.writable = true; +var writes = 0; +var buffered = 0; +w.write = function(c) { + writes += c.length; + buffered += c.length; + process.nextTick(drain); + return false; +}; + +function drain() { + assert(buffered <= 2); + buffered = 0; + w.emit('drain'); +} + + +var wended = false; +w.end = function() { + wended = true; +}; + +// Just for kicks, let's mess with the drain count. +// This verifies that even if it gets negative in the +// pipe() cleanup function, we'll still function properly. +r.on('readable', function() { + w.emit('drain'); +}); + +r.pipe(w); +process.on('exit', function() { + assert(rended); + assert(wended); + console.error('ok'); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-non-empty-end.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-non-empty-end.js new file mode 100644 index 0000000..c971898 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-non-empty-end.js @@ -0,0 +1,78 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var assert = require('assert'); +var common = require('../common.js'); +var Readable = require('../../lib/_stream_readable'); + +var len = 0; +var chunks = new Array(10); +for (var i = 1; i <= 10; i++) { + chunks[i-1] = new Buffer(i); + len += i; +} + +var test = new Readable(); +var n = 0; +test._read = function(size) { + var chunk = chunks[n++]; + setTimeout(function() { + test.push(chunk); + }); +}; + +test.on('end', thrower); +function thrower() { + throw new Error('this should not happen!'); +} + +var bytesread = 0; +test.on('readable', function() { + var b = len - bytesread - 1; + var res = test.read(b); + if (res) { + bytesread += res.length; + console.error('br=%d len=%d', bytesread, len); + setTimeout(next); + } + test.read(0); +}); +test.read(0); + +function next() { + // now let's make 'end' happen + test.removeListener('end', thrower); + + var endEmitted = false; + process.on('exit', function() { + assert(endEmitted, 'end should be emitted by now'); + }); + test.on('end', function() { + endEmitted = true; + }); + + // one to get the last byte + var r = test.read(); + assert(r); + assert.equal(r.length, 1); + r = test.read(); + assert.equal(r, null); +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-wrap-empty.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-wrap-empty.js new file mode 100644 index 0000000..fd8a3dc --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-wrap-empty.js @@ -0,0 +1,43 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); + +var Readable = require('../../lib/_stream_readable'); +var EE = require('events').EventEmitter; + +var oldStream = new EE(); +oldStream.pause = function(){}; +oldStream.resume = function(){}; + +var newStream = new Readable().wrap(oldStream); + +var ended = false; +newStream + .on('readable', function(){}) + .on('end', function(){ ended = true; }); + +oldStream.emit('end'); + +process.on('exit', function(){ + assert.ok(ended); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-wrap.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-wrap.js new file mode 100644 index 0000000..6b177f7 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-readable-wrap.js @@ -0,0 +1,105 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); + +var Readable = require('../../lib/_stream_readable'); +var Writable = require('../../lib/_stream_writable'); +var EE = require('events').EventEmitter; + +var testRuns = 0, completedRuns = 0; +function runTest(highWaterMark, objectMode, produce) { + testRuns++; + + var old = new EE; + var r = new Readable({ highWaterMark: highWaterMark, objectMode: objectMode }); + assert.equal(r, r.wrap(old)); + + var ended = false; + r.on('end', function() { + ended = true; + }); + + old.pause = function() { + console.error('old.pause()'); + old.emit('pause'); + flowing = false; + }; + + old.resume = function() { + console.error('old.resume()'); + old.emit('resume'); + flow(); + }; + + var flowing; + var chunks = 10; + var oldEnded = false; + var expected = []; + function flow() { + flowing = true; + while (flowing && chunks-- > 0) { + var item = produce(); + expected.push(item); + console.log('old.emit', chunks, flowing); + old.emit('data', item); + console.log('after emit', chunks, flowing); + } + if (chunks <= 0) { + oldEnded = true; + console.log('old end', chunks, flowing); + old.emit('end'); + } + } + + var w = new Writable({ highWaterMark: highWaterMark * 2, objectMode: objectMode }); + var written = []; + w._write = function(chunk, encoding, cb) { + console.log('_write', chunk); + written.push(chunk); + setTimeout(cb); + }; + + w.on('finish', function() { + completedRuns++; + performAsserts(); + }); + + r.pipe(w); + + flow(); + + function performAsserts() { + assert(ended); + assert(oldEnded); + assert.deepEqual(written, expected); + } +} + +runTest(100, false, function(){ return new Buffer(100); }); +runTest(10, false, function(){ return new Buffer('xxxxxxxxxx'); }); +runTest(1, true, function(){ return { foo: 'bar' }; }); + +process.on('exit', function() { + assert.equal(testRuns, completedRuns); + console.log('ok'); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-set-encoding.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-set-encoding.js new file mode 100644 index 0000000..685531b --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-set-encoding.js @@ -0,0 +1,361 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + +var common = require('../common.js'); +var assert = require('assert'); +var R = require('../../lib/_stream_readable'); +var util = require('util'); + +// tiny node-tap lookalike. +var tests = []; +var count = 0; + +function test(name, fn) { + count++; + tests.push([name, fn]); +} + +function run() { + var next = tests.shift(); + if (!next) + return console.error('ok'); + + var name = next[0]; + var fn = next[1]; + console.log('# %s', name); + fn({ + same: assert.deepEqual, + equal: assert.equal, + end: function () { + count--; + run(); + } + }); +} + +// ensure all tests have run +process.on("exit", function () { + assert.equal(count, 0); +}); + +process.nextTick(run); + +///// + +util.inherits(TestReader, R); + +function TestReader(n, opts) { + R.call(this, opts); + + this.pos = 0; + this.len = n || 100; +} + +TestReader.prototype._read = function(n) { + setTimeout(function() { + + if (this.pos >= this.len) { + // double push(null) to test eos handling + this.push(null); + return this.push(null); + } + + n = Math.min(n, this.len - this.pos); + if (n <= 0) { + // double push(null) to test eos handling + this.push(null); + return this.push(null); + } + + this.pos += n; + var ret = new Buffer(n); + ret.fill('a'); + + console.log("this.push(ret)", ret) + + return this.push(ret); + }.bind(this), 1); +}; + +test('setEncoding utf8', function(t) { + var tr = new TestReader(100); + tr.setEncoding('utf8'); + var out = []; + var expect = + [ 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa' ]; + + tr.on('readable', function flow() { + var chunk; + while (null !== (chunk = tr.read(10))) + out.push(chunk); + }); + + tr.on('end', function() { + t.same(out, expect); + t.end(); + }); +}); + + +test('setEncoding hex', function(t) { + var tr = new TestReader(100); + tr.setEncoding('hex'); + var out = []; + var expect = + [ '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161' ]; + + tr.on('readable', function flow() { + var chunk; + while (null !== (chunk = tr.read(10))) + out.push(chunk); + }); + + tr.on('end', function() { + t.same(out, expect); + t.end(); + }); +}); + +test('setEncoding hex with read(13)', function(t) { + var tr = new TestReader(100); + tr.setEncoding('hex'); + var out = []; + var expect = + [ "6161616161616", + "1616161616161", + "6161616161616", + "1616161616161", + "6161616161616", + "1616161616161", + "6161616161616", + "1616161616161", + "6161616161616", + "1616161616161", + "6161616161616", + "1616161616161", + "6161616161616", + "1616161616161", + "6161616161616", + "16161" ]; + + tr.on('readable', function flow() { + console.log("readable once") + var chunk; + while (null !== (chunk = tr.read(13))) + out.push(chunk); + }); + + tr.on('end', function() { + console.log("END") + t.same(out, expect); + t.end(); + }); +}); + +test('setEncoding base64', function(t) { + var tr = new TestReader(100); + tr.setEncoding('base64'); + var out = []; + var expect = + [ 'YWFhYWFhYW', + 'FhYWFhYWFh', + 'YWFhYWFhYW', + 'FhYWFhYWFh', + 'YWFhYWFhYW', + 'FhYWFhYWFh', + 'YWFhYWFhYW', + 'FhYWFhYWFh', + 'YWFhYWFhYW', + 'FhYWFhYWFh', + 'YWFhYWFhYW', + 'FhYWFhYWFh', + 'YWFhYWFhYW', + 'FhYQ==' ]; + + tr.on('readable', function flow() { + var chunk; + while (null !== (chunk = tr.read(10))) + out.push(chunk); + }); + + tr.on('end', function() { + t.same(out, expect); + t.end(); + }); +}); + +test('encoding: utf8', function(t) { + var tr = new TestReader(100, { encoding: 'utf8' }); + var out = []; + var expect = + [ 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa', + 'aaaaaaaaaa' ]; + + tr.on('readable', function flow() { + var chunk; + while (null !== (chunk = tr.read(10))) + out.push(chunk); + }); + + tr.on('end', function() { + t.same(out, expect); + t.end(); + }); +}); + + +test('encoding: hex', function(t) { + var tr = new TestReader(100, { encoding: 'hex' }); + var out = []; + var expect = + [ '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161', + '6161616161' ]; + + tr.on('readable', function flow() { + var chunk; + while (null !== (chunk = tr.read(10))) + out.push(chunk); + }); + + tr.on('end', function() { + t.same(out, expect); + t.end(); + }); +}); + +test('encoding: hex with read(13)', function(t) { + var tr = new TestReader(100, { encoding: 'hex' }); + var out = []; + var expect = + [ "6161616161616", + "1616161616161", + "6161616161616", + "1616161616161", + "6161616161616", + "1616161616161", + "6161616161616", + "1616161616161", + "6161616161616", + "1616161616161", + "6161616161616", + "1616161616161", + "6161616161616", + "1616161616161", + "6161616161616", + "16161" ]; + + tr.on('readable', function flow() { + var chunk; + while (null !== (chunk = tr.read(13))) + out.push(chunk); + }); + + tr.on('end', function() { + t.same(out, expect); + t.end(); + }); +}); + +test('encoding: base64', function(t) { + var tr = new TestReader(100, { encoding: 'base64' }); + var out = []; + var expect = + [ 'YWFhYWFhYW', + 'FhYWFhYWFh', + 'YWFhYWFhYW', + 'FhYWFhYWFh', + 'YWFhYWFhYW', + 'FhYWFhYWFh', + 'YWFhYWFhYW', + 'FhYWFhYWFh', + 'YWFhYWFhYW', + 'FhYWFhYWFh', + 'YWFhYWFhYW', + 'FhYWFhYWFh', + 'YWFhYWFhYW', + 'FhYQ==' ]; + + tr.on('readable', function flow() { + var chunk; + while (null !== (chunk = tr.read(10))) + out.push(chunk); + }); + + tr.on('end', function() { + t.same(out, expect); + t.end(); + }); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-transform.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-transform.js new file mode 100644 index 0000000..a0cacc6 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-transform.js @@ -0,0 +1,522 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var assert = require('assert'); +var common = require('../common.js'); +var PassThrough = require('../../').PassThrough; +var Transform = require('../../').Transform; + +// tiny node-tap lookalike. +var tests = []; +var count = 0; + +function test(name, fn) { + count++; + tests.push([name, fn]); +} + +function run() { + var next = tests.shift(); + if (!next) + return console.error('ok'); + + var name = next[0]; + var fn = next[1]; + console.log('# %s', name); + fn({ + same: assert.deepEqual, + equal: assert.equal, + ok: assert, + end: function () { + count--; + run(); + } + }); +} + +// ensure all tests have run +process.on("exit", function () { + assert.equal(count, 0); +}); + +process.nextTick(run); + +///// + +test('writable side consumption', function(t) { + var tx = new Transform({ + highWaterMark: 10 + }); + + var transformed = 0; + tx._transform = function(chunk, encoding, cb) { + transformed += chunk.length; + tx.push(chunk); + cb(); + }; + + for (var i = 1; i <= 10; i++) { + tx.write(new Buffer(i)); + } + tx.end(); + + t.equal(tx._readableState.length, 10); + t.equal(transformed, 10); + t.equal(tx._transformState.writechunk.length, 5); + t.same(tx._writableState.buffer.map(function(c) { + return c.chunk.length; + }), [6, 7, 8, 9, 10]); + + t.end(); +}); + +test('passthrough', function(t) { + var pt = new PassThrough(); + + pt.write(new Buffer('foog')); + pt.write(new Buffer('bark')); + pt.write(new Buffer('bazy')); + pt.write(new Buffer('kuel')); + pt.end(); + + t.equal(pt.read(5).toString(), 'foogb'); + t.equal(pt.read(5).toString(), 'arkba'); + t.equal(pt.read(5).toString(), 'zykue'); + t.equal(pt.read(5).toString(), 'l'); + t.end(); +}); + +test('object passthrough', function (t) { + var pt = new PassThrough({ objectMode: true }); + + pt.write(1); + pt.write(true); + pt.write(false); + pt.write(0); + pt.write('foo'); + pt.write(''); + pt.write({ a: 'b'}); + pt.end(); + + t.equal(pt.read(), 1); + t.equal(pt.read(), true); + t.equal(pt.read(), false); + t.equal(pt.read(), 0); + t.equal(pt.read(), 'foo'); + t.equal(pt.read(), ''); + t.same(pt.read(), { a: 'b'}); + t.end(); +}); + +test('simple transform', function(t) { + var pt = new Transform; + pt._transform = function(c, e, cb) { + var ret = new Buffer(c.length); + ret.fill('x'); + pt.push(ret); + cb(); + }; + + pt.write(new Buffer('foog')); + pt.write(new Buffer('bark')); + pt.write(new Buffer('bazy')); + pt.write(new Buffer('kuel')); + pt.end(); + + t.equal(pt.read(5).toString(), 'xxxxx'); + t.equal(pt.read(5).toString(), 'xxxxx'); + t.equal(pt.read(5).toString(), 'xxxxx'); + t.equal(pt.read(5).toString(), 'x'); + t.end(); +}); + +test('simple object transform', function(t) { + var pt = new Transform({ objectMode: true }); + pt._transform = function(c, e, cb) { + pt.push(JSON.stringify(c)); + cb(); + }; + + pt.write(1); + pt.write(true); + pt.write(false); + pt.write(0); + pt.write('foo'); + pt.write(''); + pt.write({ a: 'b'}); + pt.end(); + + t.equal(pt.read(), '1'); + t.equal(pt.read(), 'true'); + t.equal(pt.read(), 'false'); + t.equal(pt.read(), '0'); + t.equal(pt.read(), '"foo"'); + t.equal(pt.read(), '""'); + t.equal(pt.read(), '{"a":"b"}'); + t.end(); +}); + +test('async passthrough', function(t) { + var pt = new Transform; + pt._transform = function(chunk, encoding, cb) { + setTimeout(function() { + pt.push(chunk); + cb(); + }, 10); + }; + + pt.write(new Buffer('foog')); + pt.write(new Buffer('bark')); + pt.write(new Buffer('bazy')); + pt.write(new Buffer('kuel')); + pt.end(); + + pt.on('finish', function() { + t.equal(pt.read(5).toString(), 'foogb'); + t.equal(pt.read(5).toString(), 'arkba'); + t.equal(pt.read(5).toString(), 'zykue'); + t.equal(pt.read(5).toString(), 'l'); + t.end(); + }); +}); + +test('assymetric transform (expand)', function(t) { + var pt = new Transform; + + // emit each chunk 2 times. + pt._transform = function(chunk, encoding, cb) { + setTimeout(function() { + pt.push(chunk); + setTimeout(function() { + pt.push(chunk); + cb(); + }, 10) + }, 10); + }; + + pt.write(new Buffer('foog')); + pt.write(new Buffer('bark')); + pt.write(new Buffer('bazy')); + pt.write(new Buffer('kuel')); + pt.end(); + + pt.on('finish', function() { + t.equal(pt.read(5).toString(), 'foogf'); + t.equal(pt.read(5).toString(), 'oogba'); + t.equal(pt.read(5).toString(), 'rkbar'); + t.equal(pt.read(5).toString(), 'kbazy'); + t.equal(pt.read(5).toString(), 'bazyk'); + t.equal(pt.read(5).toString(), 'uelku'); + t.equal(pt.read(5).toString(), 'el'); + t.end(); + }); +}); + +test('assymetric transform (compress)', function(t) { + var pt = new Transform; + + // each output is the first char of 3 consecutive chunks, + // or whatever's left. + pt.state = ''; + + pt._transform = function(chunk, encoding, cb) { + if (!chunk) + chunk = ''; + var s = chunk.toString(); + setTimeout(function() { + this.state += s.charAt(0); + if (this.state.length === 3) { + pt.push(new Buffer(this.state)); + this.state = ''; + } + cb(); + }.bind(this), 10); + }; + + pt._flush = function(cb) { + // just output whatever we have. + pt.push(new Buffer(this.state)); + this.state = ''; + cb(); + }; + + pt.write(new Buffer('aaaa')); + pt.write(new Buffer('bbbb')); + pt.write(new Buffer('cccc')); + pt.write(new Buffer('dddd')); + pt.write(new Buffer('eeee')); + pt.write(new Buffer('aaaa')); + pt.write(new Buffer('bbbb')); + pt.write(new Buffer('cccc')); + pt.write(new Buffer('dddd')); + pt.write(new Buffer('eeee')); + pt.write(new Buffer('aaaa')); + pt.write(new Buffer('bbbb')); + pt.write(new Buffer('cccc')); + pt.write(new Buffer('dddd')); + pt.end(); + + // 'abcdeabcdeabcd' + pt.on('finish', function() { + t.equal(pt.read(5).toString(), 'abcde'); + t.equal(pt.read(5).toString(), 'abcde'); + t.equal(pt.read(5).toString(), 'abcd'); + t.end(); + }); +}); + +// this tests for a stall when data is written to a full stream +// that has empty transforms. +test('complex transform', function(t) { + var count = 0; + var saved = null; + var pt = new Transform({highWaterMark:3}); + pt._transform = function(c, e, cb) { + if (count++ === 1) + saved = c; + else { + if (saved) { + pt.push(saved); + saved = null; + } + pt.push(c); + } + + cb(); + }; + + pt.once('readable', function() { + process.nextTick(function() { + pt.write(new Buffer('d')); + pt.write(new Buffer('ef'), function() { + pt.end(); + t.end(); + }); + t.equal(pt.read().toString(), 'abcdef'); + t.equal(pt.read(), null); + }); + }); + + pt.write(new Buffer('abc')); +}); + + +test('passthrough event emission', function(t) { + var pt = new PassThrough(); + var emits = 0; + pt.on('readable', function() { + var state = pt._readableState; + console.error('>>> emit readable %d', emits); + emits++; + }); + + var i = 0; + + pt.write(new Buffer('foog')); + + console.error('need emit 0'); + pt.write(new Buffer('bark')); + + console.error('should have emitted readable now 1 === %d', emits); + t.equal(emits, 1); + + t.equal(pt.read(5).toString(), 'foogb'); + t.equal(pt.read(5) + '', 'null'); + + console.error('need emit 1'); + + pt.write(new Buffer('bazy')); + console.error('should have emitted, but not again'); + pt.write(new Buffer('kuel')); + + console.error('should have emitted readable now 2 === %d', emits); + t.equal(emits, 2); + + t.equal(pt.read(5).toString(), 'arkba'); + t.equal(pt.read(5).toString(), 'zykue'); + t.equal(pt.read(5), null); + + console.error('need emit 2'); + + pt.end(); + + t.equal(emits, 3); + + t.equal(pt.read(5).toString(), 'l'); + t.equal(pt.read(5), null); + + console.error('should not have emitted again'); + t.equal(emits, 3); + t.end(); +}); + +test('passthrough event emission reordered', function(t) { + var pt = new PassThrough; + var emits = 0; + pt.on('readable', function() { + console.error('emit readable', emits) + emits++; + }); + + pt.write(new Buffer('foog')); + console.error('need emit 0'); + pt.write(new Buffer('bark')); + console.error('should have emitted readable now 1 === %d', emits); + t.equal(emits, 1); + + t.equal(pt.read(5).toString(), 'foogb'); + t.equal(pt.read(5), null); + + console.error('need emit 1'); + pt.once('readable', function() { + t.equal(pt.read(5).toString(), 'arkba'); + + t.equal(pt.read(5), null); + + console.error('need emit 2'); + pt.once('readable', function() { + t.equal(pt.read(5).toString(), 'zykue'); + t.equal(pt.read(5), null); + pt.once('readable', function() { + t.equal(pt.read(5).toString(), 'l'); + t.equal(pt.read(5), null); + t.equal(emits, 4); + t.end(); + }); + pt.end(); + }); + pt.write(new Buffer('kuel')); + }); + + pt.write(new Buffer('bazy')); +}); + +test('passthrough facaded', function(t) { + console.error('passthrough facaded'); + var pt = new PassThrough; + var datas = []; + pt.on('data', function(chunk) { + datas.push(chunk.toString()); + }); + + pt.on('end', function() { + t.same(datas, ['foog', 'bark', 'bazy', 'kuel']); + t.end(); + }); + + pt.write(new Buffer('foog')); + setTimeout(function() { + pt.write(new Buffer('bark')); + setTimeout(function() { + pt.write(new Buffer('bazy')); + setTimeout(function() { + pt.write(new Buffer('kuel')); + setTimeout(function() { + pt.end(); + }, 10); + }, 10); + }, 10); + }, 10); +}); + +test('object transform (json parse)', function(t) { + console.error('json parse stream'); + var jp = new Transform({ objectMode: true }); + jp._transform = function(data, encoding, cb) { + try { + jp.push(JSON.parse(data)); + cb(); + } catch (er) { + cb(er); + } + }; + + // anything except null/undefined is fine. + // those are "magic" in the stream API, because they signal EOF. + var objects = [ + { foo: 'bar' }, + 100, + "string", + { nested: { things: [ { foo: 'bar' }, 100, "string" ] } } + ]; + + var ended = false; + jp.on('end', function() { + ended = true; + }); + + objects.forEach(function(obj) { + jp.write(JSON.stringify(obj)); + var res = jp.read(); + t.same(res, obj); + }); + + jp.end(); + // read one more time to get the 'end' event + jp.read(); + + process.nextTick(function() { + t.ok(ended); + t.end(); + }) +}); + +test('object transform (json stringify)', function(t) { + console.error('json parse stream'); + var js = new Transform({ objectMode: true }); + js._transform = function(data, encoding, cb) { + try { + js.push(JSON.stringify(data)); + cb(); + } catch (er) { + cb(er); + } + }; + + // anything except null/undefined is fine. + // those are "magic" in the stream API, because they signal EOF. + var objects = [ + { foo: 'bar' }, + 100, + "string", + { nested: { things: [ { foo: 'bar' }, 100, "string" ] } } + ]; + + var ended = false; + js.on('end', function() { + ended = true; + }); + + objects.forEach(function(obj) { + js.write(obj); + var res = js.read(); + t.equal(res, JSON.stringify(obj)); + }); + + js.end(); + // read one more time to get the 'end' event + js.read(); + + process.nextTick(function() { + t.ok(ended); + t.end(); + }) +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-unpipe-drain.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-unpipe-drain.js new file mode 100644 index 0000000..365b327 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-unpipe-drain.js @@ -0,0 +1,76 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + +var common = require('../common.js'); +var assert = require('assert'); +var stream = require('../../'); +var crypto = require('crypto'); + +var util = require('util'); + +function TestWriter() { + stream.Writable.call(this); +} +util.inherits(TestWriter, stream.Writable); + +TestWriter.prototype._write = function (buffer, encoding, callback) { + console.log('write called'); + // super slow write stream (callback never called) +}; + +var dest = new TestWriter(); + +function TestReader(id) { + stream.Readable.call(this); + this.reads = 0; +} +util.inherits(TestReader, stream.Readable); + +TestReader.prototype._read = function (size) { + this.reads += 1; + this.push(crypto.randomBytes(size)); +}; + +var src1 = new TestReader(); +var src2 = new TestReader(); + +src1.pipe(dest); + +src1.once('readable', function () { + process.nextTick(function () { + + src2.pipe(dest); + + src2.once('readable', function () { + process.nextTick(function () { + + src1.unpipe(dest); + }); + }); + }); +}); + + +process.on('exit', function () { + assert.equal(src1.reads, 2); + assert.equal(src2.reads, 2); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-unpipe-leak.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-unpipe-leak.js new file mode 100644 index 0000000..17c92ae --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-unpipe-leak.js @@ -0,0 +1,75 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + +var common = require('../common.js'); +var assert = require('assert'); +var stream = require('../../'); + +var chunk = new Buffer('hallo'); + +var util = require('util'); + +function TestWriter() { + stream.Writable.call(this); +} +util.inherits(TestWriter, stream.Writable); + +TestWriter.prototype._write = function(buffer, encoding, callback) { + callback(null); +}; + +var dest = new TestWriter(); + +// Set this high so that we'd trigger a nextTick warning +// and/or RangeError if we do maybeReadMore wrong. +function TestReader() { + stream.Readable.call(this, { highWaterMark: 0x10000 }); +} +util.inherits(TestReader, stream.Readable); + +TestReader.prototype._read = function(size) { + this.push(chunk); +}; + +var src = new TestReader(); + +for (var i = 0; i < 10; i++) { + src.pipe(dest); + src.unpipe(dest); +} + +assert.equal(src.listeners('end').length, 0); +assert.equal(src.listeners('readable').length, 0); + +assert.equal(dest.listeners('unpipe').length, 0); +assert.equal(dest.listeners('drain').length, 0); +assert.equal(dest.listeners('error').length, 0); +assert.equal(dest.listeners('close').length, 0); +assert.equal(dest.listeners('finish').length, 0); + +console.error(src._readableState); +process.on('exit', function() { + src._readableState.buffer.length = 0; + console.error(src._readableState); + assert(src._readableState.length >= src._readableState.highWaterMark); + console.log('ok'); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-writable.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-writable.js new file mode 100644 index 0000000..209c3a6 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream2-writable.js @@ -0,0 +1,393 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common.js'); +var W = require('../../').Writable; +var D = require('../../').Duplex; +var assert = require('assert'); + +var util = require('util'); +util.inherits(TestWriter, W); + +function TestWriter() { + W.apply(this, arguments); + this.buffer = []; + this.written = 0; +} + +TestWriter.prototype._write = function(chunk, encoding, cb) { + // simulate a small unpredictable latency + setTimeout(function() { + this.buffer.push(chunk.toString()); + this.written += chunk.length; + cb(); + }.bind(this), Math.floor(Math.random() * 10)); +}; + +var chunks = new Array(50); +for (var i = 0; i < chunks.length; i++) { + chunks[i] = new Array(i + 1).join('x'); +} + +// tiny node-tap lookalike. +var tests = []; +var count = 0; + +function test(name, fn) { + count++; + tests.push([name, fn]); +} + +function run() { + var next = tests.shift(); + if (!next) + return console.error('ok'); + + var name = next[0]; + var fn = next[1]; + console.log('# %s', name); + fn({ + same: assert.deepEqual, + equal: assert.equal, + end: function () { + count--; + run(); + } + }); +} + +// ensure all tests have run +process.on("exit", function () { + assert.equal(count, 0); +}); + +process.nextTick(run); + +test('write fast', function(t) { + var tw = new TestWriter({ + highWaterMark: 100 + }); + + tw.on('finish', function() { + t.same(tw.buffer, chunks, 'got chunks in the right order'); + t.end(); + }); + + chunks.forEach(function(chunk) { + // screw backpressure. Just buffer it all up. + tw.write(chunk); + }); + tw.end(); +}); + +test('write slow', function(t) { + var tw = new TestWriter({ + highWaterMark: 100 + }); + + tw.on('finish', function() { + t.same(tw.buffer, chunks, 'got chunks in the right order'); + t.end(); + }); + + var i = 0; + (function W() { + tw.write(chunks[i++]); + if (i < chunks.length) + setTimeout(W, 10); + else + tw.end(); + })(); +}); + +test('write backpressure', function(t) { + var tw = new TestWriter({ + highWaterMark: 50 + }); + + var drains = 0; + + tw.on('finish', function() { + t.same(tw.buffer, chunks, 'got chunks in the right order'); + t.equal(drains, 17); + t.end(); + }); + + tw.on('drain', function() { + drains++; + }); + + var i = 0; + (function W() { + do { + var ret = tw.write(chunks[i++]); + } while (ret !== false && i < chunks.length); + + if (i < chunks.length) { + assert(tw._writableState.length >= 50); + tw.once('drain', W); + } else { + tw.end(); + } + })(); +}); + +test('write bufferize', function(t) { + var tw = new TestWriter({ + highWaterMark: 100 + }); + + var encodings = + [ 'hex', + 'utf8', + 'utf-8', + 'ascii', + 'binary', + 'base64', + 'ucs2', + 'ucs-2', + 'utf16le', + 'utf-16le', + undefined ]; + + tw.on('finish', function() { + t.same(tw.buffer, chunks, 'got the expected chunks'); + }); + + chunks.forEach(function(chunk, i) { + var enc = encodings[ i % encodings.length ]; + chunk = new Buffer(chunk); + tw.write(chunk.toString(enc), enc); + }); + t.end(); +}); + +test('write no bufferize', function(t) { + var tw = new TestWriter({ + highWaterMark: 100, + decodeStrings: false + }); + + tw._write = function(chunk, encoding, cb) { + assert(typeof chunk === 'string'); + chunk = new Buffer(chunk, encoding); + return TestWriter.prototype._write.call(this, chunk, encoding, cb); + }; + + var encodings = + [ 'hex', + 'utf8', + 'utf-8', + 'ascii', + 'binary', + 'base64', + 'ucs2', + 'ucs-2', + 'utf16le', + 'utf-16le', + undefined ]; + + tw.on('finish', function() { + t.same(tw.buffer, chunks, 'got the expected chunks'); + }); + + chunks.forEach(function(chunk, i) { + var enc = encodings[ i % encodings.length ]; + chunk = new Buffer(chunk); + tw.write(chunk.toString(enc), enc); + }); + t.end(); +}); + +test('write callbacks', function (t) { + var callbacks = chunks.map(function(chunk, i) { + return [i, function(er) { + callbacks._called[i] = chunk; + }]; + }).reduce(function(set, x) { + set['callback-' + x[0]] = x[1]; + return set; + }, {}); + callbacks._called = []; + + var tw = new TestWriter({ + highWaterMark: 100 + }); + + tw.on('finish', function() { + process.nextTick(function() { + t.same(tw.buffer, chunks, 'got chunks in the right order'); + t.same(callbacks._called, chunks, 'called all callbacks'); + t.end(); + }); + }); + + chunks.forEach(function(chunk, i) { + tw.write(chunk, callbacks['callback-' + i]); + }); + tw.end(); +}); + +test('end callback', function (t) { + var tw = new TestWriter(); + tw.end(function () { + t.end(); + }); +}); + +test('end callback with chunk', function (t) { + var tw = new TestWriter(); + tw.end(new Buffer('hello world'), function () { + t.end(); + }); +}); + +test('end callback with chunk and encoding', function (t) { + var tw = new TestWriter(); + tw.end('hello world', 'ascii', function () { + t.end(); + }); +}); + +test('end callback after .write() call', function (t) { + var tw = new TestWriter(); + tw.write(new Buffer('hello world')); + tw.end(function () { + t.end(); + }); +}); + +test('end callback called after write callback', function (t) { + var tw = new TestWriter(); + var writeCalledback = false; + tw.write(new Buffer('hello world'), function() { + writeCalledback = true; + }); + tw.end(function () { + t.equal(writeCalledback, true); + t.end(); + }); +}); + +test('encoding should be ignored for buffers', function(t) { + var tw = new W(); + var hex = '018b5e9a8f6236ffe30e31baf80d2cf6eb'; + tw._write = function(chunk, encoding, cb) { + t.equal(chunk.toString('hex'), hex); + t.end(); + }; + var buf = new Buffer(hex, 'hex'); + tw.write(buf, 'binary'); +}); + +test('writables are not pipable', function(t) { + var w = new W(); + w._write = function() {}; + var gotError = false; + w.on('error', function(er) { + gotError = true; + }); + w.pipe(process.stdout); + assert(gotError); + t.end(); +}); + +test('duplexes are pipable', function(t) { + var d = new D(); + d._read = function() {}; + d._write = function() {}; + var gotError = false; + d.on('error', function(er) { + gotError = true; + }); + d.pipe(process.stdout); + assert(!gotError); + t.end(); +}); + +test('end(chunk) two times is an error', function(t) { + var w = new W(); + w._write = function() {}; + var gotError = false; + w.on('error', function(er) { + gotError = true; + t.equal(er.message, 'write after end'); + }); + w.end('this is the end'); + w.end('and so is this'); + process.nextTick(function() { + assert(gotError); + t.end(); + }); +}); + +test('dont end while writing', function(t) { + var w = new W(); + var wrote = false; + w._write = function(chunk, e, cb) { + assert(!this.writing); + wrote = true; + this.writing = true; + setTimeout(function() { + this.writing = false; + cb(); + }); + }; + w.on('finish', function() { + assert(wrote); + t.end(); + }); + w.write(Buffer(0)); + w.end(); +}); + +test('finish does not come before write cb', function(t) { + var w = new W(); + var writeCb = false; + w._write = function(chunk, e, cb) { + setTimeout(function() { + writeCb = true; + cb(); + }, 10); + }; + w.on('finish', function() { + assert(writeCb); + t.end(); + }); + w.write(Buffer(0)); + w.end(); +}); + +test('finish does not come before sync _write cb', function(t) { + var w = new W(); + var writeCb = false; + w._write = function(chunk, e, cb) { + cb(); + }; + w.on('finish', function() { + assert(writeCb); + t.end(); + }); + w.write(Buffer(0), function(er) { + writeCb = true; + }); + w.end(); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream3-pause-then-read.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream3-pause-then-read.js new file mode 100644 index 0000000..2f72c15 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/test/simple/test-stream3-pause-then-read.js @@ -0,0 +1,167 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); + +var stream = require('../../'); +var Readable = stream.Readable; +var Writable = stream.Writable; + +var totalChunks = 100; +var chunkSize = 99; +var expectTotalData = totalChunks * chunkSize; +var expectEndingData = expectTotalData; + +var r = new Readable({ highWaterMark: 1000 }); +var chunks = totalChunks; +r._read = function(n) { + if (!(chunks % 2)) + setImmediate(push); + else if (!(chunks % 3)) + process.nextTick(push); + else + push(); +}; + +var totalPushed = 0; +function push() { + var chunk = chunks-- > 0 ? new Buffer(chunkSize) : null; + if (chunk) { + totalPushed += chunk.length; + chunk.fill('x'); + } + r.push(chunk); +} + +read100(); + +// first we read 100 bytes +function read100() { + readn(100, onData); +} + +function readn(n, then) { + console.error('read %d', n); + expectEndingData -= n; + ;(function read() { + var c = r.read(n); + if (!c) + r.once('readable', read); + else { + assert.equal(c.length, n); + assert(!r._readableState.flowing); + then(); + } + })(); +} + +// then we listen to some data events +function onData() { + expectEndingData -= 100; + console.error('onData'); + var seen = 0; + r.on('data', function od(c) { + seen += c.length; + if (seen >= 100) { + // seen enough + r.removeListener('data', od); + r.pause(); + if (seen > 100) { + // oh no, seen too much! + // put the extra back. + var diff = seen - 100; + r.unshift(c.slice(c.length - diff)); + console.error('seen too much', seen, diff); + } + + // Nothing should be lost in between + setImmediate(pipeLittle); + } + }); +} + +// Just pipe 200 bytes, then unshift the extra and unpipe +function pipeLittle() { + expectEndingData -= 200; + console.error('pipe a little'); + var w = new Writable(); + var written = 0; + w.on('finish', function() { + assert.equal(written, 200); + setImmediate(read1234); + }); + w._write = function(chunk, encoding, cb) { + written += chunk.length; + if (written >= 200) { + r.unpipe(w); + w.end(); + cb(); + if (written > 200) { + var diff = written - 200; + written -= diff; + r.unshift(chunk.slice(chunk.length - diff)); + } + } else { + setImmediate(cb); + } + }; + r.pipe(w); +} + +// now read 1234 more bytes +function read1234() { + readn(1234, resumePause); +} + +function resumePause() { + console.error('resumePause'); + // don't read anything, just resume and re-pause a whole bunch + r.resume(); + r.pause(); + r.resume(); + r.pause(); + r.resume(); + r.pause(); + r.resume(); + r.pause(); + r.resume(); + r.pause(); + setImmediate(pipe); +} + + +function pipe() { + console.error('pipe the rest'); + var w = new Writable(); + var written = 0; + w._write = function(chunk, encoding, cb) { + written += chunk.length; + cb(); + }; + w.on('finish', function() { + console.error('written', written, totalPushed); + assert.equal(written, expectEndingData); + assert.equal(totalPushed, expectTotalData); + console.log('ok'); + }); + r.pipe(w); +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/transform.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/transform.js new file mode 100644 index 0000000..5d482f0 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/transform.js @@ -0,0 +1 @@ +module.exports = require("./lib/_stream_transform.js") diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/writable.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/writable.js new file mode 100644 index 0000000..e1e9efd --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/writable.js @@ -0,0 +1 @@ +module.exports = require("./lib/_stream_writable.js") diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/zlib.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/zlib.js new file mode 100644 index 0000000..a30ca20 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/readable-stream/zlib.js @@ -0,0 +1,452 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var Transform = require('./lib/_stream_transform.js'); + +var binding = process.binding('zlib'); +var util = require('util'); +var assert = require('assert').ok; + +// zlib doesn't provide these, so kludge them in following the same +// const naming scheme zlib uses. +binding.Z_MIN_WINDOWBITS = 8; +binding.Z_MAX_WINDOWBITS = 15; +binding.Z_DEFAULT_WINDOWBITS = 15; + +// fewer than 64 bytes per chunk is stupid. +// technically it could work with as few as 8, but even 64 bytes +// is absurdly low. Usually a MB or more is best. +binding.Z_MIN_CHUNK = 64; +binding.Z_MAX_CHUNK = Infinity; +binding.Z_DEFAULT_CHUNK = (16 * 1024); + +binding.Z_MIN_MEMLEVEL = 1; +binding.Z_MAX_MEMLEVEL = 9; +binding.Z_DEFAULT_MEMLEVEL = 8; + +binding.Z_MIN_LEVEL = -1; +binding.Z_MAX_LEVEL = 9; +binding.Z_DEFAULT_LEVEL = binding.Z_DEFAULT_COMPRESSION; + +// expose all the zlib constants +Object.keys(binding).forEach(function(k) { + if (k.match(/^Z/)) exports[k] = binding[k]; +}); + +// translation table for return codes. +exports.codes = { + Z_OK: binding.Z_OK, + Z_STREAM_END: binding.Z_STREAM_END, + Z_NEED_DICT: binding.Z_NEED_DICT, + Z_ERRNO: binding.Z_ERRNO, + Z_STREAM_ERROR: binding.Z_STREAM_ERROR, + Z_DATA_ERROR: binding.Z_DATA_ERROR, + Z_MEM_ERROR: binding.Z_MEM_ERROR, + Z_BUF_ERROR: binding.Z_BUF_ERROR, + Z_VERSION_ERROR: binding.Z_VERSION_ERROR +}; + +Object.keys(exports.codes).forEach(function(k) { + exports.codes[exports.codes[k]] = k; +}); + +exports.Deflate = Deflate; +exports.Inflate = Inflate; +exports.Gzip = Gzip; +exports.Gunzip = Gunzip; +exports.DeflateRaw = DeflateRaw; +exports.InflateRaw = InflateRaw; +exports.Unzip = Unzip; + +exports.createDeflate = function(o) { + return new Deflate(o); +}; + +exports.createInflate = function(o) { + return new Inflate(o); +}; + +exports.createDeflateRaw = function(o) { + return new DeflateRaw(o); +}; + +exports.createInflateRaw = function(o) { + return new InflateRaw(o); +}; + +exports.createGzip = function(o) { + return new Gzip(o); +}; + +exports.createGunzip = function(o) { + return new Gunzip(o); +}; + +exports.createUnzip = function(o) { + return new Unzip(o); +}; + + +// Convenience methods. +// compress/decompress a string or buffer in one step. +exports.deflate = function(buffer, callback) { + zlibBuffer(new Deflate(), buffer, callback); +}; + +exports.gzip = function(buffer, callback) { + zlibBuffer(new Gzip(), buffer, callback); +}; + +exports.deflateRaw = function(buffer, callback) { + zlibBuffer(new DeflateRaw(), buffer, callback); +}; + +exports.unzip = function(buffer, callback) { + zlibBuffer(new Unzip(), buffer, callback); +}; + +exports.inflate = function(buffer, callback) { + zlibBuffer(new Inflate(), buffer, callback); +}; + +exports.gunzip = function(buffer, callback) { + zlibBuffer(new Gunzip(), buffer, callback); +}; + +exports.inflateRaw = function(buffer, callback) { + zlibBuffer(new InflateRaw(), buffer, callback); +}; + +function zlibBuffer(engine, buffer, callback) { + var buffers = []; + var nread = 0; + + engine.on('error', onError); + engine.on('end', onEnd); + + engine.end(buffer); + flow(); + + function flow() { + var chunk; + while (null !== (chunk = engine.read())) { + buffers.push(chunk); + nread += chunk.length; + } + engine.once('readable', flow); + } + + function onError(err) { + engine.removeListener('end', onEnd); + engine.removeListener('readable', flow); + callback(err); + } + + function onEnd() { + var buf = Buffer.concat(buffers, nread); + buffers = []; + callback(null, buf); + } +} + + +// generic zlib +// minimal 2-byte header +function Deflate(opts) { + if (!(this instanceof Deflate)) return new Deflate(opts); + Zlib.call(this, opts, binding.DEFLATE); +} + +function Inflate(opts) { + if (!(this instanceof Inflate)) return new Inflate(opts); + Zlib.call(this, opts, binding.INFLATE); +} + + + +// gzip - bigger header, same deflate compression +function Gzip(opts) { + if (!(this instanceof Gzip)) return new Gzip(opts); + Zlib.call(this, opts, binding.GZIP); +} + +function Gunzip(opts) { + if (!(this instanceof Gunzip)) return new Gunzip(opts); + Zlib.call(this, opts, binding.GUNZIP); +} + + + +// raw - no header +function DeflateRaw(opts) { + if (!(this instanceof DeflateRaw)) return new DeflateRaw(opts); + Zlib.call(this, opts, binding.DEFLATERAW); +} + +function InflateRaw(opts) { + if (!(this instanceof InflateRaw)) return new InflateRaw(opts); + Zlib.call(this, opts, binding.INFLATERAW); +} + + +// auto-detect header. +function Unzip(opts) { + if (!(this instanceof Unzip)) return new Unzip(opts); + Zlib.call(this, opts, binding.UNZIP); +} + + +// the Zlib class they all inherit from +// This thing manages the queue of requests, and returns +// true or false if there is anything in the queue when +// you call the .write() method. + +function Zlib(opts, mode) { + this._opts = opts = opts || {}; + this._chunkSize = opts.chunkSize || exports.Z_DEFAULT_CHUNK; + + Transform.call(this, opts); + + // means a different thing there. + this._readableState.chunkSize = null; + + if (opts.chunkSize) { + if (opts.chunkSize < exports.Z_MIN_CHUNK || + opts.chunkSize > exports.Z_MAX_CHUNK) { + throw new Error('Invalid chunk size: ' + opts.chunkSize); + } + } + + if (opts.windowBits) { + if (opts.windowBits < exports.Z_MIN_WINDOWBITS || + opts.windowBits > exports.Z_MAX_WINDOWBITS) { + throw new Error('Invalid windowBits: ' + opts.windowBits); + } + } + + if (opts.level) { + if (opts.level < exports.Z_MIN_LEVEL || + opts.level > exports.Z_MAX_LEVEL) { + throw new Error('Invalid compression level: ' + opts.level); + } + } + + if (opts.memLevel) { + if (opts.memLevel < exports.Z_MIN_MEMLEVEL || + opts.memLevel > exports.Z_MAX_MEMLEVEL) { + throw new Error('Invalid memLevel: ' + opts.memLevel); + } + } + + if (opts.strategy) { + if (opts.strategy != exports.Z_FILTERED && + opts.strategy != exports.Z_HUFFMAN_ONLY && + opts.strategy != exports.Z_RLE && + opts.strategy != exports.Z_FIXED && + opts.strategy != exports.Z_DEFAULT_STRATEGY) { + throw new Error('Invalid strategy: ' + opts.strategy); + } + } + + if (opts.dictionary) { + if (!Buffer.isBuffer(opts.dictionary)) { + throw new Error('Invalid dictionary: it should be a Buffer instance'); + } + } + + this._binding = new binding.Zlib(mode); + + var self = this; + this._hadError = false; + this._binding.onerror = function(message, errno) { + // there is no way to cleanly recover. + // continuing only obscures problems. + self._binding = null; + self._hadError = true; + + var error = new Error(message); + error.errno = errno; + error.code = exports.codes[errno]; + self.emit('error', error); + }; + + this._binding.init(opts.windowBits || exports.Z_DEFAULT_WINDOWBITS, + opts.level || exports.Z_DEFAULT_COMPRESSION, + opts.memLevel || exports.Z_DEFAULT_MEMLEVEL, + opts.strategy || exports.Z_DEFAULT_STRATEGY, + opts.dictionary); + + this._buffer = new Buffer(this._chunkSize); + this._offset = 0; + this._closed = false; + + this.once('end', this.close); +} + +util.inherits(Zlib, Transform); + +Zlib.prototype.reset = function reset() { + return this._binding.reset(); +}; + +Zlib.prototype._flush = function(output, callback) { + var rs = this._readableState; + var self = this; + this._transform(null, output, function(er) { + if (er) + return callback(er); + + // now a weird thing happens... it could be that you called flush + // but everything had already actually been consumed, but it wasn't + // enough to get over the Readable class's lowWaterMark. + // In that case, we emit 'readable' now to make sure it's consumed. + if (rs.length && + rs.length < rs.lowWaterMark && + !rs.ended && + rs.needReadable) + self.emit('readable'); + + callback(); + }); +}; + +Zlib.prototype.flush = function(callback) { + var ws = this._writableState; + var ts = this._transformState; + + if (ws.writing) { + ws.needDrain = true; + var self = this; + this.once('drain', function() { + self._flush(ts.output, callback); + }); + return; + } + + this._flush(ts.output, callback || function() {}); +}; + +Zlib.prototype.close = function(callback) { + if (callback) + process.nextTick(callback); + + if (this._closed) + return; + + this._closed = true; + + this._binding.close(); + + var self = this; + process.nextTick(function() { + self.emit('close'); + }); +}; + +Zlib.prototype._transform = function(chunk, output, cb) { + var flushFlag; + var ws = this._writableState; + var ending = ws.ending || ws.ended; + var last = ending && (!chunk || ws.length === chunk.length); + + if (chunk !== null && !Buffer.isBuffer(chunk)) + return cb(new Error('invalid input')); + + // If it's the last chunk, or a final flush, we use the Z_FINISH flush flag. + // If it's explicitly flushing at some other time, then we use + // Z_FULL_FLUSH. Otherwise, use Z_NO_FLUSH for maximum compression + // goodness. + if (last) + flushFlag = binding.Z_FINISH; + else if (chunk === null) + flushFlag = binding.Z_FULL_FLUSH; + else + flushFlag = binding.Z_NO_FLUSH; + + var availInBefore = chunk && chunk.length; + var availOutBefore = this._chunkSize - this._offset; + var inOff = 0; + + var req = this._binding.write(flushFlag, + chunk, // in + inOff, // in_off + availInBefore, // in_len + this._buffer, // out + this._offset, //out_off + availOutBefore); // out_len + + req.buffer = chunk; + req.callback = callback; + + var self = this; + function callback(availInAfter, availOutAfter, buffer) { + if (self._hadError) + return; + + var have = availOutBefore - availOutAfter; + assert(have >= 0, 'have should not go down'); + + if (have > 0) { + var out = self._buffer.slice(self._offset, self._offset + have); + self._offset += have; + // serve some output to the consumer. + output(out); + } + + // exhausted the output buffer, or used all the input create a new one. + if (availOutAfter === 0 || self._offset >= self._chunkSize) { + availOutBefore = self._chunkSize; + self._offset = 0; + self._buffer = new Buffer(self._chunkSize); + } + + if (availOutAfter === 0) { + // Not actually done. Need to reprocess. + // Also, update the availInBefore to the availInAfter value, + // so that if we have to hit it a third (fourth, etc.) time, + // it'll have the correct byte counts. + inOff += (availInBefore - availInAfter); + availInBefore = availInAfter; + + var newReq = self._binding.write(flushFlag, + chunk, + inOff, + availInBefore, + self._buffer, + self._offset, + self._chunkSize); + newReq.callback = callback; // this same function + newReq.buffer = chunk; + return; + } + + // finished with the chunk. + cb(); + } +}; + +util.inherits(Deflate, Zlib); +util.inherits(Inflate, Zlib); +util.inherits(Gzip, Zlib); +util.inherits(Gunzip, Zlib); +util.inherits(DeflateRaw, Zlib); +util.inherits(InflateRaw, Zlib); +util.inherits(Unzip, Zlib); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/.npmignore b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/.npmignore new file mode 100644 index 0000000..07e6e47 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/.npmignore @@ -0,0 +1 @@ +/node_modules diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/README.md b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/README.md new file mode 100644 index 0000000..8d6a192 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/README.md @@ -0,0 +1,14 @@ +# stream-counter + +Keep track of how many bytes have been written to a stream. + +## Usage + +```js +var StreamCounter = require('stream-counter'); +var counter = new StreamCounter(); +counter.on('progress', function() { + console.log("progress", counter.bytes); +}); +fs.createReadStream('foo.txt').pipe(counter); +``` diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/index.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/index.js new file mode 100644 index 0000000..c490c2d --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/index.js @@ -0,0 +1,16 @@ +module.exports = ByteCounter; + +var Writable = require('readable-stream').Writable; +var util = require('util'); + +util.inherits(ByteCounter, Writable); +function ByteCounter(options) { + Writable.call(this, options); + this.bytes = 0; +} + +ByteCounter.prototype._write = function(chunk, encoding, cb) { + this.bytes += chunk.length; + this.emit('progress'); + cb(); +}; diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/package.json b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/package.json new file mode 100644 index 0000000..d4bb6ef --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/package.json @@ -0,0 +1,35 @@ +{ + "name": "stream-counter", + "version": "0.2.0", + "description": "keeps track of how many bytes have been written to a stream", + "main": "index.js", + "scripts": { + "test": "node test/test.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/superjoe30/node-stream-counter.git" + }, + "author": { + "name": "Andrew Kelley", + "email": "superjoe30@gmail.com" + }, + "license": "BSD", + "engines": { + "node": ">=0.8.0" + }, + "dependencies": { + "readable-stream": "~1.1.8" + }, + "readme": "# stream-counter\n\nKeep track of how many bytes have been written to a stream.\n\n## Usage\n\n```js\nvar StreamCounter = require('stream-counter');\nvar counter = new StreamCounter();\ncounter.on('progress', function() {\n console.log(\"progress\", counter.bytes);\n});\nfs.createReadStream('foo.txt').pipe(counter);\n```\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/superjoe30/node-stream-counter/issues" + }, + "_id": "stream-counter@0.2.0", + "dist": { + "shasum": "4d7a64f8095209f665686f806df810439a6a19c1" + }, + "_from": "stream-counter@~0.2.0", + "_resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-0.2.0.tgz" +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/test/test.js b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/test/test.js new file mode 100644 index 0000000..0da9566 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/test/test.js @@ -0,0 +1,20 @@ +var ByteCounter = require('../'); +var fs = require('fs'); +var path = require('path'); +var assert = require('assert'); + +var counter = new ByteCounter(); +var remainingTests = 2; +counter.once('progress', function() { + assert.strictEqual(counter.bytes, 5); + remainingTests -= 1; +}); +var is = fs.createReadStream(path.join(__dirname, 'test.txt')); +is.pipe(counter); +is.on('end', function() { + remainingTests -= 1; + assert.strictEqual(counter.bytes, 5); +}); +process.on('exit', function() { + assert.strictEqual(remainingTests, 0); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/test/test.txt b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/test/test.txt new file mode 100644 index 0000000..81c545e --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/node_modules/stream-counter/test/test.txt @@ -0,0 +1 @@ +1234 diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/package.json b/node_modules/express/node_modules/connect/node_modules/multiparty/package.json new file mode 100644 index 0000000..bf48102 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/package.json @@ -0,0 +1,46 @@ +{ + "name": "multiparty", + "version": "2.2.0", + "description": "multipart/form-data parser which supports streaming", + "repository": { + "type": "git", + "url": "git@github.com:superjoe30/node-multiparty.git" + }, + "keywords": [ + "file", + "upload", + "formidable", + "stream", + "s3" + ], + "devDependencies": { + "findit": "0.1.1", + "hashish": "0.0.4", + "mocha": "~1.8.2", + "request": "~2.16.6", + "mkdirp": "~0.3.5", + "superagent": "~0.14.1" + }, + "scripts": { + "test": "ulimit -n 500 && mocha --timeout 4000 --reporter spec --recursive test/test.js" + }, + "engines": { + "node": ">=0.8.0" + }, + "license": "MIT", + "dependencies": { + "readable-stream": "~1.1.9", + "stream-counter": "~0.2.0" + }, + "readme": "[![Build Status](https://travis-ci.org/superjoe30/node-multiparty.png?branch=master)](https://travis-ci.org/superjoe30/node-multiparty)\n# multiparty\n\nParse http requests with content-type `multipart/form-data`, also known as file uploads.\n\nSee also [busboy](https://github.com/mscdex/busboy) - a\n[faster](https://github.com/mscdex/dicer/wiki/Benchmarks) alternative\nwhich may be worth looking into.\n\n### Why the fork?\n\n * This module uses the Node.js v0.10 streams properly, *even in Node.js v0.8*\n * It will not create a temp file for you unless you want it to.\n * Counts bytes and does math to help you figure out the `Content-Length` of\n each part.\n * You can easily stream uploads to s3 with\n [knox](https://github.com/LearnBoost/knox), for [example](examples/s3.js).\n * Less bugs. This code is simpler, has all deprecated functionality removed,\n has cleaner tests, and does not try to do anything beyond multipart stream\n parsing.\n\n## Installation\n\n```\nnpm install multiparty\n```\n\n## Usage\n\n * See [examples](examples).\n\nParse an incoming `multipart/form-data` request.\n\n```js\nvar multiparty = require('multiparty')\n , http = require('http')\n , util = require('util')\n\nhttp.createServer(function(req, res) {\n if (req.url === '/upload' && req.method === 'POST') {\n // parse a file upload\n var form = new multiparty.Form();\n\n form.parse(req, function(err, fields, files) {\n res.writeHead(200, {'content-type': 'text/plain'});\n res.write('received upload:\\n\\n');\n res.end(util.inspect({fields: fields, files: files}));\n });\n\n return;\n }\n\n // show a file upload form\n res.writeHead(200, {'content-type': 'text/html'});\n res.end(\n '
    '+\n '
    '+\n '
    '+\n ''+\n '
    '\n );\n}).listen(8080);\n```\n\n## API\n\n### multiparty.Form\n```js\nvar form = new multiparty.Form(options)\n```\nCreates a new form. Options:\n\n * `encoding` - sets encoding for the incoming form fields. Defaults to `utf8`.\n * `maxFieldSize` - Limits the amount of memory a field (not a file) can\n allocate in bytes. If this value is exceeded, an `error` event is emitted.\n The default size is 2MB.\n * `maxFields` - Limits the number of fields that will be parsed before\n emitting an `error` event. A file counts as a field in this case.\n Defaults to 1000.\n * `autoFields` - Enables `field` events. This is automatically set to `true`\n if you add a `field` listener.\n * `autoFiles` - Enables `file` events. This is automatically set to `true`\n if you add a `file` listener.\n * `uploadDir` - Only relevant when `autoFiles` is `true`. The directory for\n placing file uploads in. You can move them later using `fs.rename()`.\n Defaults to `os.tmpDir()`.\n * `hash` - Only relevant when `autoFiles` is `true`. If you want checksums\n calculated for incoming files, set this to either `sha1` or `md5`.\n Defaults to off.\n\n#### form.parse(request, [cb])\n\nParses an incoming node.js `request` containing form data. If `cb` is\nprovided, `autoFields` and `autoFiles` are set to `true` and all fields and\nfiles are collected and passed to the callback:\n\n```js\nform.parse(req, function(err, fieldsObject, filesObject, fieldsList, filesList) {\n // ...\n});\n```\n\nIt is often convenient to access a field or file by name. In this situation,\nuse `fieldsObject` or `filesObject`. However sometimes, as in the case of a\n`` the multipart stream will contain\nmultiple files of the same input name, and you are interested in all of them.\nIn this case, use `filesList`.\n\nAnother example is when you do not care what the field name of a file is; you\nare merely interested in a single upload. In this case, set `maxFields` to 1\n(assuming no other fields expected besides the file) and use `filesList[0]`.\n\n#### form.bytesReceived\n\nThe amount of bytes received for this form so far.\n\n#### form.bytesExpected\n\nThe expected number of bytes in this form.\n\n### Events\n\n#### 'error' (err)\n\nYou definitely want to handle this event. If not your server *will* crash when\nusers submit bogus multipart requests!\n\n#### 'part' (part)\n\nEmitted when a part is encountered in the request. `part` is a\n`ReadableStream`. It also has the following properties:\n\n * `headers` - the headers for this part. For example, you may be interested\n in `content-type`.\n * `name` - the field name for this part\n * `filename` - only if the part is an incoming file\n * `byteOffset` - the byte offset of this part in the request body\n * `byteCount` - assuming that this is the last part in the request,\n this is the size of this part in bytes. You could use this, for\n example, to set the `Content-Length` header if uploading to S3.\n If the part had a `Content-Length` header then that value is used\n here instead.\n\n#### 'aborted'\n\nEmitted when the request is aborted. This event will be followed shortly\nby an `error` event. In practice you do not need to handle this event.\n\n#### 'progress' (bytesReceived, bytesExpected)\n\n#### 'close'\n\nEmitted after all parts have been parsed and emitted. Not emitted if an `error`\nevent is emitted. This is typically when you would send your response.\n\n#### 'file' (name, file)\n\n**By default multiparty will not touch your hard drive.** But if you add this\nlistener, multiparty automatically sets `form.autoFiles` to `true` and will\nstream uploads to disk for you. \n\n * `name` - the field name for this file\n * `file` - an object with these properties:\n - `fieldName` - same as `name` - the field name for this file\n - `originalFilename` - the filename that the user reports for the file\n - `path` - the absolute path of the uploaded file on disk\n - `headers` - the HTTP headers that were sent along with this file\n - `size` - size of the file in bytes\n\nIf you set the `form.hash` option, then `file` will also contain a `hash`\nproperty which is the checksum of the file.\n\n#### 'field' (name, value)\n\n * `name` - field name\n * `value` - string field value\n\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/superjoe30/node-multiparty/issues" + }, + "_id": "multiparty@2.2.0", + "dist": { + "shasum": "6f771955f8cffe3d08937a9592db04e1573bfb34" + }, + "_from": "multiparty@2.2.0", + "_resolved": "https://registry.npmjs.org/multiparty/-/multiparty-2.2.0.tgz" +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/bench-multipart-parser.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/bench-multipart-parser.js new file mode 100644 index 0000000..ee5dbad --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/bench-multipart-parser.js @@ -0,0 +1,76 @@ +var assert = require('assert') + , Form = require('../').Form + , boundary = '-----------------------------168072824752491622650073' + , mb = 100 + , buffer = createMultipartBuffer(boundary, mb * 1024 * 1024) + +var callbacks = { + partBegin: -1, + partEnd: -1, + headerField: -1, + headerValue: -1, + partData: -1, + end: -1, +}; + +var form = new Form({ boundary: boundary }); + +hijack('onParseHeaderField', function() { + callbacks.headerField++; +}); + +hijack('onParseHeaderValue', function() { + callbacks.headerValue++; +}); + +hijack('onParsePartBegin', function() { + callbacks.partBegin++; +}); + +hijack('onParsePartData', function() { + callbacks.partData++; +}); + +hijack('onParsePartEnd', function() { + callbacks.partEnd++; +}); + +form.on('finish', function() { + callbacks.end++; +}); + +var start = new Date(); +form.write(buffer, function(err) { + var duration = new Date() - start; + assert.ifError(err); + var mbPerSec = (mb / (duration / 1000)).toFixed(2); + console.log(mbPerSec+' mb/sec'); +}); + +process.on('exit', function() { + for (var k in callbacks) { + assert.equal(0, callbacks[k], k+' count off by '+callbacks[k]); + } +}); + +function createMultipartBuffer(boundary, size) { + var head = + '--'+boundary+'\r\n' + + 'content-disposition: form-data; name="field1"\r\n' + + '\r\n' + , tail = '\r\n--'+boundary+'--\r\n' + , buffer = new Buffer(size); + + buffer.write(head, 'ascii', 0); + buffer.write(tail, 'ascii', buffer.length - tail.length); + return buffer; +} + +function hijack(name, fn) { + var oldFn = form[name]; + form[name] = function() { + fn(); + return oldFn.apply(this, arguments); + }; +} + diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/beta-sticker-1.png b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/beta-sticker-1.png new file mode 100644 index 0000000..20b1a7f Binary files /dev/null and b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/beta-sticker-1.png differ diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/binaryfile.tar.gz b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/binaryfile.tar.gz new file mode 100644 index 0000000..4a85af7 Binary files /dev/null and b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/binaryfile.tar.gz differ diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/blank.gif b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/blank.gif new file mode 100755 index 0000000..75b945d Binary files /dev/null and b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/blank.gif differ diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/funkyfilename.txt b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/funkyfilename.txt new file mode 100644 index 0000000..e7a4785 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/funkyfilename.txt @@ -0,0 +1 @@ +I am a text file with a funky name! diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/menu_separator.png b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/menu_separator.png new file mode 100644 index 0000000..1c16a71 Binary files /dev/null and b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/menu_separator.png differ diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/pf1y5.png b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/pf1y5.png new file mode 100644 index 0000000..44d6017 Binary files /dev/null and b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/pf1y5.png differ diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/plain.txt b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/plain.txt new file mode 100644 index 0000000..9b6903e --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/file/plain.txt @@ -0,0 +1 @@ +I am a plain text file diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/beta-sticker-1.png.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/beta-sticker-1.png.http new file mode 100644 index 0000000..833b83c --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/beta-sticker-1.png.http @@ -0,0 +1,12 @@ +POST /upload HTTP/1.1 +Host: localhost:8080 +Content-Type: multipart/form-data; boundary=\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +Content-Length: 2483 + +--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +Content-Disposition: form-data; name="sticker"; filename="beta-sticker-1.png" +Content-Type: image/png +Content-Transfer-Encoding: base64 + +iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABh5JREFUeNrMmHtIHEcYwGfv5SNwaovxEanEiJKqlYCCTRo1f0SvDeof1legEcE/YttQaNOiaQjYFFtpKaJILZU8SCRUWqlJGpoWepGLTXqUEnzFxCrnK9DEelbvvPOe/WacuY7r7HmGFjrwsbNzt7u//V7zfYvQ/2xI/9K1/NyvMP9PgCTuGmmL6/0ckD9UOGmbIExUsqMkAPHJjv5QwKRtgKioqDlh5+w/7IFeCuLlxCeA2zQ0IcCwh2qoaLH09fUdTElJ2e/1elU+n0/y+9fvPz4+fvfYsWN3YOoBcXPiocLghD4mBYHhQTCErqWlZU9FRcXJqKiowyqVSk/uSEH4o8fjWVlYWDB2d3e3d3R0WGB5jYqLg/NyGgsKxMNgkDB4451NTU3vxcXF1SlBKB0tFsuVxsbGjlu3bj2GJQeIk8K5RVBqBTMxrYRfuHAh9/jx4+ejo6MPS9I6f6hHPOC6rOLi4vyVlZXf7t27Z5c5/iZfkgMxxyUwFy9ezC0tLe3V6XRJ/MOCAYjWwsLCni0oKCh98uSJaWhoyMZFn0/uT2qBqYi/1NbWxjc0NJwPFUYExc/B53R5eXk5ZrN5YH5+3slFn5+D2uBDzG90IJETExOtzGdC9RelNf78wYMH3xQWFn4Ep0sgyyCr1NmJP6kEIa5tbW3dEx8fXxeKRoJpT76OR3p6enllZWUKTCOwNalFAglWDkTCvLq6+uR2YYKZSw4GQVKNfZQCafjkqhKYTBsTE3NY/uYi2Q4MP5KTkw9QGB3VEMv6G/YioqFLly5lazQavfytxobnUW+PWTGisIyNPEL3QYLB4PPIyMi4EydO7JUBbTIZ0RDYOFPkE8t/OdHczCK6Y/qdzP8BfUTW8Tj/uQndvT1F5vOzVvTLz1PwX4cQbt++fekURsNpSNLIw16v1z/HLsRRgecsSnovm8nxs5bvUe+NN1Bz47fkfBaAXj2aA2BWEsM/3hhFX1/5Fe3NTEAfvn8NXTO+tSH68IiNjU2Qw/AmCzg2XCQp+YyhJAu9c+pl9GJ+KmhiEt38bhjpoyJQRtYudA60k3dwD6o4mouKjmSiolcy0ArRqnXz3rT+knwFEShhNKLNlmmFP7Kf8XxuehHpj0QQmLdPGch/ioYyCSAe57pMaHnJgcprctDdwUkRjKi8CUTWhipvbm7uvlJo3zFNoHJDOznPeGEXqn+9EBUf+AQZXvqU+BEG/KCpHz2flYh+ALO9++ZX5L/Mj3gfevjw4ZRoP+PzD/b4HadPn844c+aMkb0F1DqIz9byzBvquXytvr6+7vr16+Ow9CfN2njjdfFAWpo9o2FnNmm12kQMw24gcvSnhbHb7Y+huHsNlhapLNHSxK3idlq287qhhrkKlSByOBzIZrPhGyCn04ncbjfRGAMV5ZlQxvDw8E+yYi1Q3qpleYjUQlNTU5aysrJqgNBhIAwGVSDCkFj48BVFULA1eCl7XV3dx1CKYK3YqKnY7u9Ti2royclJ76FDh1YhxefgsoFpCIOtra0RuGBQwYbRaLzc1dVlpjA2ZiqmKbWsDAmEYU9Pz8Tg4OCNoqKixNTU1BQostDq6iqBcrlcRBiYfEff1KBR+OnpabPBYOikWlnhtOOWm0zUffpnZ2ednZ2dJtCYMTs7+xkA2x0eHk6gsMYwFPYr/EC1Wo2LMEWzWa1WC1QRZ8FUVgpj42ohD3umWqHjRFxf5RkZGVkCNQ9CcTWQn5+flpSUtBOiMKAt7Fek/FSAmpmZMVdVVZ0dGxv7g4PhteMVlbBIofv0sh4Lbmhtb2+/Cbv1eFpaWmJCQsJODMO0hGGgUghAAay9v7//i5KSki9lmmG+4+Jg/MHaIH6f0dCkqaNFFc5VkViam5v319TUNEDdvRubEGsNYHGqsAwMDFxta2u7DdpdpA+3c+LgWiHfVkCiFnpDw0iLqwgqO6BVKoPo00K6WIDsOzE6OrpE395FzeLgxMn5jVe0dYTa26s5jfFg4VR0nAuwNtrFda1rgmToD6VzVWq3eTPyYAxOwwH5gvT2PiWY7X4fUgJTywp1fivyyL6E+Lb6XvQ0X9AkBeeXZED+p/k+9LcAAwAXm3hBLzoZPAAAAABJRU5ErkJggg== +--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/-- diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/binaryfile.tar.gz.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/binaryfile.tar.gz.http new file mode 100644 index 0000000..4f4fadb --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/binaryfile.tar.gz.http @@ -0,0 +1,12 @@ +POST /upload HTTP/1.1 +Host: localhost:8080 +Content-Type: multipart/form-data; boundary=\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +Content-Length: 676 + +--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +Content-Disposition: form-data; name="file"; filename="binaryfile.tar.gz" +Content-Type: application/x-gzip +Content-Transfer-Encoding: base64 + +H4sIAGiNIU8AA+3R0W6CMBQGYK59iobLZantRDG73osUOGqnFNJWM2N897UghG1ZdmWWLf93U/jP4bRAq8q92hJ/dY1J7kQEqyyLq8yXYrp2ltkqkTKXYiEykYc++ZTLVcLEvQ40dXReWcYSV1pdnL/v+6n+R11mjKVG1ZQ+s3TT2FpXqjhQ+hjzE1mnGxNLkgu+7tOKWjIVmVKTC6XL9ZaeXj4VQhwKWzL+cI4zwgQuuhkh3mhTad/Hkssh3im3027X54JnQ360R/M19OT8kC7SEN7Ooi2VvrEfznHQRWzl83gxttZKmzGehzPRW/+W8X+3fvL8sFet9sS6m3EIma02071MU3Uf9KHrmV1/+y8DAAAAAAAAAAAAAAAAAAAAAMB/9A6txIuJACgAAA== +--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/-- diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/blank.gif.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/blank.gif.http new file mode 100644 index 0000000..7426f5b --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/blank.gif.http @@ -0,0 +1,12 @@ +POST /upload HTTP/1.1 +Host: localhost:8080 +Content-Type: multipart/form-data; boundary=\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +Content-Length: 323 + +--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +Content-Disposition: form-data; name="file"; filename="blank.gif" +Content-Type: image/gif +Content-Transfer-Encoding: base64 + +R0lGODlhAQABAJH/AP///wAAAMDAwAAAACH5BAEAAAIALAAAAAABAAEAAAICVAEAOw== +--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/-- diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/menu_seperator.png.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/menu_seperator.png.http new file mode 100644 index 0000000..d08fd37 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/menu_seperator.png.http @@ -0,0 +1,12 @@ +POST /upload HTTP/1.1 +Host: localhost:8080 +Content-Type: multipart/form-data; boundary=\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +Content-Length: 1509 + +--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +Content-Disposition: form-data; name="image"; filename="menu_separator.png" +Content-Type: image/png +Content-Transfer-Encoding: base64 + +iVBORw0KGgoAAAANSUhEUgAAAAIAAAAYCAIAAABfmbuOAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDcxODNBNzJERDcyMTFFMUFBOEVFNDQzOTA0MDJDMjQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDcxODNBNzNERDcyMTFFMUFBOEVFNDQzOTA0MDJDMjQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowNzE4M0E3MERENzIxMUUxQUE4RUU0NDM5MDQwMkMyNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowNzE4M0E3MURENzIxMUUxQUE4RUU0NDM5MDQwMkMyNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pmvhbb8AAAAXSURBVHjaYnHk9PON8WJiAIPBSwEEGAAPrgG+VozFWgAAAABJRU5ErkJggg== +--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/-- diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/pf1y5.png.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/pf1y5.png.http new file mode 100644 index 0000000..20c2c2d Binary files /dev/null and b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/pf1y5.png.http differ diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/plain.txt.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/plain.txt.http new file mode 100644 index 0000000..5e85ad6 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/encoding/plain.txt.http @@ -0,0 +1,13 @@ +POST /upload HTTP/1.1 +Host: localhost:8080 +Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ +Content-Length: 221 + +------TLV0SrKD4z1TRxRhAPUvZ +Content-Disposition: form-data; name="file"; filename="plain.txt" +Content-Type: text/plain +Content-Transfer-Encoding: 7bit + +I am a plain text file + +------TLV0SrKD4z1TRxRhAPUvZ-- diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/no-filename/filename-name.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/no-filename/filename-name.http new file mode 100644 index 0000000..43672a3 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/no-filename/filename-name.http @@ -0,0 +1,13 @@ +POST /upload HTTP/1.1 +Host: localhost:8080 +Content-Type: multipart/form-data; boundary=----WebKitFormBoundarytyE4wkKlZ5CQJVTG +Content-Length: 1000 + +------WebKitFormBoundarytyE4wkKlZ5CQJVTG +Content-Disposition: form-data; filename="plain.txt"; name="upload" +Content-Type: text/plain + +I am a plain text file + +------WebKitFormBoundarytyE4wkKlZ5CQJVTG-- + diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/no-filename/generic.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/no-filename/generic.http new file mode 100644 index 0000000..e0dee27 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/no-filename/generic.http @@ -0,0 +1,13 @@ +POST /upload HTTP/1.1 +Host: localhost:8080 +Content-Type: multipart/form-data; boundary=----WebKitFormBoundarytyE4wkKlZ5CQJVTG +Content-Length: 1000 + +------WebKitFormBoundarytyE4wkKlZ5CQJVTG +Content-Disposition: form-data; name="upload"; filename="" +Content-Type: text/plain + +I am a plain text file + +------WebKitFormBoundarytyE4wkKlZ5CQJVTG-- + diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/preamble/crlf.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/preamble/crlf.http new file mode 100644 index 0000000..1d5f709 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/preamble/crlf.http @@ -0,0 +1,13 @@ +POST /upload HTTP/1.1 +Host: localhost:8080 +Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ +Content-Length: 184 + + +------TLV0SrKD4z1TRxRhAPUvZ +Content-Disposition: form-data; name="upload"; filename="plain.txt" +Content-Type: text/plain + +I am a plain text file + +------TLV0SrKD4z1TRxRhAPUvZ-- diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/preamble/preamble.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/preamble/preamble.http new file mode 100644 index 0000000..d14d433 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/preamble/preamble.http @@ -0,0 +1,13 @@ +POST /upload HTTP/1.1 +Host: localhost:8080 +Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ +Content-Length: 226 + +This is a preamble which should be ignored +------TLV0SrKD4z1TRxRhAPUvZ +Content-Disposition: form-data; name="upload"; filename="plain.txt" +Content-Type: text/plain + +I am a plain text file + +------TLV0SrKD4z1TRxRhAPUvZ-- diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/info.md b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/info.md new file mode 100644 index 0000000..3c9dbe3 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/info.md @@ -0,0 +1,3 @@ +* Opera does not allow submitting this file, it shows a warning to the + user that the file could not be found instead. Tested in 9.8, 11.51 on OSX. + Reported to Opera on 08.09.2011 (tracking email DSK-346009@bugs.opera.com). diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/osx-chrome-13.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/osx-chrome-13.http new file mode 100644 index 0000000..4ef3917 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/osx-chrome-13.http @@ -0,0 +1,26 @@ +POST /upload HTTP/1.1 +Host: localhost:8080 +Connection: keep-alive +Referer: http://localhost:8080/ +Content-Length: 383 +Cache-Control: max-age=0 +Origin: http://localhost:8080 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1 +Content-Type: multipart/form-data; boundary=----WebKitFormBoundarytyE4wkKlZ5CQJVTG +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Accept-Encoding: gzip,deflate,sdch +Accept-Language: en-US,en;q=0.8 +Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 +Cookie: jqCookieJar_tablesorter=%7B%22showListTable%22%3A%5B%5B5%2C1%5D%2C%5B1%2C0%5D%5D%7D + +------WebKitFormBoundarytyE4wkKlZ5CQJVTG +Content-Disposition: form-data; name="title" + +Weird filename +------WebKitFormBoundarytyE4wkKlZ5CQJVTG +Content-Disposition: form-data; name="upload"; filename=": \ ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt" +Content-Type: text/plain + +I am a text file with a funky name! + +------WebKitFormBoundarytyE4wkKlZ5CQJVTG-- diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/osx-firefox-3.6.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/osx-firefox-3.6.http new file mode 100644 index 0000000..bf49f85 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/osx-firefox-3.6.http @@ -0,0 +1,24 @@ +POST /upload HTTP/1.1 +Host: localhost:8080 +User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.22) Gecko/20110902 Firefox/3.6.22 +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Accept-Language: en-us,en;q=0.5 +Accept-Encoding: gzip,deflate +Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 +Keep-Alive: 115 +Connection: keep-alive +Referer: http://localhost:8080/ +Content-Type: multipart/form-data; boundary=---------------------------9849436581144108930470211272 +Content-Length: 438 + +-----------------------------9849436581144108930470211272 +Content-Disposition: form-data; name="title" + +Weird filename +-----------------------------9849436581144108930470211272 +Content-Disposition: form-data; name="upload"; filename=": \ ? % * | " < > . ☃ ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt" +Content-Type: text/plain + +I am a text file with a funky name! + +-----------------------------9849436581144108930470211272-- diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/osx-safari-5.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/osx-safari-5.http new file mode 100644 index 0000000..ff158a4 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/osx-safari-5.http @@ -0,0 +1,23 @@ +POST /upload HTTP/1.1 +Host: localhost:8080 +Origin: http://localhost:8080 +Content-Length: 383 +User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1 +Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryQJZ1gvhvdgfisJPJ +Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 +Referer: http://localhost:8080/ +Accept-Language: en-us +Accept-Encoding: gzip, deflate +Connection: keep-alive + +------WebKitFormBoundaryQJZ1gvhvdgfisJPJ +Content-Disposition: form-data; name="title" + +Weird filename +------WebKitFormBoundaryQJZ1gvhvdgfisJPJ +Content-Disposition: form-data; name="upload"; filename=": \ ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt" +Content-Type: text/plain + +I am a text file with a funky name! + +------WebKitFormBoundaryQJZ1gvhvdgfisJPJ-- diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/xp-chrome-12.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/xp-chrome-12.http new file mode 100644 index 0000000..f0fc533 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/xp-chrome-12.http @@ -0,0 +1,24 @@ +POST /upload HTTP/1.1 +Host: 192.168.56.1:8080 +Connection: keep-alive +Referer: http://192.168.56.1:8080/ +Content-Length: 344 +Cache-Control: max-age=0 +Origin: http://192.168.56.1:8080 +User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30 +Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryEvqBNplR3ByrwQPa +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Accept-Encoding: gzip,deflate,sdch +Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4 +Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 + +------WebKitFormBoundaryEvqBNplR3ByrwQPa +Content-Disposition: form-data; name="title" + +Weird filename +------WebKitFormBoundaryEvqBNplR3ByrwQPa +Content-Disposition: form-data; name="upload"; filename=" ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt" +Content-Type: text/plain + + +------WebKitFormBoundaryEvqBNplR3ByrwQPa-- diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/xp-ie-7.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/xp-ie-7.http new file mode 100644 index 0000000..2e2c61c --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/xp-ie-7.http @@ -0,0 +1,22 @@ +POST /upload HTTP/1.1 +Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, */* +Referer: http://192.168.56.1:8080/ +Accept-Language: de +User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1) +Content-Type: multipart/form-data; boundary=---------------------------7db1fe232017c +Accept-Encoding: gzip, deflate +Host: 192.168.56.1:8080 +Content-Length: 368 +Connection: Keep-Alive +Cache-Control: no-cache + +-----------------------------7db1fe232017c +Content-Disposition: form-data; name="title" + +Weird filename +-----------------------------7db1fe232017c +Content-Disposition: form-data; name="upload"; filename=" ? % * | " < > . ☃ ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt" +Content-Type: application/octet-stream + + +-----------------------------7db1fe232017c-- diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/xp-ie-8.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/xp-ie-8.http new file mode 100644 index 0000000..e2b94fa --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/xp-ie-8.http @@ -0,0 +1,22 @@ +POST /upload HTTP/1.1 +Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, */* +Referer: http://192.168.56.1:8080/ +Accept-Language: de +User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0) +Content-Type: multipart/form-data; boundary=---------------------------7db3a8372017c +Accept-Encoding: gzip, deflate +Host: 192.168.56.1:8080 +Content-Length: 368 +Connection: Keep-Alive +Cache-Control: no-cache + +-----------------------------7db3a8372017c +Content-Disposition: form-data; name="title" + +Weird filename +-----------------------------7db3a8372017c +Content-Disposition: form-data; name="upload"; filename=" ? % * | " < > . ☃ ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt" +Content-Type: application/octet-stream + + +-----------------------------7db3a8372017c-- diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/xp-safari-5.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/xp-safari-5.http new file mode 100644 index 0000000..6379ac0 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/special-chars-in-filename/xp-safari-5.http @@ -0,0 +1,22 @@ +POST /upload HTTP/1.1 +Host: 192.168.56.1:8080 +Referer: http://192.168.56.1:8080/ +Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 +Accept-Language: en-US +Origin: http://192.168.56.1:8080 +User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4 +Accept-Encoding: gzip, deflate +Content-Type: multipart/form-data; boundary=----WebKitFormBoundarykmaWSUbu697WN9TM +Content-Length: 344 +Connection: keep-alive + +------WebKitFormBoundarykmaWSUbu697WN9TM +Content-Disposition: form-data; name="title" + +Weird filename +------WebKitFormBoundarykmaWSUbu697WN9TM +Content-Disposition: form-data; name="upload"; filename=" ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt" +Content-Type: text/plain + + +------WebKitFormBoundarykmaWSUbu697WN9TM-- diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/workarounds/missing-hyphens1.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/workarounds/missing-hyphens1.http new file mode 100644 index 0000000..2826890 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/workarounds/missing-hyphens1.http @@ -0,0 +1,12 @@ +POST /upload HTTP/1.1 +Host: localhost:8080 +Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ +Content-Length: 178 + +------TLV0SrKD4z1TRxRhAPUvZ +Content-Disposition: form-data; name="upload"; filename="plain.txt" +Content-Type: text/plain + +I am a plain text file + +------TLV0SrKD4z1TRxRhAPUvZ diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/workarounds/missing-hyphens2.http b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/workarounds/missing-hyphens2.http new file mode 100644 index 0000000..8e18194 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/http/workarounds/missing-hyphens2.http @@ -0,0 +1,12 @@ +POST /upload HTTP/1.1 +Host: localhost:8080 +Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ +Content-Length: 180 + +------TLV0SrKD4z1TRxRhAPUvZ +Content-Disposition: form-data; name="upload"; filename="plain.txt" +Content-Type: text/plain + +I am a plain text file + +------TLV0SrKD4z1TRxRhAPUvZ diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/js/encoding.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/js/encoding.js new file mode 100644 index 0000000..1ade965 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/js/encoding.js @@ -0,0 +1,69 @@ +module.exports['menu_seperator.png.http'] = [ + { + type: 'file', + name: 'image', + filename: 'menu_separator.png', + fixture: 'menu_separator.png', + sha1: 'c845ca3ea794be298f2a1b79769b71939eaf4e54', + size: 931, + } +]; + +module.exports['beta-sticker-1.png.http'] = [ + { + type: 'file', + name: 'sticker', + filename: 'beta-sticker-1.png', + fixture: 'beta-sticker-1.png', + sha1: '6abbcffd12b4ada5a6a084fe9e4584f846331bc4', + size: 1660, + } +]; + +module.exports['blank.gif.http'] = [ + { + type: 'file', + name: 'file', + filename: 'blank.gif', + fixture: 'blank.gif', + sha1: 'a1fdee122b95748d81cee426d717c05b5174fe96', + size: 49, + } +]; + +module.exports['binaryfile.tar.gz.http'] = [ + { + type: 'file', + name: 'file', + filename: 'binaryfile.tar.gz', + fixture: 'binaryfile.tar.gz', + sha1: 'cfabe13b348e5e69287d677860880c52a69d2155', + size: 301, + } +]; + +module.exports['plain.txt.http'] = [ + { + type: 'file', + name: 'file', + filename: 'plain.txt', + fixture: 'plain.txt', + sha1: 'b31d07bac24ac32734de88b3687dddb10e976872', + size: 23, + } +]; + +module.exports['pf1y5.png.http'] = [ + { + type: 'field', + name: 'path', + }, + { + type: 'file', + name: 'upload', + filename: 'pf1y5.png', + fixture: 'pf1y5.png', + sha1: '805cc640c5b182e86f2b5c8ebf34ecf063cd34fd', + size: 768323, + } +]; diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/js/no-filename.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/js/no-filename.js new file mode 100644 index 0000000..f03b4f0 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/js/no-filename.js @@ -0,0 +1,9 @@ +module.exports['generic.http'] = [ + {type: 'file', name: 'upload', filename: '', fixture: 'plain.txt', + sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'}, +]; + +module.exports['filename-name.http'] = [ + {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt', + sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'}, +]; diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/js/preamble.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/js/preamble.js new file mode 100644 index 0000000..d2e4cfd --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/js/preamble.js @@ -0,0 +1,9 @@ +module.exports['crlf.http'] = [ + {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt', + sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'}, +]; + +module.exports['preamble.http'] = [ + {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt', + sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'}, +]; diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/js/special-chars-in-filename.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/js/special-chars-in-filename.js new file mode 100644 index 0000000..aa0b79f --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/js/special-chars-in-filename.js @@ -0,0 +1,30 @@ +var properFilename = 'funkyfilename.txt'; + +function expect(filename) { + return [ + { + type: 'field', + name: 'title', + value: 'Weird filename', + }, + { + type: 'file', + name: 'upload', + filename: filename, + fixture: properFilename, + }, + ]; +} + +var webkit = " ? % * | \" < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"; +var ffOrIe = " ? % * | \" < > . ☃ ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"; + +module.exports = { + 'osx-chrome-13.http' : expect(webkit), + 'osx-firefox-3.6.http' : expect(ffOrIe), + 'osx-safari-5.http' : expect(webkit), + 'xp-chrome-12.http' : expect(webkit), + 'xp-ie-7.http' : expect(ffOrIe), + 'xp-ie-8.http' : expect(ffOrIe), + 'xp-safari-5.http' : expect(webkit), +}; diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/js/workarounds.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/js/workarounds.js new file mode 100644 index 0000000..e59c5b2 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/js/workarounds.js @@ -0,0 +1,8 @@ +module.exports['missing-hyphens1.http'] = [ + {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt', + sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'}, +]; +module.exports['missing-hyphens2.http'] = [ + {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt', + sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'}, +]; diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/multi_video.upload b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/multi_video.upload new file mode 100644 index 0000000..9c82ba3 Binary files /dev/null and b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/multi_video.upload differ diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/multipart.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/multipart.js new file mode 100644 index 0000000..a476169 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/fixture/multipart.js @@ -0,0 +1,72 @@ +exports['rfc1867'] = + { boundary: 'AaB03x', + raw: + '--AaB03x\r\n'+ + 'content-disposition: form-data; name="field1"\r\n'+ + '\r\n'+ + 'Joe Blow\r\nalmost tricked you!\r\n'+ + '--AaB03x\r\n'+ + 'content-disposition: form-data; name="pics"; filename="file1.txt"\r\n'+ + 'Content-Type: text/plain\r\n'+ + '\r\n'+ + '... contents of file1.txt ...\r\r\n'+ + '--AaB03x--\r\n', + parts: + [ { headers: { + 'content-disposition': 'form-data; name="field1"', + }, + data: 'Joe Blow\r\nalmost tricked you!', + }, + { headers: { + 'content-disposition': 'form-data; name="pics"; filename="file1.txt"', + 'Content-Type': 'text/plain', + }, + data: '... contents of file1.txt ...\r', + } + ] + }; + +exports['noTrailing\r\n'] = + { boundary: 'AaB03x', + raw: + '--AaB03x\r\n'+ + 'content-disposition: form-data; name="field1"\r\n'+ + '\r\n'+ + 'Joe Blow\r\nalmost tricked you!\r\n'+ + '--AaB03x\r\n'+ + 'content-disposition: form-data; name="pics"; filename="file1.txt"\r\n'+ + 'Content-Type: text/plain\r\n'+ + '\r\n'+ + '... contents of file1.txt ...\r\r\n'+ + '--AaB03x--', + parts: + [ { headers: { + 'content-disposition': 'form-data; name="field1"', + }, + data: 'Joe Blow\r\nalmost tricked you!', + }, + { headers: { + 'content-disposition': 'form-data; name="pics"; filename="file1.txt"', + 'Content-Type': 'text/plain', + }, + data: '... contents of file1.txt ...\r', + } + ] + }; + +exports['emptyHeader'] = + { boundary: 'AaB03x', + raw: + '--AaB03x\r\n'+ + 'content-disposition: form-data; name="field1"\r\n'+ + ': foo\r\n'+ + '\r\n'+ + 'Joe Blow\r\nalmost tricked you!\r\n'+ + '--AaB03x\r\n'+ + 'content-disposition: form-data; name="pics"; filename="file1.txt"\r\n'+ + 'Content-Type: text/plain\r\n'+ + '\r\n'+ + '... contents of file1.txt ...\r\r\n'+ + '--AaB03x--\r\n', + expectError: true, + }; diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/record.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/record.js new file mode 100644 index 0000000..9f1cef8 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/record.js @@ -0,0 +1,47 @@ +var http = require('http'); +var fs = require('fs'); +var connections = 0; + +var server = http.createServer(function(req, res) { + var socket = req.socket; + console.log('Request: %s %s -> %s', req.method, req.url, socket.filename); + + req.on('end', function() { + if (req.url !== '/') { + res.end(JSON.stringify({ + method: req.method, + url: req.url, + filename: socket.filename, + })); + return; + } + + res.writeHead(200, {'content-type': 'text/html'}); + res.end( + '
    '+ + '
    '+ + '
    '+ + ''+ + '
    ' + ); + }); +}); + +server.on('connection', function(socket) { + connections++; + + socket.id = connections; + socket.filename = 'connection-' + socket.id + '.http'; + socket.file = fs.createWriteStream(socket.filename); + socket.pipe(socket.file); + + console.log('--> %s', socket.filename); + socket.on('close', function() { + console.log('<-- %s', socket.filename); + }); +}); + +var port = process.env.PORT || 8080; +server.listen(port, function() { + console.log('Recording connections on port %s', port); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-connection-aborted.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-connection-aborted.js new file mode 100644 index 0000000..bd83e1d --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-connection-aborted.js @@ -0,0 +1,27 @@ +var assert = require('assert'); +var http = require('http'); +var net = require('net'); +var multiparty = require('../../'); + +var server = http.createServer(function (req, res) { + var form = new multiparty.Form(); + var aborted_received = false; + form.on('aborted', function () { + aborted_received = true; + }); + form.on('error', function () { + assert(aborted_received, 'Error event should follow aborted'); + server.close(); + }); + form.on('end', function () { + throw new Error('Unexpected "end" event'); + }); + form.parse(req); +}).listen(0, 'localhost', function () { + var client = net.connect(server.address().port); + client.write( + "POST / HTTP/1.1\r\n" + + "Content-Length: 70\r\n" + + "Content-Type: multipart/form-data; boundary=foo\r\n\r\n"); + client.end(); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-content-transfer-encoding.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-content-transfer-encoding.js new file mode 100644 index 0000000..35e5a1f --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-content-transfer-encoding.js @@ -0,0 +1,52 @@ +var assert = require('assert') + , multiparty = require('../../') + , http = require('http') + , path = require('path') + , TMP_PATH = path.join(__dirname, '..', 'tmp') + +var server = http.createServer(function(req, res) { + var form = new multiparty.Form(); + form.uploadDir = TMP_PATH; + form.on('close', function () { + throw new Error('Unexpected "close" event'); + }); + form.on('end', function () { + throw new Error('Unexpected "end" event'); + }); + form.on('error', function (e) { + res.writeHead(500); + res.end(e.message); + }); + form.parse(req); +}); + +server.listen(0, function() { + var body = + '--foo\r\n' + + 'Content-Disposition: form-data; name="file1"; filename="file1"\r\n' + + 'Content-Type: application/octet-stream\r\n' + + '\r\nThis is the first file\r\n' + + '--foo\r\n' + + 'Content-Type: application/octet-stream\r\n' + + 'Content-Disposition: form-data; name="file2"; filename="file2"\r\n' + + 'Content-Transfer-Encoding: unknown\r\n' + + '\r\nThis is the second file\r\n' + + '--foo--\r\n'; + + var req = http.request({ + method: 'POST', + port: server.address().port, + headers: { + 'Content-Length': body.length, + 'Content-Type': 'multipart/form-data; boundary=foo' + } + }); + req.on('response', function (res) { + assert.equal(res.statusCode, 500); + res.on('data', function () {}); + res.on('end', function () { + server.close(); + }); + }); + req.end(body); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-invalid.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-invalid.js new file mode 100644 index 0000000..ede541d --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-invalid.js @@ -0,0 +1,35 @@ +var superagent = require('superagent') + , multiparty = require('../../') + , http = require('http') + +var server = http.createServer(function(req, resp) { + var form = new multiparty.Form(); + + var errCount = 0; + form.on('error', function(err) { + errCount += 1; + resp.end(); + }); + form.on('file', function(name, file) { + }); + form.on('field', function(name, file) { + }); + + form.parse(req); +}); +server.listen(function() { + var url = 'http://localhost:' + server.address().port + '/' + var req = superagent.post(url) + req.set('Content-Type', 'multipart/form-data; boundary=foo') + req.write('--foo\r\n') + req.write('Content-filename="foo.txt"\r\n') + req.write('\r\n') + req.write('some text here') + req.write('Content-Disposition: form-data; name="text"; filename="bar.txt"\r\n') + req.write('\r\n') + req.write('some more text stuff') + req.write('\r\n--foo--') + req.end(function(err, resp) { + server.close(); + }); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-15.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-15.js new file mode 100644 index 0000000..43982fa --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-15.js @@ -0,0 +1,88 @@ +var http = require('http') + , multiparty = require('../../') + , assert = require('assert') + , superagent = require('superagent') + , path = require('path') + +var server = http.createServer(function(req, res) { + assert.strictEqual(req.url, '/upload'); + assert.strictEqual(req.method, 'POST'); + + var form = new multiparty.Form({autoFields:true,autoFiles:true}); + + form.on('error', function(err) { + console.log(err); + }); + + form.on('close', function() { + }); + + var fileCount = 0; + form.on('file', function(name, file) { + fileCount += 1; + }); + + form.parse(req, function(err, fields, files) { + var objFileCount = 0; + for (var file in files) { + objFileCount += 1; + } + // multiparty does NOT try to do intelligent things based on + // the part name. + assert.strictEqual(fileCount, 2); + assert.strictEqual(objFileCount, 1); + res.end(); + }); +}); +server.listen(function() { + var url = 'http://localhost:' + server.address().port + '/upload'; + var req = superagent.post(url); + req.attach('files[]', fixture('pf1y5.png'), 'SOG2.JPG'); + req.attach('files[]', fixture('binaryfile.tar.gz'), 'BenF364_LIB353.zip'); + + // Get the existing boundary. + var contentType = req.get('content-type'); + var split = contentType.split(' '); + + // Set the content-type. + req.set('content-type', split.join('')); + + req.end(function(err, resp) { + assert.ifError(err); + resp.on('end', function() { + server.close(); + }); + }); + + // No space. + createRequest(''); + + // Single space. + createRequest(' '); + + // Multiple spaces. + createRequest(' '); +}); + +function createRequest(separator) { + var url = 'http://localhost:' + server.address().port + '/upload'; + var req = superagent.post(url); + req.attach('files[]', fixture('pf1y5.png'), 'SOG2.JPG'); + req.attach('files[]', fixture('binaryfile.tar.gz'), 'BenF364_LIB353.zip'); + + // Get the existing boundary. + var contentType = req.get('content-type'); + var split = contentType.split(' '); + + // Set the content-type. + req.set('content-type', split.join(separator)); + + req.end(function(err, resp) { + assert.ifError(err); + // We don't close the server, to allow other requests to pass. + }); +} + +function fixture(name) { + return path.join(__dirname, '..', 'fixture', 'file', name) +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-19.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-19.js new file mode 100644 index 0000000..d7da0cf --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-19.js @@ -0,0 +1,44 @@ +var assert = require('assert'); +var http = require('http'); +var net = require('net'); +var multiparty = require('../../'); + +var client; +var server = http.createServer(function (req, res) { + var form = new multiparty.Form({maxFields: 1}); + form.on('aborted', function () { + throw new Error("did not expect aborted"); + }); + var first = true; + form.on('error', function (err) { + assert.ok(first); + first = false; + client.end(); + assert.ok(/maxFields/.test(err.message)); + server.close(); + }); + form.on('end', function () { + throw new Error('Unexpected "end" event'); + }); + form.parse(req); +}); +server.listen(function() { + client = net.connect(server.address().port); + + client.write("POST /upload HTTP/1.1\r\n" + + "Content-Length: 728\r\n" + + "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryvfUZhxgsZDO7FXLF\r\n" + + "\r\n" + + "------WebKitFormBoundaryvfUZhxgsZDO7FXLF\r\n" + + "Content-Disposition: form-data; name=\"title\"\r\n" + + "\r\n" + + "foofoo" + + "\r\n" + + "------WebKitFormBoundaryvfUZhxgsZDO7FXLF\r\n" + + "Content-Disposition: form-data; name=\"upload\"; filename=\"blah1.txt\"\r\n" + + "Content-Type: text/plain\r\n" + + "\r\n" + + "hi1\r\n" + + "\r\n" + + "------WebKitFormBoundaryvfUZhxgsZDO7FXLF\r\n"); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-21.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-21.js new file mode 100644 index 0000000..155fba0 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-21.js @@ -0,0 +1,66 @@ +var assert = require('assert'); +var http = require('http'); +var net = require('net'); +var multiparty = require('../../'); + +var client; +var server = http.createServer(function(req, res) { + var form = new multiparty.Form(); + + form.parse(req, function(err, fieldsTable, filesTable, fieldsList, filesList) { + if (err) { + console.error(err.stack); + return; + } + assert.strictEqual(fieldsList.length, 1); + assert.strictEqual(fieldsList[0].name, "title"); + assert.strictEqual(fieldsList[0].value, "foofoo"); + assert.strictEqual(filesList.length, 4); + assert.strictEqual(filesList[0].fieldName, "upload"); + assert.strictEqual(filesList[1].fieldName, "upload"); + assert.strictEqual(filesList[2].fieldName, "upload"); + assert.strictEqual(filesList[3].fieldName, "upload"); + res.end(); + client.end(); + server.close(); + }); +}); +server.listen(function() { + client = net.connect(server.address().port); + + client.write("POST /upload HTTP/1.1\r\n" + + "Content-Length: 728\r\n" + + "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryvfUZhxgsZDO7FXLF\r\n" + + "\r\n" + + "------WebKitFormBoundaryvfUZhxgsZDO7FXLF\r\n" + + "Content-Disposition: form-data; name=\"title\"\r\n" + + "\r\n" + + "foofoo" + + "\r\n" + + "------WebKitFormBoundaryvfUZhxgsZDO7FXLF\r\n" + + "Content-Disposition: form-data; name=\"upload\"; filename=\"blah1.txt\"\r\n" + + "Content-Type: text/plain\r\n" + + "\r\n" + + "hi1\r\n" + + "\r\n" + + "------WebKitFormBoundaryvfUZhxgsZDO7FXLF\r\n" + + "Content-Disposition: form-data; name=\"upload\"; filename=\"blah2.txt\"\r\n" + + "Content-Type: text/plain\r\n" + + "\r\n" + + "hi2\r\n" + + "\r\n" + + "------WebKitFormBoundaryvfUZhxgsZDO7FXLF\r\n" + + "Content-Disposition: form-data; name=\"upload\"; filename=\"blah3.txt\"\r\n" + + "Content-Type: text/plain\r\n" + + "\r\n" + + "hi3\r\n" + + "\r\n" + + "------WebKitFormBoundaryvfUZhxgsZDO7FXLF\r\n" + + "Content-Disposition: form-data; name=\"upload\"; filename=\"blah4.txt\"\r\n" + + "Content-Type: text/plain\r\n" + + "\r\n" + + "hi4\r\n" + + "\r\n" + + "------WebKitFormBoundaryvfUZhxgsZDO7FXLF--\r\n" + ); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-4.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-4.js new file mode 100644 index 0000000..66b2a69 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-4.js @@ -0,0 +1,51 @@ +var http = require('http') + , multiparty = require('../../') + , assert = require('assert') + , superagent = require('superagent') + , path = require('path') + +var server = http.createServer(function(req, res) { + assert.strictEqual(req.url, '/upload'); + assert.strictEqual(req.method, 'POST'); + + var form = new multiparty.Form({autoFields:true,autoFiles:true}); + + form.on('error', function(err) { + console.log(err); + }); + + form.on('close', function() { + }); + + var fileCount = 0; + form.on('file', function(name, file) { + fileCount += 1; + }); + + form.parse(req, function(err, fields, files) { + var objFileCount = 0; + for (var file in files) { + objFileCount += 1; + } + // multiparty does NOT try to do intelligent things based on + // the part name. + assert.strictEqual(fileCount, 2); + assert.strictEqual(objFileCount, 1); + res.end(); + }); +}); +server.listen(function() { + var url = 'http://localhost:' + server.address().port + '/upload'; + var req = superagent.post(url); + req.attach('files[]', fixture('pf1y5.png'), 'SOG2.JPG'); + req.attach('files[]', fixture('binaryfile.tar.gz'), 'BenF364_LIB353.zip'); + req.end(function(err, resp) { + assert.ifError(err); + resp.on('end', function() { + server.close(); + }); + }); +}); +function fixture(name) { + return path.join(__dirname, '..', 'fixture', 'file', name) +} diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-46.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-46.js new file mode 100644 index 0000000..676b870 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-46.js @@ -0,0 +1,49 @@ +var http = require('http'), + multiparty = require('../../'), + request = require('request'), + assert = require('assert'); + +var host = 'localhost'; + +var index = [ + '
    ', + ' ', + ' ', + '
    ' +].join("\n"); + +var server = http.createServer(function(req, res) { + + // Show a form for testing purposes. + if (req.method === 'GET') { + res.writeHead(200, {'content-type': 'text/html'}); + res.end(index); + return; + } + + // Parse form and write results to response. + var form = new multiparty.Form(); + form.parse(req, function(err, fields, files) { + res.writeHead(200, {'content-type': 'text/plain'}); + res.write(JSON.stringify({err: err, fields: fields, files: files})); + res.end(); + }); + +}).listen(0, host, function() { + + //console.log("Server up and running..."); + + var server = this, + url = 'http://' + host + ':' + server.address().port; + + var parts = [ + {'Content-Disposition': 'form-data; name="foo"', 'body': 'bar'} + ] + + var req = request({method: 'POST', url: url, multipart: parts}, function(e, res, body) { + var obj = JSON.parse(body); + assert.equal("bar", obj.fields.foo); + server.close(); + }); + +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-5.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-5.js new file mode 100644 index 0000000..80eadf2 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/standalone/test-issue-5.js @@ -0,0 +1,39 @@ +var assert = require('assert'); +var http = require('http'); +var net = require('net'); +var multiparty = require('../../'); + +var client; +var attachmentCount = 510; +var server = http.createServer(function(req, res) { + var form = new multiparty.Form({maxFields: 10000}); + + form.parse(req, function(err, fieldsTable, filesTable, fieldsList, filesList) { + assert.strictEqual(err.code, "EMFILE"); + res.end(); + client.end(); + server.close(); + }); +}); +server.listen(function() { + client = net.connect(server.address().port); + + var boundary = "------WebKitFormBoundaryvfUZhxgsZDO7FXLF\r\n"; + var oneAttachment = boundary + + "Content-Disposition: form-data; name=\"upload\"; filename=\"blah1.txt\"\r\n" + + "Content-Type: text/plain\r\n" + + "\r\n" + + "hi1\r\n" + + "\r\n"; + var payloadSize = oneAttachment.length * attachmentCount + boundary.length; + + client.write("POST /upload HTTP/1.1\r\n" + + "Content-Length: " + payloadSize + "\r\n" + + "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryvfUZhxgsZDO7FXLF\r\n" + + "\r\n"); + + for (var i = 0; i < attachmentCount; i += 1) { + client.write(oneAttachment); + } + client.write(boundary); +}); diff --git a/node_modules/express/node_modules/connect/node_modules/multiparty/test/test.js b/node_modules/express/node_modules/connect/node_modules/multiparty/test/test.js new file mode 100644 index 0000000..199d5cd --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/multiparty/test/test.js @@ -0,0 +1,117 @@ +var spawn = require('child_process').spawn + , findit = require('findit') + , path = require('path') + , hashish = require('hashish') + , fs = require('fs') + , http = require('http') + , net = require('net') + , assert = require('assert') + , multiparty = require('../') + , mkdirp = require('mkdirp') + , STANDALONE_PATH = path.join(__dirname, 'standalone') + , server = http.createServer() + , PORT = 13532 + , FIXTURE_PATH = path.join(__dirname, 'fixture') + , TMP_PATH = path.join(__dirname, 'tmp') + +mkdirp.sync(TMP_PATH); + +describe("fixtures", function() { + before(function(done) { + server.listen(PORT, done); + }); + var fixtures = []; + findit + .sync(path.join(FIXTURE_PATH, 'js')) + .forEach(function(jsPath) { + if (!/\.js$/.test(jsPath)) return; + var group = path.basename(jsPath, '.js'); + hashish.forEach(require(jsPath), function(fixture, name) { + it(group + '/' + name, createTest({ + name : group + '/' + name, + fixture : fixture, + })); + }); + }); +}); + +describe("standalone", function() { + findit + .sync(STANDALONE_PATH) + .forEach(function(jsPath) { + if (!/\.js$/.test(jsPath)) return; + it(path.basename(jsPath, '.js'), function(done) { + var child = spawn(process.execPath, [jsPath], { stdio: 'inherit' }); + child.on('error', function(err) { + done(err); + }); + child.on('exit', function(code) { + if (code) return done(new Error("exited with code " + code)); + done(); + }); + }); + }); +}); + +function createTest(fixture) { + var name = fixture.name; + fixture = fixture.fixture; + return function(done) { + uploadFixture(name, function(err, parts) { + if (err) return done(err); + fixture.forEach(function(expectedPart, i) { + var parsedPart = parts[i]; + assert.equal(parsedPart.type, expectedPart.type); + assert.equal(parsedPart.name, expectedPart.name); + + if (parsedPart.type === 'file') { + var file = parsedPart.value; + assert.equal(file.originalFilename, expectedPart.filename); + if(expectedPart.sha1) assert.strictEqual(file.hash, expectedPart.sha1); + if(expectedPart.size) assert.strictEqual(file.size, expectedPart.size); + } + }); + done(); + }); + }; + +} + +function uploadFixture(name, cb) { + server.once('request', function(req, res) { + var parts = []; + var form = new multiparty.Form({ + autoFields: true, + autoFiles: true, + }); + form.uploadDir = TMP_PATH; + form.hash = "sha1"; + + form.on('error', callback); + form.on('file', function(name, value) { + parts.push({type: 'file', name: name, value: value}); + }); + form.on('field', function(name, value) { + parts.push({type: 'field', name: name, value: value}); + }); + form.on('close', function() { + res.end('OK'); + callback(null, parts); + }); + form.parse(req); + + function callback() { + var realCallback = cb; + cb = function() {}; + realCallback.apply(null, arguments); + } + }); + + var socket = net.createConnection(PORT); + var file = fs.createReadStream(FIXTURE_PATH + '/http/' + name); + + file.pipe(socket, {end: false}); + socket.on('data', function () { + socket.end(); + }); +} diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/LICENSE b/node_modules/express/node_modules/connect/node_modules/negotiator/LICENSE new file mode 100644 index 0000000..42ca2e7 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/LICENSE @@ -0,0 +1,27 @@ +Original "Negotiator" program Copyright Federico Romero +Port to JavaScript Copyright Isaac Z. Schlueter + +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/examples/accept.js b/node_modules/express/node_modules/connect/node_modules/negotiator/examples/accept.js new file mode 100644 index 0000000..2a18039 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/examples/accept.js @@ -0,0 +1,47 @@ +(function() { + var Negotiator, availableMediaTypes, http, key, representations, server, val; + + Negotiator = require('../lib/negotiator').Negotiator; + + http = require('http'); + + representations = { + 'text/html': '

    Hello world!

    ', + 'text/plain': 'Hello World!', + 'application/json': JSON.stringify({ + hello: 'world!' + }) + }; + + availableMediaTypes = (function() { + var _results; + _results = []; + for (key in representations) { + val = representations[key]; + _results.push(key); + } + return _results; + })(); + + server = http.createServer(function(req, res) { + var mediaType, negotiator; + negotiator = new Negotiator(req); + console.log("Accept: " + req.headers['accept']); + console.log("Preferred: " + (negotiator.preferredMediaTypes())); + console.log("Possible: " + (negotiator.preferredMediaTypes(availableMediaTypes))); + mediaType = negotiator.preferredMediaType(availableMediaTypes); + console.log("Selected: " + mediaType); + if (mediaType) { + res.writeHead(200, { + 'Content-Type': mediaType + }); + return res.end(representations[mediaType]); + } else { + res.writeHead(406); + return res.end(); + } + }); + + server.listen(8080); + +}).call(this); diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/examples/charset.js b/node_modules/express/node_modules/connect/node_modules/negotiator/examples/charset.js new file mode 100644 index 0000000..6455eff --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/examples/charset.js @@ -0,0 +1,52 @@ +(function() { + var Buffer, Iconv, Negotiator, availableCharsets, http, iconv, key, message, messages, server, val; + + Negotiator = require('../lib/negotiator').Negotiator; + + http = require('http'); + + Buffer = require('buffer').Buffer; + + Iconv = require('iconv').Iconv; + + iconv = new Iconv('UTF-8', 'ISO-8859-1'); + + message = "ë"; + + messages = { + 'utf-8': message, + 'iso-8859-1': iconv.convert(new Buffer(message)) + }; + + availableCharsets = (function() { + var _results; + _results = []; + for (key in messages) { + val = messages[key]; + _results.push(key); + } + return _results; + })(); + + server = http.createServer(function(req, res) { + var charset, negotiator; + negotiator = new Negotiator(req); + console.log("Accept-Charset: " + req.headers['accept-charset']); + console.log("Preferred: " + (negotiator.preferredCharsets())); + console.log("Possible: " + (negotiator.preferredCharsets(availableCharsets))); + charset = negotiator.preferredCharset(availableCharsets); + console.log("Selected: " + charset); + if (charset) { + res.writeHead(200, { + 'Content-Type': "text/html; charset=" + charset + }); + return res.end(messages[charset]); + } else { + res.writeHead(406); + return res.end(); + } + }); + + server.listen(8080); + +}).call(this); diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/examples/encoding.js b/node_modules/express/node_modules/connect/node_modules/negotiator/examples/encoding.js new file mode 100644 index 0000000..a02d0f4 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/examples/encoding.js @@ -0,0 +1,48 @@ +(function() { + var Negotiator, gbuf, http, messages; + + Negotiator = require('../lib/negotiator').Negotiator; + + http = require('http'); + + gbuf = require('gzip-buffer'); + + messages = { + identity: 'Hello World' + }; + + gbuf.gzip(messages.identity, function(zipped) { + var availableEncodings, key, server, val; + messages.gzip = zipped; + availableEncodings = (function() { + var _results; + _results = []; + for (key in messages) { + val = messages[key]; + _results.push(key); + } + return _results; + })(); + console.log(availableEncodings); + server = http.createServer(function(req, res) { + var encoding, negotiator; + negotiator = new Negotiator(req); + console.log("Accept-Encoding: " + req.headers['accept-encoding']); + console.log("Preferred: " + (negotiator.preferredEncodings())); + console.log("Possible: " + (negotiator.preferredEncodings(availableEncodings))); + encoding = negotiator.preferredEncoding(availableEncodings); + console.log("Selected: " + encoding); + if (encoding) { + res.writeHead(200, { + 'Content-Encoding': encoding + }); + return res.end(messages[encoding]); + } else { + res.writeHead(406); + return res.end(); + } + }); + return server.listen(8080); + }); + +}).call(this); diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/examples/language.js b/node_modules/express/node_modules/connect/node_modules/negotiator/examples/language.js new file mode 100644 index 0000000..f161743 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/examples/language.js @@ -0,0 +1,44 @@ +(function() { + var Negotiator, availableLanguages, http, key, messages, server, val; + + Negotiator = require('../lib/negotiator').Negotiator; + + http = require('http'); + + messages = { + es: "¡Hola Mundo!", + en: "Hello World!" + }; + + availableLanguages = (function() { + var _results; + _results = []; + for (key in messages) { + val = messages[key]; + _results.push(key); + } + return _results; + })(); + + server = http.createServer(function(req, res) { + var language, negotiator; + negotiator = new Negotiator(req); + console.log("Accept-Language: " + req.headers['accept-language']); + console.log("Preferred: " + (negotiator.preferredLanguages())); + console.log("Possible: " + (negotiator.preferredLanguages(availableLanguages))); + language = negotiator.preferredLanguage(availableLanguages); + console.log("Selected: " + language); + if (language) { + res.writeHead(200, { + 'Content-Language': language + }); + return res.end(messages[language]); + } else { + res.writeHead(406); + return res.end(); + } + }); + + server.listen(8080); + +}).call(this); diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/lib/charset.js b/node_modules/express/node_modules/connect/node_modules/negotiator/lib/charset.js new file mode 100644 index 0000000..3300457 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/lib/charset.js @@ -0,0 +1,71 @@ +module.exports = preferredCharsets; +preferredCharsets.preferredCharsets = preferredCharsets; + +function parseAcceptCharset(accept) { + return accept.split(',').map(function(e) { + return parseCharset(e.trim()); + }).filter(function(e) { + return e && e.q > 0; + }); +} + +function parseCharset(s) { + var match = s.match(/^\s*(\S+?)\s*(?:;(.*))?$/); + if (!match) return null; + + var charset = match[1]; + var q = 1; + if (match[2]) { + var params = match[2].split(';') + for (var i = 0; i < params.length; i ++) { + var p = params[i].trim().split('='); + if (p[0] === 'q') { + q = parseFloat(p[1]); + break; + } + } + } + + return { + charset: charset, + q: q + }; +} + +function getCharsetPriority(charset, accepted) { + return (accepted.filter(function(a) { + return specify(charset, a); + }).sort(function (a, b) { + // revsort + return a.q === b.q ? 0 : a.q > b.q ? -1 : 1; + })[0] || {q:0}).q; +} + +function specify(charset, spec) { + if (spec.charset === '*' || spec.charset === charset) { + return spec; + } +}; + +function preferredCharsets(accept, provided) { + accept = parseAcceptCharset(accept || ''); + if (provided) { + return provided.map(function(type) { + return [type, getCharsetPriority(type, accept)]; + }).filter(function(pair) { + return pair[1] > 0; + }).sort(function(a, b) { + // revsort + return a[1] === b[1] ? 0 : a[1] > b[1] ? -1 : 1; + }).map(function(pair) { + return pair[0]; + }); + } else { + return accept.sort(function (a, b) { + // revsort + return a.q < b.q ? 1 : -1; + }).map(function(type) { + return type.charset; + }); + } +} diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/lib/encoding.js b/node_modules/express/node_modules/connect/node_modules/negotiator/lib/encoding.js new file mode 100644 index 0000000..b4fc889 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/lib/encoding.js @@ -0,0 +1,89 @@ +module.exports = preferredEncodings; +preferredEncodings.preferredEncodings = preferredEncodings; + +function parseAcceptEncoding(accept) { + var acceptableEncodings; + + if (accept) { + acceptableEncodings = accept.split(',').map(function(e) { + return parseEncoding(e.trim()); + }); + } else { + acceptableEncodings = []; + } + + if (!acceptableEncodings.some(function(e) { + return e && e.encoding === 'identity'; + })) { + acceptableEncodings.push({ + encoding: 'identity', + q: 0.1 + }); + } + + return acceptableEncodings.filter(function(e) { + return e && e.q > 0; + }); +} + +function parseEncoding(s) { + var match = s.match(/^\s*(\S+?)\s*(?:;(.*))?$/); + + if (!match) return null; + + var encoding = match[1]; + var q = 1; + if (match[2]) { + var params = match[2].split(';'); + for (var i = 0; i < params.length; i ++) { + var p = params[i].trim().split('='); + if (p[0] === 'q') { + q = parseFloat(p[1]); + break; + } + } + } + + return { + encoding: encoding, + q: q + }; +} + +function getEncodingPriority(encoding, accepted) { + return (accepted.filter(function(a) { + return specify(encoding, a); + }).sort(function (a, b) { + // revsort + return a.q === b.q ? 0 : a.q > b.q ? -1 : 1; + })[0] || {q:0}).q; +} + +function specify(encoding, spec) { + if (spec.encoding === '*' || spec.encoding === encoding) { + return spec; + } +} + +function preferredEncodings(accept, provided) { + accept = parseAcceptEncoding(accept || ''); + if (provided) { + return provided.map(function(type) { + return [type, getEncodingPriority(type, accept)]; + }).filter(function(pair) { + return pair[1] > 0; + }).sort(function(a, b) { + // revsort + return a[1] === b[1] ? 0 : a[1] > b[1] ? -1 : 1; + }).map(function(pair) { + return pair[0]; + }); + } else { + return accept.sort(function (a, b) { + // revsort + return a.q < b.q ? 1 : -1; + }).map(function(type) { + return type.encoding; + }); + } +} diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/lib/language.js b/node_modules/express/node_modules/connect/node_modules/negotiator/lib/language.js new file mode 100644 index 0000000..432b702 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/lib/language.js @@ -0,0 +1,92 @@ +module.exports = preferredLanguages; +preferredLanguages.preferredLanguages = preferredLanguages; + +function parseAcceptLanguage(accept) { + return accept.split(',').map(function(e) { + return parseLanguage(e.trim()); + }).filter(function(e) { + return e && e.q > 0; + }); +} + +function parseLanguage(s) { + var match = s.match(/^\s*(\S+?)(?:-(\S+?))?\s*(?:;(.*))?$/); + if (!match) return null; + + var prefix = match[1], + suffix = match[2], + full = prefix; + + if (suffix) full += "-" + suffix; + + var q = 1; + if (match[3]) { + var params = match[3].split(';') + for (var i = 0; i < params.length; i ++) { + var p = params[i].split('='); + if (p[0] === 'q') q = parseFloat(p[1]); + } + } + + return { + prefix: prefix, + suffix: suffix, + q: q, + full: full + }; +} + +function getLanguagePriority(language, accepted) { + var match = getClosestMatch(language, accepted); + return match ? match.q : 0; +} + +function getClosestMatch(language, accepted) { + var parsed = parseLanguage(language); + + var matches = accepted.filter(function(a) { + return a.full === parsed.full; + }); + if (matches.length) return matches[0]; + + matches = accepted.filter(function(a) { + return a.prefix === parsed.prefix && !a.suffix; + }); + if (matches.length) return matches[0]; + + matches = accepted.filter(function(a) { + return a.prefix === parsed.prefix; + }); + if (matches.length) return matches[0]; + + matches = accepted.filter(function(a) { + return a.prefix === '*'; + }); + return matches[0]; +} + +function preferredLanguages(accept, provided) { + accept = parseAcceptLanguage(accept || ''); + if (provided) { + + var ret = provided.map(function(type) { + return [type, getLanguagePriority(type, accept)]; + }).filter(function(pair) { + return pair[1] > 0; + }).sort(function(a, b) { + // revsort + return a[1] === b[1] ? 0 : a[1] > b[1] ? -1 : 1; + }).map(function(pair) { + return pair[0]; + }); + return ret; + + } else { + return accept.sort(function (a, b) { + // revsort + return a.q < b.q ? 1 : -1; + }).map(function(type) { + return type.full; + }); + } +} diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/lib/mediaType.js b/node_modules/express/node_modules/connect/node_modules/negotiator/lib/mediaType.js new file mode 100644 index 0000000..3dc017f --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/lib/mediaType.js @@ -0,0 +1,101 @@ +module.exports = preferredMediaTypes; +preferredMediaTypes.preferredMediaTypes = preferredMediaTypes; + +function parseAccept(accept) { + return accept.split(',').map(function(e) { + return parseMediaType(e.trim()); + }).filter(function(e) { + return e && e.q > 0; + }); +}; + +function parseMediaType(s) { + var match = s.match(/\s*(\S+)\/([^;\s]+)\s*(?:;(.*))?/); + if (!match) return null; + + var type = match[1], + subtype = match[2], + full = "" + type + "/" + subtype, + params = {}, + q = 1; + + if (match[3]) { + params = match[3].split(';').map(function(s) { + return s.trim().split('='); + }).reduce(function (set, p) { + set[p[0]] = p[1]; + return set + }, params); + + if (params.q != null) { + q = parseFloat(params.q); + delete params.q; + } + } + + return { + type: type, + subtype: subtype, + params: params, + q: q, + full: full + }; +} + +function getMediaTypePriority(type, accepted) { + return (accepted.filter(function(a) { + return specify(type, a); + }).sort(function (a, b) { + // revsort + return a.q > b.q ? -1 : 1; + })[0] || {q:0}).q; +} + +function specifies(spec, type) { + return spec === '*' || spec === type; +} + +function specify(type, spec) { + var p = parseMediaType(type); + + if (spec.params) { + var keys = Object.keys(spec.params); + if (keys.some(function (k) { + return !specifies(spec.params[k], p.params[k]); + })) { + // some didn't specify. + return null; + } + } + + if (specifies(spec.type, p.type) && + specifies(spec.subtype, p.subtype)) { + return spec; + } +} + +function preferredMediaTypes(accept, provided) { + accept = parseAccept(accept || ''); + if (provided) { + return provided.map(function(type) { + return [type, getMediaTypePriority(type, accept)]; + }).filter(function(pair) { + return pair[1] > 0; + }).sort(function(a, b) { + // revsort + return a[1] === b[1] ? 0 : a[1] > b[1] ? -1 : 1; + }).map(function(pair) { + return pair[0]; + }); + + } else { + return accept.sort(function (a, b) { + // revsort + return a.q < b.q ? 1 : -1; + }).map(function(type) { + return type.full; + }); + } +} + + diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/lib/negotiator.js b/node_modules/express/node_modules/connect/node_modules/negotiator/lib/negotiator.js new file mode 100644 index 0000000..fe0e58a --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/lib/negotiator.js @@ -0,0 +1,29 @@ +module.exports = Negotiator; +Negotiator.Negotiator = Negotiator; + +function Negotiator(request) { + if (!(this instanceof Negotiator)) return new Negotiator(request); + this.request = request; +} + +var set = { preferredCharset: [require('./charset.js'), 'accept-charset'], + preferredEncoding: [require('./encoding.js'), 'accept-encoding'], + preferredLanguage: [require('./language.js'), 'accept-language'], + preferredMediaType: [require('./mediaType.js'), 'accept'] }; + +Object.keys(set).forEach(function (k) { + var mh = set[k], + method = mh[0], + header = mh[1], + singular = k, + plural = k + 's'; + + Negotiator.prototype[plural] = function (available) { + return method(this.request.headers[header], available); + }; + + Negotiator.prototype[singular] = function(available) { + var set = this[plural](available); + if (set) return set[0]; + }; +}) diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/package.json b/node_modules/express/node_modules/connect/node_modules/negotiator/package.json new file mode 100644 index 0000000..471794a --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/package.json @@ -0,0 +1,53 @@ +{ + "name": "negotiator", + "description": "HTTP content negotiation", + "version": "0.3.0", + "author": { + "name": "Federico Romero", + "email": "federico.romero@outboxlabs.com" + }, + "contributors": [ + { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me/" + } + ], + "repository": { + "type": "git", + "url": "git://github.com/federomero/negotiator.git" + }, + "keywords": [ + "http", + "content negotiation", + "accept", + "accept-language", + "accept-encoding", + "accept-charset" + ], + "engine": "node >= 0.6", + "license": "MIT", + "devDependencies": { + "nodeunit": "0.6.x" + }, + "scripts": { + "test": "nodeunit test" + }, + "optionalDependencies": {}, + "engines": { + "node": "*" + }, + "main": "lib/negotiator.js", + "readme": "# Negotiator\n\nAn HTTP content negotiator for node.js written in javascript.\n\n# Accept Negotiation\n\n Negotiator = require('negotiator')\n\n availableMediaTypes = ['text/html', 'text/plain', 'application/json']\n\n // The negotiator constructor receives a request object\n negotiator = new Negotiator(request)\n\n // Let's say Accept header is 'text/html, application/*;q=0.2, image/jpeg;q=0.8'\n\n negotiator.preferredMediaTypes()\n // -> ['text/html', 'image/jpeg', 'application/*']\n\n negotiator.preferredMediaTypes(availableMediaTypes)\n // -> ['text/html', 'application/json']\n\n negotiator.preferredMediaType(availableMediaTypes)\n // -> 'text/html'\n\nYou can check a working example at `examples/accept.js`.\n\n## Methods\n\n`preferredMediaTypes(availableMediaTypes)`:\n\nReturns an array of preferred media types ordered by priority from a list of available media types.\n\n`preferredMediaType(availableMediaType)`:\n\nReturns the top preferred media type from a list of available media types.\n\n# Accept-Language Negotiation\n\n Negotiator = require('negotiator')\n\n negotiator = new Negotiator(request)\n\n availableLanguages = 'en', 'es', 'fr'\n\n // Let's say Accept-Language header is 'en;q=0.8, es, pt'\n\n negotiator.preferredLanguages()\n // -> ['es', 'pt', 'en']\n\n negotiator.preferredLanguages(availableLanguages)\n // -> ['es', 'en']\n\n language = negotiator.preferredLanguage(availableLanguages)\n // -> 'es'\n\nYou can check a working example at `examples/language.js`.\n\n## Methods\n\n`preferredLanguages(availableLanguages)`:\n\nReturns an array of preferred languages ordered by priority from a list of available languages.\n\n`preferredLanguage(availableLanguages)`:\n\nReturns the top preferred language from a list of available languages.\n\n# Accept-Charset Negotiation\n\n Negotiator = require('negotiator')\n\n availableCharsets = ['utf-8', 'iso-8859-1', 'iso-8859-5']\n\n negotiator = new Negotiator(request)\n\n // Let's say Accept-Charset header is 'utf-8, iso-8859-1;q=0.8, utf-7;q=0.2'\n\n negotiator.preferredCharsets()\n // -> ['utf-8', 'iso-8859-1', 'utf-7']\n\n negotiator.preferredCharsets(availableCharsets)\n // -> ['utf-8', 'iso-8859-1']\n\n negotiator.preferredCharset(availableCharsets)\n // -> 'utf-8'\n\nYou can check a working example at `examples/charset.js`.\n\n## Methods\n\n`preferredCharsets(availableCharsets)`:\n\nReturns an array of preferred charsets ordered by priority from a list of available charsets.\n\n`preferredCharset(availableCharsets)`:\n\nReturns the top preferred charset from a list of available charsets.\n\n# Accept-Encoding Negotiation\n\n Negotiator = require('negotiator').Negotiator\n\n availableEncodings = ['identity', 'gzip']\n\n negotiator = new Negotiator(request)\n\n // Let's say Accept-Encoding header is 'gzip, compress;q=0.2, identity;q=0.5'\n\n negotiator.preferredEncodings()\n // -> ['gzip', 'identity', 'compress']\n\n negotiator.preferredEncodings(availableEncodings)\n // -> ['gzip', 'identity']\n\n negotiator.preferredEncoding(availableEncodings)\n // -> 'gzip'\n\nYou can check a working example at `examples/encoding.js`.\n\n## Methods\n\n`preferredEncodings(availableEncodings)`:\n\nReturns an array of preferred encodings ordered by priority from a list of available encodings.\n\n`preferredEncoding(availableEncodings)`:\n\nReturns the top preferred encoding from a list of available encodings.\n\n# License\n\nMIT\n", + "readmeFilename": "readme.md", + "bugs": { + "url": "https://github.com/federomero/negotiator/issues" + }, + "dependencies": {}, + "_id": "negotiator@0.3.0", + "dist": { + "shasum": "706d692efeddf574d57ea9fb1ab89a4fa7ee8f60" + }, + "_from": "negotiator@0.3.0", + "_resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.3.0.tgz" +} diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/readme.md b/node_modules/express/node_modules/connect/node_modules/negotiator/readme.md new file mode 100644 index 0000000..0a077bb --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/readme.md @@ -0,0 +1,132 @@ +# Negotiator + +An HTTP content negotiator for node.js written in javascript. + +# Accept Negotiation + + Negotiator = require('negotiator') + + availableMediaTypes = ['text/html', 'text/plain', 'application/json'] + + // The negotiator constructor receives a request object + negotiator = new Negotiator(request) + + // Let's say Accept header is 'text/html, application/*;q=0.2, image/jpeg;q=0.8' + + negotiator.preferredMediaTypes() + // -> ['text/html', 'image/jpeg', 'application/*'] + + negotiator.preferredMediaTypes(availableMediaTypes) + // -> ['text/html', 'application/json'] + + negotiator.preferredMediaType(availableMediaTypes) + // -> 'text/html' + +You can check a working example at `examples/accept.js`. + +## Methods + +`preferredMediaTypes(availableMediaTypes)`: + +Returns an array of preferred media types ordered by priority from a list of available media types. + +`preferredMediaType(availableMediaType)`: + +Returns the top preferred media type from a list of available media types. + +# Accept-Language Negotiation + + Negotiator = require('negotiator') + + negotiator = new Negotiator(request) + + availableLanguages = 'en', 'es', 'fr' + + // Let's say Accept-Language header is 'en;q=0.8, es, pt' + + negotiator.preferredLanguages() + // -> ['es', 'pt', 'en'] + + negotiator.preferredLanguages(availableLanguages) + // -> ['es', 'en'] + + language = negotiator.preferredLanguage(availableLanguages) + // -> 'es' + +You can check a working example at `examples/language.js`. + +## Methods + +`preferredLanguages(availableLanguages)`: + +Returns an array of preferred languages ordered by priority from a list of available languages. + +`preferredLanguage(availableLanguages)`: + +Returns the top preferred language from a list of available languages. + +# Accept-Charset Negotiation + + Negotiator = require('negotiator') + + availableCharsets = ['utf-8', 'iso-8859-1', 'iso-8859-5'] + + negotiator = new Negotiator(request) + + // Let's say Accept-Charset header is 'utf-8, iso-8859-1;q=0.8, utf-7;q=0.2' + + negotiator.preferredCharsets() + // -> ['utf-8', 'iso-8859-1', 'utf-7'] + + negotiator.preferredCharsets(availableCharsets) + // -> ['utf-8', 'iso-8859-1'] + + negotiator.preferredCharset(availableCharsets) + // -> 'utf-8' + +You can check a working example at `examples/charset.js`. + +## Methods + +`preferredCharsets(availableCharsets)`: + +Returns an array of preferred charsets ordered by priority from a list of available charsets. + +`preferredCharset(availableCharsets)`: + +Returns the top preferred charset from a list of available charsets. + +# Accept-Encoding Negotiation + + Negotiator = require('negotiator').Negotiator + + availableEncodings = ['identity', 'gzip'] + + negotiator = new Negotiator(request) + + // Let's say Accept-Encoding header is 'gzip, compress;q=0.2, identity;q=0.5' + + negotiator.preferredEncodings() + // -> ['gzip', 'identity', 'compress'] + + negotiator.preferredEncodings(availableEncodings) + // -> ['gzip', 'identity'] + + negotiator.preferredEncoding(availableEncodings) + // -> 'gzip' + +You can check a working example at `examples/encoding.js`. + +## Methods + +`preferredEncodings(availableEncodings)`: + +Returns an array of preferred encodings ordered by priority from a list of available encodings. + +`preferredEncoding(availableEncodings)`: + +Returns the top preferred encoding from a list of available encodings. + +# License + +MIT diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/test/charset.js b/node_modules/express/node_modules/connect/node_modules/negotiator/test/charset.js new file mode 100644 index 0000000..79224a7 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/test/charset.js @@ -0,0 +1,62 @@ +(function() { + var configuration, preferredCharsets, testConfigurations, testCorrectCharset, _i, _len, + _this = this; + + preferredCharsets = require('../lib/charset').preferredCharsets; + + this["Should not return a charset when no charset is provided"] = function(test) { + test.deepEqual(preferredCharsets('*', []), []); + return test.done(); + }; + + this["Should not return a charset when no charset is acceptable"] = function(test) { + test.deepEqual(preferredCharsets('ISO-8859-1', ['utf-8']), []); + return test.done(); + }; + + this["Should not return a charset with q = 0"] = function(test) { + test.deepEqual(preferredCharsets('utf-8;q=0', ['utf-8']), []); + return test.done(); + }; + + testCorrectCharset = function(c) { + return _this["Should return " + c.selected + " for accept-charset header " + c.accept + " with provided charset " + c.provided] = function(test) { + test.deepEqual(preferredCharsets(c.accept, c.provided), c.selected); + return test.done(); + }; + }; + + testConfigurations = [ + { + accept: 'utf-8', + provided: ['utf-8'], + selected: ['utf-8'] + }, { + accept: '*', + provided: ['utf-8'], + selected: ['utf-8'] + }, { + accept: 'utf-8', + provided: ['utf-8', 'ISO-8859-1'], + selected: ['utf-8'] + }, { + accept: 'utf-8, ISO-8859-1', + provided: ['utf-8'], + selected: ['utf-8'] + }, { + accept: 'utf-8;q=0.8, ISO-8859-1', + provided: ['utf-8', 'ISO-8859-1'], + selected: ['ISO-8859-1', 'utf-8'] + }, { + accept: 'utf-8;q=0.8, ISO-8859-1', + provided: null, + selected: ['ISO-8859-1', 'utf-8'] + } + ]; + + for (_i = 0, _len = testConfigurations.length; _i < _len; _i++) { + configuration = testConfigurations[_i]; + testCorrectCharset(configuration); + } + +}).call(this); diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/test/encoding.js b/node_modules/express/node_modules/connect/node_modules/negotiator/test/encoding.js new file mode 100644 index 0000000..7859d5e --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/test/encoding.js @@ -0,0 +1,70 @@ +(function() { + var configuration, preferredEncodings, testConfigurations, testCorrectEncoding, _i, _len, + _this = this; + + preferredEncodings = require('../lib/encoding').preferredEncodings; + + this["Should return identity encoding when no encoding is provided"] = function(test) { + test.deepEqual(preferredEncodings(null), ['identity']); + return test.done(); + }; + + this["Should include the identity encoding even if not explicity listed"] = function(test) { + test.ok(preferredEncodings('gzip').indexOf('identity') !== -1); + return test.done(); + }; + + this["Should not return identity encoding if q = 0"] = function(test) { + test.ok(preferredEncodings('identity;q=0').indexOf('identity') === -1); + return test.done(); + }; + + testCorrectEncoding = function(c) { + return _this["Should return " + c.selected + " for accept-encoding header " + c.accept + " with provided encoding " + c.provided] = function(test) { + test.deepEqual(preferredEncodings(c.accept, c.provided), c.selected); + return test.done(); + }; + }; + + testConfigurations = [ + { + accept: 'gzip', + provided: ['identity', 'gzip'], + selected: ['gzip', 'identity'] + }, { + accept: 'gzip, compress', + provided: ['compress'], + selected: ['compress'] + }, { + accept: 'deflate', + provided: ['gzip', 'identity'], + selected: ['identity'] + }, { + accept: '*', + provided: ['identity', 'gzip'], + selected: ['identity', 'gzip'] + }, { + accept: 'gzip, compress', + provided: ['compress', 'identity'], + selected: ['compress', 'identity'] + }, { + accept: 'gzip;q=0.8, identity;q=0.5, *;q=0.3', + provided: ['identity', 'gzip', 'compress'], + selected: ['gzip', 'identity', 'compress'] + }, { + accept: 'gzip;q=0.8, compress', + provided: ['gzip', 'compress'], + selected: ['compress', 'gzip'] + }, { + accept: 'gzip;q=0.8, compress', + provided: null, + selected: ['compress', 'gzip', 'identity'] + } + ]; + + for (_i = 0, _len = testConfigurations.length; _i < _len; _i++) { + configuration = testConfigurations[_i]; + testCorrectEncoding(configuration); + } + +}).call(this); diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/test/language.js b/node_modules/express/node_modules/connect/node_modules/negotiator/test/language.js new file mode 100644 index 0000000..d98f26d --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/test/language.js @@ -0,0 +1,70 @@ +(function() { + var configuration, preferredLanguages, testConfigurations, testCorrectType, _i, _len, + _this = this; + + preferredLanguages = require('../lib/language').preferredLanguages; + + this["Should not return a language when no is provided"] = function(test) { + test.deepEqual(preferredLanguages('*', []), []); + return test.done(); + }; + + this["Should not return a language when no language is acceptable"] = function(test) { + test.deepEqual(preferredLanguages('en', ['es']), []); + return test.done(); + }; + + this["Should not return a language with q = 0"] = function(test) { + test.deepEqual(preferredLanguages('en;q=0', ['en']), []); + return test.done(); + }; + + testCorrectType = function(c) { + return _this["Should return " + c.selected + " for accept-language header " + c.accept + " with provided language " + c.provided] = function(test) { + test.deepEqual(preferredLanguages(c.accept, c.provided), c.selected); + return test.done(); + }; + }; + + testConfigurations = [ + { + accept: 'en', + provided: ['en'], + selected: ['en'] + }, { + accept: '*', + provided: ['en'], + selected: ['en'] + }, { + accept: 'en-US, en;q=0.8', + provided: ['en-US', 'en-GB'], + selected: ['en-US', 'en-GB'] + }, { + accept: 'en-US, en-GB', + provided: ['en-US'], + selected: ['en-US'] + }, { + accept: 'en', + provided: ['en-US'], + selected: ['en-US'] + }, { + accept: 'en;q=0.8, es', + provided: ['en', 'es'], + selected: ['es', 'en'] + }, { + accept: 'en-US;q=0.8, es', + provided: ['en', 'es'], + selected: ['es', 'en'] + }, { + accept: 'en-US;q=0.8, es', + provided: null, + selected: ['es', 'en-US'] + } + ]; + + for (_i = 0, _len = testConfigurations.length; _i < _len; _i++) { + configuration = testConfigurations[_i]; + testCorrectType(configuration); + } + +}).call(this); diff --git a/node_modules/express/node_modules/connect/node_modules/negotiator/test/mediaType.js b/node_modules/express/node_modules/connect/node_modules/negotiator/test/mediaType.js new file mode 100644 index 0000000..08e4923 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/negotiator/test/mediaType.js @@ -0,0 +1,70 @@ +(function() { + var configuration, preferredMediaTypes, testConfigurations, testCorrectType, _i, _len, + _this = this; + + preferredMediaTypes = require('../lib/mediaType').preferredMediaTypes; + + this["Should not return a media type when no media type provided"] = function(test) { + test.deepEqual(preferredMediaTypes('*/*', []), []); + return test.done(); + }; + + this["Should not return a media type when no media type is acceptable"] = function(test) { + test.deepEqual(preferredMediaTypes('application/json', ['text/html']), []); + return test.done(); + }; + + this["Should not return a media type with q = 0"] = function(test) { + test.deepEqual(preferredMediaTypes('text/html;q=0', ['text/html']), []); + return test.done(); + }; + + testCorrectType = function(c) { + return _this["Should return " + c.selected + " for access header " + c.accept + " with provided types " + c.provided] = function(test) { + test.deepEqual(preferredMediaTypes(c.accept, c.provided), c.selected); + return test.done(); + }; + }; + + testConfigurations = [ + { + accept: 'text/html', + provided: ['text/html'], + selected: ['text/html'] + }, { + accept: '*/*', + provided: ['text/html'], + selected: ['text/html'] + }, { + accept: 'text/*', + provided: ['text/html'], + selected: ['text/html'] + }, { + accept: 'application/json, text/html', + provided: ['text/html'], + selected: ['text/html'] + }, { + accept: 'text/html;q=0.1', + provided: ['text/html'], + selected: ['text/html'] + }, { + accept: 'application/json, text/html', + provided: ['application/json', 'text/html'], + selected: ['application/json', 'text/html'] + }, { + accept: 'application/json;q=0.2, text/html', + provided: ['application/json', 'text/html'], + selected: ['text/html', 'application/json'] + }, { + accept: 'application/json;q=0.2, text/html', + provided: null, + selected: ['text/html', 'application/json'] + } + ]; + + for (_i = 0, _len = testConfigurations.length; _i < _len; _i++) { + configuration = testConfigurations[_i]; + testCorrectType(configuration); + } + +}).call(this); diff --git a/node_modules/express/node_modules/connect/node_modules/pause/.npmignore b/node_modules/express/node_modules/connect/node_modules/pause/.npmignore new file mode 100644 index 0000000..f1250e5 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/pause/.npmignore @@ -0,0 +1,4 @@ +support +test +examples +*.sock diff --git a/node_modules/express/node_modules/connect/node_modules/pause/History.md b/node_modules/express/node_modules/connect/node_modules/pause/History.md new file mode 100644 index 0000000..c8aa68f --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/pause/History.md @@ -0,0 +1,5 @@ + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/express/node_modules/connect/node_modules/pause/Makefile b/node_modules/express/node_modules/connect/node_modules/pause/Makefile new file mode 100644 index 0000000..4e9c8d3 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/pause/Makefile @@ -0,0 +1,7 @@ + +test: + @./node_modules/.bin/mocha \ + --require should \ + --reporter spec + +.PHONY: test \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/pause/Readme.md b/node_modules/express/node_modules/connect/node_modules/pause/Readme.md new file mode 100644 index 0000000..1cdd68a --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/pause/Readme.md @@ -0,0 +1,29 @@ + +# pause + + Pause streams... + +## License + +(The MIT License) + +Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/pause/index.js b/node_modules/express/node_modules/connect/node_modules/pause/index.js new file mode 100644 index 0000000..1b7b379 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/pause/index.js @@ -0,0 +1,29 @@ + +module.exports = 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]); + } + } + }; +}; \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/pause/package.json b/node_modules/express/node_modules/connect/node_modules/pause/package.json new file mode 100644 index 0000000..9296b24 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/pause/package.json @@ -0,0 +1,24 @@ +{ + "name": "pause", + "version": "0.0.1", + "description": "Pause streams...", + "keywords": [], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "*", + "should": "*" + }, + "main": "index", + "readme": "\n# pause\n\n Pause streams...\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", + "readmeFilename": "Readme.md", + "_id": "pause@0.0.1", + "dist": { + "shasum": "1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" + }, + "_from": "pause@0.0.1", + "_resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz" +} diff --git a/node_modules/express/node_modules/connect/node_modules/qs/.gitmodules b/node_modules/express/node_modules/connect/node_modules/qs/.gitmodules new file mode 100644 index 0000000..49e31da --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/qs/.gitmodules @@ -0,0 +1,6 @@ +[submodule "support/expresso"] + path = support/expresso + url = git://github.com/visionmedia/expresso.git +[submodule "support/should"] + path = support/should + url = git://github.com/visionmedia/should.js.git diff --git a/node_modules/express/node_modules/connect/node_modules/qs/.npmignore b/node_modules/express/node_modules/connect/node_modules/qs/.npmignore new file mode 100644 index 0000000..e85ce2a --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/qs/.npmignore @@ -0,0 +1,7 @@ +test +.travis.yml +benchmark.js +component.json +examples.js +History.md +Makefile diff --git a/node_modules/express/node_modules/connect/node_modules/qs/Readme.md b/node_modules/express/node_modules/connect/node_modules/qs/Readme.md new file mode 100644 index 0000000..27e54a4 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/qs/Readme.md @@ -0,0 +1,58 @@ +# node-querystring + + query string parser for node and the browser supporting nesting, as it was removed from `0.3.x`, so this library provides the previous and commonly desired behaviour (and twice as fast). Used by [express](http://expressjs.com), [connect](http://senchalabs.github.com/connect) and others. + +## Installation + + $ npm install qs + +## Examples + +```js +var qs = require('qs'); + +qs.parse('user[name][first]=Tobi&user[email]=tobi@learnboost.com'); +// => { user: { name: { first: 'Tobi' }, email: 'tobi@learnboost.com' } } + +qs.stringify({ user: { name: 'Tobi', email: 'tobi@learnboost.com' }}) +// => user[name]=Tobi&user[email]=tobi%40learnboost.com +``` + +## Testing + +Install dev dependencies: + + $ npm install -d + +and execute: + + $ make test + +browser: + + $ open test/browser/index.html + +## License + +(The MIT License) + +Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/qs/index.js b/node_modules/express/node_modules/connect/node_modules/qs/index.js new file mode 100644 index 0000000..590491e --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/qs/index.js @@ -0,0 +1,387 @@ +/** + * Object#toString() ref for stringify(). + */ + +var toString = Object.prototype.toString; + +/** + * Object#hasOwnProperty ref + */ + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * Array#indexOf shim. + */ + +var indexOf = typeof Array.prototype.indexOf === 'function' + ? function(arr, el) { return arr.indexOf(el); } + : function(arr, el) { + for (var i = 0; i < arr.length; i++) { + if (arr[i] === el) return i; + } + return -1; + }; + +/** + * Array.isArray shim. + */ + +var isArray = Array.isArray || function(arr) { + return toString.call(arr) == '[object Array]'; +}; + +/** + * Object.keys shim. + */ + +var objectKeys = Object.keys || function(obj) { + var ret = []; + for (var key in obj) ret.push(key); + return ret; +}; + +/** + * Array#forEach shim. + */ + +var forEach = typeof Array.prototype.forEach === 'function' + ? function(arr, fn) { return arr.forEach(fn); } + : function(arr, fn) { + for (var i = 0; i < arr.length; i++) fn(arr[i]); + }; + +/** + * Array#reduce shim. + */ + +var reduce = function(arr, fn, initial) { + if (typeof arr.reduce === 'function') return arr.reduce(fn, initial); + var res = initial; + for (var i = 0; i < arr.length; i++) res = fn(res, arr[i]); + return res; +}; + +/** + * Create a nullary object if possible + */ + +function createObject() { + return Object.create + ? Object.create(null) + : {}; +} + +/** + * Cache non-integer test regexp. + */ + +var isint = /^[0-9]+$/; + +function promote(parent, key) { + if (parent[key].length == 0) return parent[key] = createObject(); + var t = createObject(); + for (var i in parent[key]) { + if (hasOwnProperty.call(parent[key], i)) { + t[i] = parent[key][i]; + } + } + parent[key] = t; + return t; +} + +function parse(parts, parent, key, val) { + var part = parts.shift(); + // end + if (!part) { + if (isArray(parent[key])) { + parent[key].push(val); + } else if ('object' == typeof parent[key]) { + parent[key] = val; + } else if ('undefined' == typeof parent[key]) { + parent[key] = val; + } else { + parent[key] = [parent[key], val]; + } + // array + } else { + var obj = parent[key] = parent[key] || []; + if (']' == part) { + if (isArray(obj)) { + if ('' != val) obj.push(val); + } else if ('object' == typeof obj) { + obj[objectKeys(obj).length] = val; + } else { + obj = parent[key] = [parent[key], val]; + } + // prop + } else if (~indexOf(part, ']')) { + part = part.substr(0, part.length - 1); + if (!isint.test(part) && isArray(obj)) obj = promote(parent, key); + parse(parts, obj, part, val); + // key + } else { + if (!isint.test(part) && isArray(obj)) obj = promote(parent, key); + parse(parts, obj, part, val); + } + } +} + +/** + * Merge parent key/val pair. + */ + +function merge(parent, key, val){ + if (~indexOf(key, ']')) { + var parts = key.split('[') + , len = parts.length + , last = len - 1; + parse(parts, parent, 'base', val); + // optimize + } else { + if (!isint.test(key) && isArray(parent.base)) { + var t = createObject(); + for (var k in parent.base) t[k] = parent.base[k]; + parent.base = t; + } + set(parent.base, key, val); + } + + return parent; +} + +/** + * Compact sparse arrays. + */ + +function compact(obj) { + if ('object' != typeof obj) return obj; + + if (isArray(obj)) { + var ret = []; + + for (var i in obj) { + if (hasOwnProperty.call(obj, i)) { + ret.push(obj[i]); + } + } + + return ret; + } + + for (var key in obj) { + obj[key] = compact(obj[key]); + } + + return obj; +} + +/** + * Restore Object.prototype. + * see pull-request #58 + */ + +function restoreProto(obj) { + if (!Object.create) return obj; + if (isArray(obj)) return obj; + if (obj && 'object' != typeof obj) return obj; + + for (var key in obj) { + if (hasOwnProperty.call(obj, key)) { + obj[key] = restoreProto(obj[key]); + } + } + + obj.__proto__ = Object.prototype; + return obj; +} + +/** + * Parse the given obj. + */ + +function parseObject(obj){ + var ret = { base: {} }; + + forEach(objectKeys(obj), function(name){ + merge(ret, name, obj[name]); + }); + + return compact(ret.base); +} + +/** + * Parse the given str. + */ + +function parseString(str){ + var ret = reduce(String(str).split('&'), function(ret, pair){ + var eql = indexOf(pair, '=') + , brace = lastBraceInKey(pair) + , key = pair.substr(0, brace || eql) + , val = pair.substr(brace || eql, pair.length) + , val = val.substr(indexOf(val, '=') + 1, val.length); + + // ?foo + if ('' == key) key = pair, val = ''; + if ('' == key) return ret; + + return merge(ret, decode(key), decode(val)); + }, { base: createObject() }).base; + + return restoreProto(compact(ret)); +} + +/** + * Parse the given query `str` or `obj`, returning an object. + * + * @param {String} str | {Object} obj + * @return {Object} + * @api public + */ + +exports.parse = function(str){ + if (null == str || '' == str) return {}; + return 'object' == typeof str + ? parseObject(str) + : parseString(str); +}; + +/** + * Turn the given `obj` into a query string + * + * @param {Object} obj + * @return {String} + * @api public + */ + +var stringify = exports.stringify = function(obj, prefix) { + if (isArray(obj)) { + return stringifyArray(obj, prefix); + } else if ('[object Object]' == toString.call(obj)) { + return stringifyObject(obj, prefix); + } else if ('string' == typeof obj) { + return stringifyString(obj, prefix); + } else { + return prefix + '=' + encodeURIComponent(String(obj)); + } +}; + +/** + * Stringify the given `str`. + * + * @param {String} str + * @param {String} prefix + * @return {String} + * @api private + */ + +function stringifyString(str, prefix) { + if (!prefix) throw new TypeError('stringify expects an object'); + return prefix + '=' + encodeURIComponent(str); +} + +/** + * Stringify the given `arr`. + * + * @param {Array} arr + * @param {String} prefix + * @return {String} + * @api private + */ + +function stringifyArray(arr, prefix) { + var ret = []; + if (!prefix) throw new TypeError('stringify expects an object'); + for (var i = 0; i < arr.length; i++) { + ret.push(stringify(arr[i], prefix + '[' + i + ']')); + } + return ret.join('&'); +} + +/** + * Stringify the given `obj`. + * + * @param {Object} obj + * @param {String} prefix + * @return {String} + * @api private + */ + +function stringifyObject(obj, prefix) { + var ret = [] + , keys = objectKeys(obj) + , key; + + for (var i = 0, len = keys.length; i < len; ++i) { + key = keys[i]; + if ('' == key) continue; + if (null == obj[key]) { + ret.push(encodeURIComponent(key) + '='); + } else { + ret.push(stringify(obj[key], prefix + ? prefix + '[' + encodeURIComponent(key) + ']' + : encodeURIComponent(key))); + } + } + + return ret.join('&'); +} + +/** + * Set `obj`'s `key` to `val` respecting + * the weird and wonderful syntax of a qs, + * where "foo=bar&foo=baz" becomes an array. + * + * @param {Object} obj + * @param {String} key + * @param {String} val + * @api private + */ + +function set(obj, key, val) { + var v = obj[key]; + if (undefined === v) { + obj[key] = val; + } else if (isArray(v)) { + v.push(val); + } else { + obj[key] = [v, val]; + } +} + +/** + * Locate last brace in `str` within the key. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function lastBraceInKey(str) { + var len = str.length + , brace + , c; + for (var i = 0; i < len; ++i) { + c = str[i]; + if (']' == c) brace = false; + if ('[' == c) brace = true; + if ('=' == c && !brace) return i; + } +} + +/** + * Decode `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +function decode(str) { + try { + return decodeURIComponent(str.replace(/\+/g, ' ')); + } catch (err) { + return str; + } +} diff --git a/node_modules/express/node_modules/connect/node_modules/qs/package.json b/node_modules/express/node_modules/connect/node_modules/qs/package.json new file mode 100644 index 0000000..73c360f --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/qs/package.json @@ -0,0 +1,41 @@ +{ + "name": "qs", + "description": "querystring parser", + "version": "0.6.5", + "keywords": [ + "query string", + "parser", + "component" + ], + "repository": { + "type": "git", + "url": "git://github.com/visionmedia/node-querystring.git" + }, + "devDependencies": { + "mocha": "*", + "expect.js": "*" + }, + "scripts": { + "test": "make test" + }, + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca", + "url": "http://tjholowaychuk.com" + }, + "main": "index", + "engines": { + "node": "*" + }, + "readme": "# node-querystring\n\n query string parser for node and the browser supporting nesting, as it was removed from `0.3.x`, so this library provides the previous and commonly desired behaviour (and twice as fast). Used by [express](http://expressjs.com), [connect](http://senchalabs.github.com/connect) and others.\n\n## Installation\n\n $ npm install qs\n\n## Examples\n\n```js\nvar qs = require('qs');\n\nqs.parse('user[name][first]=Tobi&user[email]=tobi@learnboost.com');\n// => { user: { name: { first: 'Tobi' }, email: 'tobi@learnboost.com' } }\n\nqs.stringify({ user: { name: 'Tobi', email: 'tobi@learnboost.com' }})\n// => user[name]=Tobi&user[email]=tobi%40learnboost.com\n```\n\n## Testing\n\nInstall dev dependencies:\n\n $ npm install -d\n\nand execute:\n\n $ make test\n\nbrowser:\n\n $ open test/browser/index.html\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/node-querystring/issues" + }, + "_id": "qs@0.6.5", + "dist": { + "shasum": "294b268e4b0d4250f6dde19b3b8b34935dff14ef" + }, + "_from": "qs@0.6.5", + "_resolved": "https://registry.npmjs.org/qs/-/qs-0.6.5.tgz" +} diff --git a/node_modules/express/node_modules/connect/node_modules/raw-body/.npmignore b/node_modules/express/node_modules/connect/node_modules/raw-body/.npmignore new file mode 100644 index 0000000..602eb8e --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/raw-body/.npmignore @@ -0,0 +1 @@ +test.js \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/raw-body/.travis.yml b/node_modules/express/node_modules/connect/node_modules/raw-body/.travis.yml new file mode 100644 index 0000000..e79f715 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/raw-body/.travis.yml @@ -0,0 +1,4 @@ +node_js: +- "0.10" +- "0.8" +language: node_js \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/raw-body/Makefile b/node_modules/express/node_modules/connect/node_modules/raw-body/Makefile new file mode 100644 index 0000000..775fa5d --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/raw-body/Makefile @@ -0,0 +1,11 @@ +BIN = ./node_modules/.bin/ + +test: + @${BIN}mocha \ + --reporter spec \ + --bail + +clean: + @rm -rf node_modules + +.PHONY: test clean \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/raw-body/README.md b/node_modules/express/node_modules/connect/node_modules/raw-body/README.md new file mode 100644 index 0000000..aeeb94b --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/raw-body/README.md @@ -0,0 +1,74 @@ +# Raw Body [![Build Status](https://travis-ci.org/stream-utils/raw-body.png)](https://travis-ci.org/stream-utils/raw-body) + +Gets the entire buffer of a stream and validates its length against an expected length and limit. +Ideal for parsing request bodies. + +This is the callback version of [cat-stream](https://github.com/jonathanong/cat-stream), which is much more convoluted because streams suck. + +## API + +```js +var getRawBody = require('raw-body') + +app.use(function (req, res, next) { + getRawBody(req, { + expected: req.headers['content-length'], + limit: 1 * 1024 * 1024 // 1 mb + }, function (err, buffer) { + if (err) + return next(err) + + req.rawBody = buffer + next() + }) +}) +``` + +### Options + +- `expected` - The expected length of the stream. + If the contents of the stream do not add up to this length, + an `400` error code is returned. +- `limit` - The byte limit of the body. + If the body ends up being larger than this limit, + a `413` error code is returned. + +### Strings + +This library only returns the raw buffer. +If you want the string, +you can do something like this: + +```js +getRawBody(req, function (err, buffer) { + if (err) + return next(err) + + req.text = buffer.toString('utf8') + next() +}) +``` + +## License + +The MIT License (MIT) + +Copyright (c) 2013 Jonathan Ong me@jongleberry.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. \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/raw-body/index.js b/node_modules/express/node_modules/connect/node_modules/raw-body/index.js new file mode 100644 index 0000000..6616b0d --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/raw-body/index.js @@ -0,0 +1,72 @@ +module.exports = function (stream, options, callback) { + if (typeof options === 'function') { + callback = options + options = {} + } + + var limit = typeof options.limit === 'number' + ? options.limit + : null + + var expected = !isNaN(options.expected) + ? parseInt(options.expected, 10) + : null + + if (limit !== null && expected !== null && expected > limit) { + var err = new Error('request entity too large') + err.status = 413 + err.expected = expected + err.limit = limit + callback(err) + stream.resume() // dump stream + cleanup() + return + } + + var received = 0 + var buffers = [] + + stream.on('data', onData) + stream.once('end', onEnd) + stream.once('error', callback) + stream.once('error', cleanup) + stream.once('close', cleanup) + + function onData(chunk) { + buffers.push(chunk) + received += chunk.length + + if (limit !== null && received > limit) { + var err = new Error('request entity too large') + err.status = 413 + err.received = received + err.limit = limit + callback(err) + cleanup() + } + } + + function onEnd() { + if (expected !== null && received !== expected) { + var err = new Error('request size did not match content length') + err.status = 400 + err.received = received + err.expected = expected + callback(err) + } else { + callback(null, Buffer.concat(buffers)) + } + + cleanup() + } + + function cleanup() { + received = buffers = null + + stream.removeListener('data', onData) + stream.removeListener('end', onEnd) + stream.removeListener('error', callback) + stream.removeListener('error', cleanup) + stream.removeListener('close', cleanup) + } +} \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/raw-body/package.json b/node_modules/express/node_modules/connect/node_modules/raw-body/package.json new file mode 100644 index 0000000..4e2e1a6 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/raw-body/package.json @@ -0,0 +1,32 @@ +{ + "name": "raw-body", + "description": "Get and validate the raw body of a readable stream.", + "version": "0.0.3", + "author": { + "name": "Jonathan Ong", + "email": "me@jongleberry.com", + "url": "http://jongleberry.com" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/stream-utils/raw-body.git" + }, + "bugs": { + "url": "https://github.com/stream-utils/raw-body/issues" + }, + "devDependencies": { + "mocha": "~1.12" + }, + "scripts": { + "test": "make test" + }, + "readme": "# Raw Body [![Build Status](https://travis-ci.org/stream-utils/raw-body.png)](https://travis-ci.org/stream-utils/raw-body)\n\nGets the entire buffer of a stream and validates its length against an expected length and limit.\nIdeal for parsing request bodies.\n\nThis is the callback version of [cat-stream](https://github.com/jonathanong/cat-stream), which is much more convoluted because streams suck.\n\n## API\n\n```js\nvar getRawBody = require('raw-body')\n\napp.use(function (req, res, next) {\n getRawBody(req, {\n expected: req.headers['content-length'],\n limit: 1 * 1024 * 1024 // 1 mb\n }, function (err, buffer) {\n if (err)\n return next(err)\n\n req.rawBody = buffer\n next()\n })\n})\n```\n\n### Options\n\n- `expected` - The expected length of the stream.\n If the contents of the stream do not add up to this length,\n an `400` error code is returned.\n- `limit` - The byte limit of the body.\n If the body ends up being larger than this limit,\n a `413` error code is returned.\n\n### Strings\n\nThis library only returns the raw buffer.\nIf you want the string,\nyou can do something like this:\n\n```js\ngetRawBody(req, function (err, buffer) {\n if (err)\n return next(err)\n\n req.text = buffer.toString('utf8')\n next()\n})\n```\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2013 Jonathan Ong me@jongleberry.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.", + "readmeFilename": "README.md", + "_id": "raw-body@0.0.3", + "dist": { + "shasum": "0cb3eb22ced1ca607d32dd8fd94a6eb383f3eb8a" + }, + "_from": "raw-body@0.0.3", + "_resolved": "https://registry.npmjs.org/raw-body/-/raw-body-0.0.3.tgz" +} diff --git a/node_modules/express/node_modules/connect/node_modules/uid2/LICENSE b/node_modules/express/node_modules/connect/node_modules/uid2/LICENSE new file mode 100644 index 0000000..bdfab69 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/uid2/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 Marco Aurelio + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/express/node_modules/connect/node_modules/uid2/index.js b/node_modules/express/node_modules/connect/node_modules/uid2/index.js new file mode 100644 index 0000000..6240b30 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/uid2/index.js @@ -0,0 +1,55 @@ +/** + * Module dependencies + */ + +var crypto = require('crypto'); + +/** + * 62 characters in the ascii range that can be used in URLs without special + * encoding. + */ +var UIDCHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + +/** + * Make a Buffer into a string ready for use in URLs + * + * @param {String} + * @returns {String} + * @api private + */ +function tostr(bytes) { + var chars, r, i; + + r = []; + for (i = 0; i < bytes.length; i++) { + r.push(UIDCHARS[bytes[i] % UIDCHARS.length]); + } + + return r.join(''); +} + +/** + * Generate an Unique Id + * + * @param {Number} length The number of chars of the uid + * @param {Number} cb (optional) Callback for async uid generation + * @api public + */ + +function uid(length, cb) { + + if (typeof cb === 'undefined') { + return tostr(crypto.pseudoRandomBytes(length)); + } else { + crypto.pseudoRandomBytes(length, function(err, bytes) { + if (err) return cb(err); + cb(null, tostr(bytes)); + }) + } +} + +/** + * Exports + */ + +module.exports = uid; diff --git a/node_modules/express/node_modules/connect/node_modules/uid2/package.json b/node_modules/express/node_modules/connect/node_modules/uid2/package.json new file mode 100644 index 0000000..08af7a1 --- /dev/null +++ b/node_modules/express/node_modules/connect/node_modules/uid2/package.json @@ -0,0 +1,16 @@ +{ + "name": "uid2", + "description": "strong uid", + "tags": [ + "uid" + ], + "version": "0.0.3", + "dependencies": {}, + "readme": "ERROR: No README data found!", + "_id": "uid2@0.0.3", + "dist": { + "shasum": "837bfbe18583ae394e1e2b803f8bc13c47f942ef" + }, + "_from": "uid2@0.0.3", + "_resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz" +} diff --git a/node_modules/express/node_modules/connect/package.json b/node_modules/express/node_modules/connect/package.json new file mode 100644 index 0000000..48ed87f --- /dev/null +++ b/node_modules/express/node_modules/connect/package.json @@ -0,0 +1,67 @@ +{ + "name": "connect", + "version": "2.11.0", + "description": "High performance middleware framework", + "keywords": [ + "framework", + "web", + "middleware", + "connect", + "rack" + ], + "repository": { + "type": "git", + "url": "git://github.com/senchalabs/connect.git" + }, + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca", + "url": "http://tjholowaychuk.com" + }, + "dependencies": { + "qs": "0.6.5", + "cookie-signature": "1.0.1", + "buffer-crc32": "0.2.1", + "cookie": "0.1.0", + "send": "0.1.4", + "bytes": "0.2.1", + "fresh": "0.2.0", + "pause": "0.0.1", + "uid2": "0.0.3", + "debug": "*", + "methods": "0.0.1", + "raw-body": "0.0.3", + "negotiator": "0.3.0", + "multiparty": "2.2.0" + }, + "devDependencies": { + "should": ">= 2.0.0", + "mocha": "*", + "jade": "*", + "dox": "*" + }, + "licenses": [ + { + "type": "MIT", + "url": "https://raw.github.com/senchalabs/connect/master/LICENSE" + } + ], + "main": "index", + "engines": { + "node": ">= 0.8.0" + }, + "scripts": { + "test": "make" + }, + "readme": "# Connect [![build status](https://secure.travis-ci.org/senchalabs/connect.png)](http://travis-ci.org/senchalabs/connect)\n\n Connect is an extensible HTTP server framework for [node](http://nodejs.org), providing high performance \"plugins\" known as _middleware_.\n\n Connect is bundled with over _20_ commonly used middleware, including\n a logger, session support, cookie parser, and [more](http://senchalabs.github.com/connect). Be sure to view the 2.x [documentation](http://senchalabs.github.com/connect/).\n\n```js\nvar connect = require('connect')\n , http = require('http');\n\nvar app = connect()\n .use(connect.favicon())\n .use(connect.logger('dev'))\n .use(connect.static('public'))\n .use(connect.directory('public'))\n .use(connect.cookieParser())\n .use(connect.session({ secret: 'my secret here' }))\n .use(function(req, res){\n res.end('Hello from Connect!\\n');\n });\n\nhttp.createServer(app).listen(3000);\n```\n\n## Middleware\n\n - [basicAuth](http://www.senchalabs.org/connect/basicAuth.html)\n - [bodyParser](http://www.senchalabs.org/connect/bodyParser.html)\n - [compress](http://www.senchalabs.org/connect/compress.html)\n - [cookieParser](http://www.senchalabs.org/connect/cookieParser.html)\n - [cookieSession](http://www.senchalabs.org/connect/cookieSession.html)\n - [csrf](http://www.senchalabs.org/connect/csrf.html)\n - [directory](http://www.senchalabs.org/connect/directory.html)\n - [errorHandler](http://www.senchalabs.org/connect/errorHandler.html)\n - [favicon](http://www.senchalabs.org/connect/favicon.html)\n - [json](http://www.senchalabs.org/connect/json.html)\n - [limit](http://www.senchalabs.org/connect/limit.html)\n - [logger](http://www.senchalabs.org/connect/logger.html)\n - [methodOverride](http://www.senchalabs.org/connect/methodOverride.html)\n - [multipart](http://www.senchalabs.org/connect/multipart.html)\n - [urlencoded](http://www.senchalabs.org/connect/urlencoded.html)\n - [query](http://www.senchalabs.org/connect/query.html)\n - [responseTime](http://www.senchalabs.org/connect/responseTime.html)\n - [session](http://www.senchalabs.org/connect/session.html)\n - [static](http://www.senchalabs.org/connect/static.html)\n - [staticCache](http://www.senchalabs.org/connect/staticCache.html)\n - [subdomains](http://www.senchalabs.org/connect/subdomains.html)\n - [vhost](http://www.senchalabs.org/connect/vhost.html)\n\n## Running Tests\n\nfirst:\n\n $ npm install -d\n\nthen:\n\n $ make test\n\n## Contributors\n\n https://github.com/senchalabs/connect/graphs/contributors\n\n## Node Compatibility\n\n Connect `< 1.x` is compatible with node 0.2.x\n\n\n Connect `1.x` is compatible with node 0.4.x\n\n\n Connect `2.x` is compatible with node 0.6.x\n\n\n Connect (_master_) is compatible with node 0.8.x\n\n## CLA\n\n [http://sencha.com/cla](http://sencha.com/cla)\n\n## License\n\nView the [LICENSE](https://github.com/senchalabs/connect/blob/master/LICENSE) file. The [Silk](http://www.famfamfam.com/lab/icons/silk/) icons used by the `directory` middleware created by/copyright of [FAMFAMFAM](http://www.famfamfam.com/).\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/senchalabs/connect/issues" + }, + "_id": "connect@2.11.0", + "dist": { + "shasum": "9991ce09ff9b85d9ead27f9d41d0b2a2df2f9284" + }, + "_from": "connect@2.11.0", + "_resolved": "https://registry.npmjs.org/connect/-/connect-2.11.0.tgz" +} diff --git a/node_modules/express/node_modules/cookie-signature/.npmignore b/node_modules/express/node_modules/cookie-signature/.npmignore new file mode 100644 index 0000000..f1250e5 --- /dev/null +++ b/node_modules/express/node_modules/cookie-signature/.npmignore @@ -0,0 +1,4 @@ +support +test +examples +*.sock diff --git a/node_modules/express/node_modules/cookie-signature/History.md b/node_modules/express/node_modules/cookie-signature/History.md new file mode 100644 index 0000000..9e30179 --- /dev/null +++ b/node_modules/express/node_modules/cookie-signature/History.md @@ -0,0 +1,11 @@ + +1.0.1 / 2013-04-15 +================== + + * Revert "Changed underlying HMAC algo. to sha512." + * Revert "Fix for timing attacks on MAC verification." + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/express/node_modules/cookie-signature/Makefile b/node_modules/express/node_modules/cookie-signature/Makefile new file mode 100644 index 0000000..4e9c8d3 --- /dev/null +++ b/node_modules/express/node_modules/cookie-signature/Makefile @@ -0,0 +1,7 @@ + +test: + @./node_modules/.bin/mocha \ + --require should \ + --reporter spec + +.PHONY: test \ No newline at end of file diff --git a/node_modules/express/node_modules/cookie-signature/Readme.md b/node_modules/express/node_modules/cookie-signature/Readme.md new file mode 100644 index 0000000..2559e84 --- /dev/null +++ b/node_modules/express/node_modules/cookie-signature/Readme.md @@ -0,0 +1,42 @@ + +# cookie-signature + + Sign and unsign cookies. + +## Example + +```js +var cookie = require('cookie-signature'); + +var val = cookie.sign('hello', 'tobiiscool'); +val.should.equal('hello.DGDUkGlIkCzPz+C0B064FNgHdEjox7ch8tOBGslZ5QI'); + +var val = cookie.sign('hello', 'tobiiscool'); +cookie.unsign(val, 'tobiiscool').should.equal('hello'); +cookie.unsign(val, 'luna').should.be.false; +``` + +## License + +(The MIT License) + +Copyright (c) 2012 LearnBoost <tj@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. \ No newline at end of file diff --git a/node_modules/express/node_modules/cookie-signature/index.js b/node_modules/express/node_modules/cookie-signature/index.js new file mode 100644 index 0000000..ed62814 --- /dev/null +++ b/node_modules/express/node_modules/cookie-signature/index.js @@ -0,0 +1,42 @@ + +/** + * Module dependencies. + */ + +var crypto = require('crypto'); + +/** + * Sign the given `val` with `secret`. + * + * @param {String} val + * @param {String} secret + * @return {String} + * @api private + */ + +exports.sign = function(val, secret){ + if ('string' != typeof val) throw new TypeError('cookie required'); + if ('string' != typeof secret) throw new TypeError('secret required'); + return val + '.' + crypto + .createHmac('sha256', secret) + .update(val) + .digest('base64') + .replace(/\=+$/, ''); +}; + +/** + * Unsign and decode the given `val` with `secret`, + * returning `false` if the signature is invalid. + * + * @param {String} val + * @param {String} secret + * @return {String|Boolean} + * @api private + */ + +exports.unsign = function(val, secret){ + if ('string' != typeof val) throw new TypeError('cookie required'); + if ('string' != typeof secret) throw new TypeError('secret required'); + var str = val.slice(0, val.lastIndexOf('.')); + return exports.sign(str, secret) == val ? str : false; +}; diff --git a/node_modules/express/node_modules/cookie-signature/package.json b/node_modules/express/node_modules/cookie-signature/package.json new file mode 100644 index 0000000..5203d81 --- /dev/null +++ b/node_modules/express/node_modules/cookie-signature/package.json @@ -0,0 +1,28 @@ +{ + "name": "cookie-signature", + "version": "1.0.1", + "description": "Sign and unsign cookies", + "keywords": [ + "cookie", + "sign", + "unsign" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@learnboost.com" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "*", + "should": "*" + }, + "main": "index", + "readme": "\n# cookie-signature\n\n Sign and unsign cookies.\n\n## Example\n\n```js\nvar cookie = require('cookie-signature');\n\nvar val = cookie.sign('hello', 'tobiiscool');\nval.should.equal('hello.DGDUkGlIkCzPz+C0B064FNgHdEjox7ch8tOBGslZ5QI');\n\nvar val = cookie.sign('hello', 'tobiiscool');\ncookie.unsign(val, 'tobiiscool').should.equal('hello');\ncookie.unsign(val, 'luna').should.be.false;\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2012 LearnBoost <tj@learnboost.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", + "readmeFilename": "Readme.md", + "_id": "cookie-signature@1.0.1", + "dist": { + "shasum": "44e072148af01e6e8e24afbf12690d68ae698ecb" + }, + "_from": "cookie-signature@1.0.1", + "_resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz" +} diff --git a/node_modules/express/node_modules/cookie/.npmignore b/node_modules/express/node_modules/cookie/.npmignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/node_modules/express/node_modules/cookie/.npmignore @@ -0,0 +1 @@ +node_modules diff --git a/node_modules/express/node_modules/cookie/.travis.yml b/node_modules/express/node_modules/cookie/.travis.yml new file mode 100644 index 0000000..9400c11 --- /dev/null +++ b/node_modules/express/node_modules/cookie/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - "0.6" + - "0.8" + - "0.10" diff --git a/node_modules/express/node_modules/cookie/LICENSE b/node_modules/express/node_modules/cookie/LICENSE new file mode 100644 index 0000000..249d9de --- /dev/null +++ b/node_modules/express/node_modules/cookie/LICENSE @@ -0,0 +1,9 @@ +// MIT License + +Copyright (C) Roman Shtylman + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/express/node_modules/cookie/README.md b/node_modules/express/node_modules/cookie/README.md new file mode 100644 index 0000000..5187ed1 --- /dev/null +++ b/node_modules/express/node_modules/cookie/README.md @@ -0,0 +1,44 @@ +# cookie [![Build Status](https://secure.travis-ci.org/shtylman/node-cookie.png?branch=master)](http://travis-ci.org/shtylman/node-cookie) # + +cookie is a basic cookie parser and serializer. It doesn't make assumptions about how you are going to deal with your cookies. It basically just provides a way to read and write the HTTP cookie headers. + +See [RFC6265](http://tools.ietf.org/html/rfc6265) for details about the http header for cookies. + +## how? + +``` +npm install cookie +``` + +```javascript +var cookie = require('cookie'); + +var hdr = cookie.serialize('foo', 'bar'); +// hdr = 'foo=bar'; + +var cookies = cookie.parse('foo=bar; cat=meow; dog=ruff'); +// cookies = { foo: 'bar', cat: 'meow', dog: 'ruff' }; +``` + +## more + +The serialize function takes a third parameter, an object, to set cookie options. See the RFC for valid values. + +### path +> cookie path + +### expires +> absolute expiration date for the cookie (Date object) + +### maxAge +> relative max age of the cookie from when the client receives it (seconds) + +### domain +> domain for the cookie + +### secure +> true or false + +### httpOnly +> true or false + diff --git a/node_modules/express/node_modules/cookie/index.js b/node_modules/express/node_modules/cookie/index.js new file mode 100644 index 0000000..16bdb65 --- /dev/null +++ b/node_modules/express/node_modules/cookie/index.js @@ -0,0 +1,70 @@ + +/// Serialize the a name value pair into a cookie string suitable for +/// http headers. An optional options object specified cookie parameters +/// +/// serialize('foo', 'bar', { httpOnly: true }) +/// => "foo=bar; httpOnly" +/// +/// @param {String} name +/// @param {String} val +/// @param {Object} options +/// @return {String} +var serialize = function(name, val, opt){ + opt = opt || {}; + var enc = opt.encode || encode; + var pairs = [name + '=' + enc(val)]; + + if (opt.maxAge) pairs.push('Max-Age=' + opt.maxAge); + if (opt.domain) pairs.push('Domain=' + opt.domain); + if (opt.path) pairs.push('Path=' + opt.path); + if (opt.expires) pairs.push('Expires=' + opt.expires.toUTCString()); + if (opt.httpOnly) pairs.push('HttpOnly'); + if (opt.secure) pairs.push('Secure'); + + return pairs.join('; '); +}; + +/// Parse the given cookie header string into an object +/// The object has the various cookies as keys(names) => values +/// @param {String} str +/// @return {Object} +var parse = function(str, opt) { + opt = opt || {}; + var obj = {} + var pairs = str.split(/[;,] */); + var dec = opt.decode || decode; + + pairs.forEach(function(pair) { + var eq_idx = pair.indexOf('=') + + // skip things that don't look like key=value + if (eq_idx < 0) { + return; + } + + var key = pair.substr(0, eq_idx).trim() + var val = pair.substr(++eq_idx, pair.length).trim(); + + // quoted values + if ('"' == val[0]) { + val = val.slice(1, -1); + } + + // only assign once + if (undefined == obj[key]) { + try { + obj[key] = dec(val); + } catch (e) { + obj[key] = val; + } + } + }); + + return obj; +}; + +var encode = encodeURIComponent; +var decode = decodeURIComponent; + +module.exports.serialize = serialize; +module.exports.parse = parse; diff --git a/node_modules/express/node_modules/cookie/package.json b/node_modules/express/node_modules/cookie/package.json new file mode 100644 index 0000000..7f6da52 --- /dev/null +++ b/node_modules/express/node_modules/cookie/package.json @@ -0,0 +1,40 @@ +{ + "author": { + "name": "Roman Shtylman", + "email": "shtylman@gmail.com" + }, + "name": "cookie", + "description": "cookie parsing and serialization", + "version": "0.1.0", + "repository": { + "type": "git", + "url": "git://github.com/shtylman/node-cookie.git" + }, + "keywords": [ + "cookie", + "cookies" + ], + "main": "index.js", + "scripts": { + "test": "mocha" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "1.x.x" + }, + "optionalDependencies": {}, + "engines": { + "node": "*" + }, + "readme": "# cookie [![Build Status](https://secure.travis-ci.org/shtylman/node-cookie.png?branch=master)](http://travis-ci.org/shtylman/node-cookie) #\n\ncookie is a basic cookie parser and serializer. It doesn't make assumptions about how you are going to deal with your cookies. It basically just provides a way to read and write the HTTP cookie headers.\n\nSee [RFC6265](http://tools.ietf.org/html/rfc6265) for details about the http header for cookies.\n\n## how?\n\n```\nnpm install cookie\n```\n\n```javascript\nvar cookie = require('cookie');\n\nvar hdr = cookie.serialize('foo', 'bar');\n// hdr = 'foo=bar';\n\nvar cookies = cookie.parse('foo=bar; cat=meow; dog=ruff');\n// cookies = { foo: 'bar', cat: 'meow', dog: 'ruff' };\n```\n\n## more\n\nThe serialize function takes a third parameter, an object, to set cookie options. See the RFC for valid values.\n\n### path\n> cookie path\n\n### expires\n> absolute expiration date for the cookie (Date object)\n\n### maxAge\n> relative max age of the cookie from when the client receives it (seconds)\n\n### domain\n> domain for the cookie\n\n### secure\n> true or false\n\n### httpOnly\n> true or false\n\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/shtylman/node-cookie/issues" + }, + "_id": "cookie@0.1.0", + "dist": { + "shasum": "90eb469ddce905c866de687efc43131d8801f9d0" + }, + "_from": "cookie@0.1.0", + "_resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz" +} diff --git a/node_modules/express/node_modules/cookie/test/mocha.opts b/node_modules/express/node_modules/cookie/test/mocha.opts new file mode 100644 index 0000000..e2bfcc5 --- /dev/null +++ b/node_modules/express/node_modules/cookie/test/mocha.opts @@ -0,0 +1 @@ +--ui qunit diff --git a/node_modules/express/node_modules/cookie/test/parse.js b/node_modules/express/node_modules/cookie/test/parse.js new file mode 100644 index 0000000..c6c27a2 --- /dev/null +++ b/node_modules/express/node_modules/cookie/test/parse.js @@ -0,0 +1,44 @@ + +var assert = require('assert'); + +var cookie = require('..'); + +suite('parse'); + +test('basic', function() { + assert.deepEqual({ foo: 'bar' }, cookie.parse('foo=bar')); + assert.deepEqual({ foo: '123' }, cookie.parse('foo=123')); +}); + +test('ignore spaces', function() { + assert.deepEqual({ FOO: 'bar', baz: 'raz' }, + cookie.parse('FOO = bar; baz = raz')); +}); + +test('escaping', function() { + assert.deepEqual({ foo: 'bar=123456789&name=Magic+Mouse' }, + cookie.parse('foo="bar=123456789&name=Magic+Mouse"')); + + assert.deepEqual({ email: ' ",;/' }, + cookie.parse('email=%20%22%2c%3b%2f')); +}); + +test('ignore escaping error and return original value', function() { + assert.deepEqual({ foo: '%1', bar: 'bar' }, cookie.parse('foo=%1;bar=bar')); +}); + +test('ignore non values', function() { + assert.deepEqual({ foo: '%1', bar: 'bar' }, cookie.parse('foo=%1;bar=bar;HttpOnly;Secure')); +}); + +test('unencoded', function() { + assert.deepEqual({ foo: 'bar=123456789&name=Magic+Mouse' }, + cookie.parse('foo="bar=123456789&name=Magic+Mouse"',{ + decode: function(value) { return value; } + })); + + assert.deepEqual({ email: '%20%22%2c%3b%2f' }, + cookie.parse('email=%20%22%2c%3b%2f',{ + decode: function(value) { return value; } + })); +}) diff --git a/node_modules/express/node_modules/cookie/test/serialize.js b/node_modules/express/node_modules/cookie/test/serialize.js new file mode 100644 index 0000000..86bb8c9 --- /dev/null +++ b/node_modules/express/node_modules/cookie/test/serialize.js @@ -0,0 +1,64 @@ +// builtin +var assert = require('assert'); + +var cookie = require('..'); + +suite('serialize'); + +test('basic', function() { + assert.equal('foo=bar', cookie.serialize('foo', 'bar')); + assert.equal('foo=bar%20baz', cookie.serialize('foo', 'bar baz')); +}); + +test('path', function() { + assert.equal('foo=bar; Path=/', cookie.serialize('foo', 'bar', { + path: '/' + })); +}); + +test('secure', function() { + assert.equal('foo=bar; Secure', cookie.serialize('foo', 'bar', { + secure: true + })); + + assert.equal('foo=bar', cookie.serialize('foo', 'bar', { + secure: false + })); +}); + +test('domain', function() { + assert.equal('foo=bar; Domain=example.com', cookie.serialize('foo', 'bar', { + domain: 'example.com' + })); +}); + +test('httpOnly', function() { + assert.equal('foo=bar; HttpOnly', cookie.serialize('foo', 'bar', { + httpOnly: true + })); +}); + +test('maxAge', function() { + assert.equal('foo=bar; Max-Age=1000', cookie.serialize('foo', 'bar', { + maxAge: 1000 + })); +}); + +test('escaping', function() { + assert.deepEqual('cat=%2B%20', cookie.serialize('cat', '+ ')); +}); + +test('parse->serialize', function() { + + assert.deepEqual({ cat: 'foo=123&name=baz five' }, cookie.parse( + cookie.serialize('cat', 'foo=123&name=baz five'))); + + assert.deepEqual({ cat: ' ";/' }, cookie.parse( + cookie.serialize('cat', ' ";/'))); +}); + +test('unencoded', function() { + assert.deepEqual('cat=+ ', cookie.serialize('cat', '+ ', { + encode: function(value) { return value; } + })); +}) diff --git a/node_modules/express/node_modules/debug/Readme.md b/node_modules/express/node_modules/debug/Readme.md new file mode 100644 index 0000000..c5a34e8 --- /dev/null +++ b/node_modules/express/node_modules/debug/Readme.md @@ -0,0 +1,115 @@ +# debug + + tiny node.js debugging utility modelled after node core's debugging technique. + +## Installation + +``` +$ npm install debug +``` + +## Usage + + With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility. + +Example _app.js_: + +```js +var debug = require('debug')('http') + , http = require('http') + , name = 'My App'; + +// fake app + +debug('booting %s', name); + +http.createServer(function(req, res){ + debug(req.method + ' ' + req.url); + res.end('hello\n'); +}).listen(3000, function(){ + debug('listening'); +}); + +// fake worker of some kind + +require('./worker'); +``` + +Example _worker.js_: + +```js +var debug = require('debug')('worker'); + +setInterval(function(){ + debug('doing some work'); +}, 1000); +``` + + The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples: + + ![debug http and worker](http://f.cl.ly/items/18471z1H402O24072r1J/Screenshot.png) + + ![debug worker](http://f.cl.ly/items/1X413v1a3M0d3C2c1E0i/Screenshot.png) + +## Millisecond diff + + When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls. + + ![](http://f.cl.ly/items/2i3h1d3t121M2Z1A3Q0N/Screenshot.png) + + When stderr is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below: + _(NOTE: Debug now uses stderr instead of stdout, so the correct shell command for this example is actually `DEBUG=* node example/worker 2> out &`)_ + + ![](http://f.cl.ly/items/112H3i0e0o0P0a2Q2r11/Screenshot.png) + +## Conventions + + If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser". + +## Wildcards + + The "*" character may be used as a wildcard. Suppose for example your library has debuggers named "connect:bodyParser", "connect:compress", "connect:session", instead of listing all three with `DEBUG=connect:bodyParser,connect.compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`. + + You can also exclude specific debuggers by prefixing them with a "-" character. For example, `DEBUG=* -connect:*` would include all debuggers except those starting with "connect:". + +## Browser support + + Debug works in the browser as well, currently persisted by `localStorage`. For example if you have `worker:a` and `worker:b` as shown below, and wish to debug both type `debug.enable('worker:*')` in the console and refresh the page, this will remain until you disable with `debug.disable()`. + +```js +a = debug('worker:a'); +b = debug('worker:b'); + +setInterval(function(){ + a('doing some work'); +}, 1000); + +setInterval(function(){ + a('doing some work'); +}, 1200); +``` + +## License + +(The MIT License) + +Copyright (c) 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/node_modules/express/node_modules/debug/debug.js b/node_modules/express/node_modules/debug/debug.js new file mode 100644 index 0000000..509dc0d --- /dev/null +++ b/node_modules/express/node_modules/debug/debug.js @@ -0,0 +1,137 @@ + +/** + * Expose `debug()` as the module. + */ + +module.exports = debug; + +/** + * Create a debugger with the given `name`. + * + * @param {String} name + * @return {Type} + * @api public + */ + +function debug(name) { + if (!debug.enabled(name)) return function(){}; + + return function(fmt){ + fmt = coerce(fmt); + + var curr = new Date; + var ms = curr - (debug[name] || curr); + debug[name] = curr; + + fmt = name + + ' ' + + fmt + + ' +' + debug.humanize(ms); + + // This hackery is required for IE8 + // where `console.log` doesn't have 'apply' + window.console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); + } +} + +/** + * The currently active debug mode names. + */ + +debug.names = []; +debug.skips = []; + +/** + * Enables a debug mode by name. This can include modes + * separated by a colon and wildcards. + * + * @param {String} name + * @api public + */ + +debug.enable = function(name) { + try { + localStorage.debug = name; + } catch(e){} + + var split = (name || '').split(/[\s,]+/) + , len = split.length; + + for (var i = 0; i < len; i++) { + name = split[i].replace('*', '.*?'); + if (name[0] === '-') { + debug.skips.push(new RegExp('^' + name.substr(1) + '$')); + } + else { + debug.names.push(new RegExp('^' + name + '$')); + } + } +}; + +/** + * Disable debug output. + * + * @api public + */ + +debug.disable = function(){ + debug.enable(''); +}; + +/** + * Humanize the given `ms`. + * + * @param {Number} m + * @return {String} + * @api private + */ + +debug.humanize = function(ms) { + var sec = 1000 + , min = 60 * 1000 + , hour = 60 * min; + + if (ms >= hour) return (ms / hour).toFixed(1) + 'h'; + if (ms >= min) return (ms / min).toFixed(1) + 'm'; + if (ms >= sec) return (ms / sec | 0) + 's'; + return ms + 'ms'; +}; + +/** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ + +debug.enabled = function(name) { + for (var i = 0, len = debug.skips.length; i < len; i++) { + if (debug.skips[i].test(name)) { + return false; + } + } + for (var i = 0, len = debug.names.length; i < len; i++) { + if (debug.names[i].test(name)) { + return true; + } + } + return false; +}; + +/** + * Coerce `val`. + */ + +function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; +} + +// persist + +try { + if (window.localStorage) debug.enable(localStorage.debug); +} catch(e){} diff --git a/node_modules/express/node_modules/debug/index.js b/node_modules/express/node_modules/debug/index.js new file mode 100644 index 0000000..e02c13b --- /dev/null +++ b/node_modules/express/node_modules/debug/index.js @@ -0,0 +1,5 @@ +if ('undefined' == typeof window) { + module.exports = require('./lib/debug'); +} else { + module.exports = require('./debug'); +} diff --git a/node_modules/express/node_modules/debug/lib/debug.js b/node_modules/express/node_modules/debug/lib/debug.js new file mode 100644 index 0000000..3b0a918 --- /dev/null +++ b/node_modules/express/node_modules/debug/lib/debug.js @@ -0,0 +1,147 @@ +/** + * Module dependencies. + */ + +var tty = require('tty'); + +/** + * Expose `debug()` as the module. + */ + +module.exports = debug; + +/** + * Enabled debuggers. + */ + +var names = [] + , skips = []; + +(process.env.DEBUG || '') + .split(/[\s,]+/) + .forEach(function(name){ + name = name.replace('*', '.*?'); + if (name[0] === '-') { + skips.push(new RegExp('^' + name.substr(1) + '$')); + } else { + names.push(new RegExp('^' + name + '$')); + } + }); + +/** + * Colors. + */ + +var colors = [6, 2, 3, 4, 5, 1]; + +/** + * Previous debug() call. + */ + +var prev = {}; + +/** + * Previously assigned color. + */ + +var prevColor = 0; + +/** + * Is stdout a TTY? Colored output is disabled when `true`. + */ + +var isatty = tty.isatty(2); + +/** + * Select a color. + * + * @return {Number} + * @api private + */ + +function color() { + return colors[prevColor++ % colors.length]; +} + +/** + * Humanize the given `ms`. + * + * @param {Number} m + * @return {String} + * @api private + */ + +function humanize(ms) { + var sec = 1000 + , min = 60 * 1000 + , hour = 60 * min; + + if (ms >= hour) return (ms / hour).toFixed(1) + 'h'; + if (ms >= min) return (ms / min).toFixed(1) + 'm'; + if (ms >= sec) return (ms / sec | 0) + 's'; + return ms + 'ms'; +} + +/** + * Create a debugger with the given `name`. + * + * @param {String} name + * @return {Type} + * @api public + */ + +function debug(name) { + function disabled(){} + disabled.enabled = false; + + var match = skips.some(function(re){ + return re.test(name); + }); + + if (match) return disabled; + + match = names.some(function(re){ + return re.test(name); + }); + + if (!match) return disabled; + var c = color(); + + function colored(fmt) { + fmt = coerce(fmt); + + var curr = new Date; + var ms = curr - (prev[name] || curr); + prev[name] = curr; + + fmt = ' \u001b[9' + c + 'm' + name + ' ' + + '\u001b[3' + c + 'm\u001b[90m' + + fmt + '\u001b[3' + c + 'm' + + ' +' + humanize(ms) + '\u001b[0m'; + + console.error.apply(this, arguments); + } + + function plain(fmt) { + fmt = coerce(fmt); + + fmt = new Date().toUTCString() + + ' ' + name + ' ' + fmt; + console.error.apply(this, arguments); + } + + colored.enabled = plain.enabled = true; + + return isatty || process.env.DEBUG_COLORS + ? colored + : plain; +} + +/** + * Coerce `val`. + */ + +function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; +} diff --git a/node_modules/express/node_modules/debug/package.json b/node_modules/express/node_modules/debug/package.json new file mode 100644 index 0000000..0fa595d --- /dev/null +++ b/node_modules/express/node_modules/debug/package.json @@ -0,0 +1,50 @@ +{ + "name": "debug", + "version": "0.7.3", + "repository": { + "type": "git", + "url": "git://github.com/visionmedia/debug.git" + }, + "description": "small debugging utility", + "keywords": [ + "debug", + "log", + "debugger" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "*" + }, + "main": "lib/debug.js", + "browserify": "debug.js", + "browser": "./debug.js", + "engines": { + "node": "*" + }, + "files": [ + "lib/debug.js", + "debug.js", + "index.js" + ], + "component": { + "scripts": { + "debug/index.js": "index.js", + "debug/debug.js": "debug.js" + } + }, + "readme": "# debug\n\n tiny node.js debugging utility modelled after node core's debugging technique.\n\n## Installation\n\n```\n$ npm install debug\n```\n\n## Usage\n\n With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility.\n \nExample _app.js_:\n\n```js\nvar debug = require('debug')('http')\n , http = require('http')\n , name = 'My App';\n\n// fake app\n\ndebug('booting %s', name);\n\nhttp.createServer(function(req, res){\n debug(req.method + ' ' + req.url);\n res.end('hello\\n');\n}).listen(3000, function(){\n debug('listening');\n});\n\n// fake worker of some kind\n\nrequire('./worker');\n```\n\nExample _worker.js_:\n\n```js\nvar debug = require('debug')('worker');\n\nsetInterval(function(){\n debug('doing some work');\n}, 1000);\n```\n\n The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples:\n\n ![debug http and worker](http://f.cl.ly/items/18471z1H402O24072r1J/Screenshot.png)\n\n ![debug worker](http://f.cl.ly/items/1X413v1a3M0d3C2c1E0i/Screenshot.png)\n\n## Millisecond diff\n\n When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the \"+NNNms\" will show you how much time was spent between calls.\n\n ![](http://f.cl.ly/items/2i3h1d3t121M2Z1A3Q0N/Screenshot.png)\n\n When stderr is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below:\n _(NOTE: Debug now uses stderr instead of stdout, so the correct shell command for this example is actually `DEBUG=* node example/worker 2> out &`)_\n \n ![](http://f.cl.ly/items/112H3i0e0o0P0a2Q2r11/Screenshot.png)\n \n## Conventions\n\n If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use \":\" to separate features. For example \"bodyParser\" from Connect would then be \"connect:bodyParser\". \n\n## Wildcards\n\n The \"*\" character may be used as a wildcard. Suppose for example your library has debuggers named \"connect:bodyParser\", \"connect:compress\", \"connect:session\", instead of listing all three with `DEBUG=connect:bodyParser,connect.compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.\n\n You can also exclude specific debuggers by prefixing them with a \"-\" character. For example, `DEBUG=* -connect:*` would include all debuggers except those starting with \"connect:\".\n\n## Browser support\n\n Debug works in the browser as well, currently persisted by `localStorage`. For example if you have `worker:a` and `worker:b` as shown below, and wish to debug both type `debug.enable('worker:*')` in the console and refresh the page, this will remain until you disable with `debug.disable()`. \n\n```js\na = debug('worker:a');\nb = debug('worker:b');\n\nsetInterval(function(){\n a('doing some work');\n}, 1000);\n\nsetInterval(function(){\n a('doing some work');\n}, 1200);\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/debug/issues" + }, + "_id": "debug@0.7.3", + "dist": { + "shasum": "ba7ae369799066a28d234fb8dad6f05837839da8" + }, + "_from": "debug@*", + "_resolved": "https://registry.npmjs.org/debug/-/debug-0.7.3.tgz" +} diff --git a/node_modules/express/node_modules/fresh/.npmignore b/node_modules/express/node_modules/fresh/.npmignore new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/node_modules/express/node_modules/fresh/.npmignore @@ -0,0 +1 @@ +test diff --git a/node_modules/express/node_modules/fresh/History.md b/node_modules/express/node_modules/fresh/History.md new file mode 100644 index 0000000..60a2903 --- /dev/null +++ b/node_modules/express/node_modules/fresh/History.md @@ -0,0 +1,5 @@ + +0.2.0 / 2013-08-11 +================== + + * fix: return false for no-cache diff --git a/node_modules/express/node_modules/fresh/Makefile b/node_modules/express/node_modules/fresh/Makefile new file mode 100644 index 0000000..8e8640f --- /dev/null +++ b/node_modules/express/node_modules/fresh/Makefile @@ -0,0 +1,7 @@ + +test: + @./node_modules/.bin/mocha \ + --reporter spec \ + --require should + +.PHONY: test \ No newline at end of file diff --git a/node_modules/express/node_modules/fresh/Readme.md b/node_modules/express/node_modules/fresh/Readme.md new file mode 100644 index 0000000..61366c5 --- /dev/null +++ b/node_modules/express/node_modules/fresh/Readme.md @@ -0,0 +1,57 @@ + +# node-fresh + + HTTP response freshness testing + +## fresh(req, res) + + Check freshness of `req` and `res` headers. + + When the cache is "fresh" __true__ is returned, + otherwise __false__ is returned to indicate that + the cache is now stale. + +## Example: + +```js +var req = { 'if-none-match': 'tobi' }; +var res = { 'etag': 'luna' }; +fresh(req, res); +// => false + +var req = { 'if-none-match': 'tobi' }; +var res = { 'etag': 'tobi' }; +fresh(req, res); +// => true +``` + +## Installation + +``` +$ npm install fresh +``` + +## License + +(The MIT License) + +Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/express/node_modules/fresh/index.js b/node_modules/express/node_modules/fresh/index.js new file mode 100644 index 0000000..9c3f47d --- /dev/null +++ b/node_modules/express/node_modules/fresh/index.js @@ -0,0 +1,53 @@ + +/** + * Expose `fresh()`. + */ + +module.exports = fresh; + +/** + * Check freshness of `req` and `res` headers. + * + * When the cache is "fresh" __true__ is returned, + * otherwise __false__ is returned to indicate that + * the cache is now stale. + * + * @param {Object} req + * @param {Object} res + * @return {Boolean} + * @api public + */ + +function fresh(req, res) { + // defaults + var etagMatches = true; + var notModified = true; + + // fields + var modifiedSince = req['if-modified-since']; + var noneMatch = req['if-none-match']; + var lastModified = res['last-modified']; + var etag = res['etag']; + var cc = req['cache-control']; + + // unconditional request + if (!modifiedSince && !noneMatch) return false; + + // check for no-cache cache request directive + if (cc && cc.indexOf('no-cache') !== -1) return false; + + // parse if-none-match + if (noneMatch) noneMatch = noneMatch.split(/ *, */); + + // if-none-match + if (noneMatch) etagMatches = ~noneMatch.indexOf(etag) || '*' == noneMatch[0]; + + // if-modified-since + if (modifiedSince) { + modifiedSince = new Date(modifiedSince); + lastModified = new Date(lastModified); + notModified = lastModified <= modifiedSince; + } + + return !! (etagMatches && notModified); +} \ No newline at end of file diff --git a/node_modules/express/node_modules/fresh/package.json b/node_modules/express/node_modules/fresh/package.json new file mode 100644 index 0000000..76a8131 --- /dev/null +++ b/node_modules/express/node_modules/fresh/package.json @@ -0,0 +1,31 @@ +{ + "name": "fresh", + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca", + "url": "http://tjholowaychuk.com" + }, + "description": "HTTP response freshness testing", + "version": "0.2.0", + "main": "index.js", + "repository": { + "type": "git", + "url": "https://github.com/visionmedia/node-fresh.git" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "*", + "should": "*" + }, + "readme": "\n# node-fresh\n\n HTTP response freshness testing\n\n## fresh(req, res)\n\n Check freshness of `req` and `res` headers.\n\n When the cache is \"fresh\" __true__ is returned,\n otherwise __false__ is returned to indicate that\n the cache is now stale.\n\n## Example:\n\n```js\nvar req = { 'if-none-match': 'tobi' };\nvar res = { 'etag': 'luna' };\nfresh(req, res);\n// => false\n\nvar req = { 'if-none-match': 'tobi' };\nvar res = { 'etag': 'tobi' };\nfresh(req, res);\n// => true\n```\n\n## Installation\n\n```\n$ npm install fresh\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/node-fresh/issues" + }, + "_id": "fresh@0.2.0", + "dist": { + "shasum": "bfd9402cf3df12c4a4c310c79f99a3dde13d34a7" + }, + "_from": "fresh@0.2.0", + "_resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.0.tgz" +} diff --git a/node_modules/express/node_modules/methods/History.md b/node_modules/express/node_modules/methods/History.md new file mode 100644 index 0000000..1d0e229 --- /dev/null +++ b/node_modules/express/node_modules/methods/History.md @@ -0,0 +1,5 @@ + +0.1.0 / 2013-10-28 +================== + + * add http.METHODS support diff --git a/node_modules/express/node_modules/methods/Readme.md b/node_modules/express/node_modules/methods/Readme.md new file mode 100644 index 0000000..ac0658e --- /dev/null +++ b/node_modules/express/node_modules/methods/Readme.md @@ -0,0 +1,4 @@ + +# Methods + + HTTP verbs that node core's parser supports. diff --git a/node_modules/express/node_modules/methods/index.js b/node_modules/express/node_modules/methods/index.js new file mode 100644 index 0000000..95b93f5 --- /dev/null +++ b/node_modules/express/node_modules/methods/index.js @@ -0,0 +1,37 @@ + +var http = require('http'); + +if (http.METHODS) { + module.exports = http.METHODS.map(function(method){ + return method.toLowerCase(); + }); + + return; +} + +module.exports = [ + 'get', + 'post', + 'put', + 'head', + 'delete', + 'options', + 'trace', + 'copy', + 'lock', + 'mkcol', + 'move', + 'propfind', + 'proppatch', + 'unlock', + 'report', + 'mkactivity', + 'checkout', + 'merge', + 'm-search', + 'notify', + 'subscribe', + 'unsubscribe', + 'patch', + 'search' +]; diff --git a/node_modules/express/node_modules/methods/package.json b/node_modules/express/node_modules/methods/package.json new file mode 100644 index 0000000..e6b4db8 --- /dev/null +++ b/node_modules/express/node_modules/methods/package.json @@ -0,0 +1,32 @@ +{ + "name": "methods", + "version": "0.1.0", + "description": "HTTP methods that node supports", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "http", + "methods" + ], + "author": { + "name": "TJ Holowaychuk" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git://github.com/visionmedia/node-methods.git" + }, + "readme": "\n# Methods\n\n HTTP verbs that node core's parser supports.\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/node-methods/issues" + }, + "_id": "methods@0.1.0", + "dist": { + "shasum": "335d429eefd21b7bacf2e9c922a8d2bd14a30e4f" + }, + "_from": "methods@0.1.0", + "_resolved": "https://registry.npmjs.org/methods/-/methods-0.1.0.tgz" +} diff --git a/node_modules/express/node_modules/mkdirp/.npmignore b/node_modules/express/node_modules/mkdirp/.npmignore new file mode 100644 index 0000000..9303c34 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/.npmignore @@ -0,0 +1,2 @@ +node_modules/ +npm-debug.log \ No newline at end of file diff --git a/node_modules/express/node_modules/mkdirp/.travis.yml b/node_modules/express/node_modules/mkdirp/.travis.yml new file mode 100644 index 0000000..84fd7ca --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - 0.6 + - 0.8 + - 0.9 diff --git a/node_modules/express/node_modules/mkdirp/LICENSE b/node_modules/express/node_modules/mkdirp/LICENSE new file mode 100644 index 0000000..432d1ae --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/LICENSE @@ -0,0 +1,21 @@ +Copyright 2010 James Halliday (mail@substack.net) + +This project is free software released under the MIT/X11 license: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/express/node_modules/mkdirp/examples/pow.js b/node_modules/express/node_modules/mkdirp/examples/pow.js new file mode 100644 index 0000000..e692421 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/examples/pow.js @@ -0,0 +1,6 @@ +var mkdirp = require('mkdirp'); + +mkdirp('/tmp/foo/bar/baz', function (err) { + if (err) console.error(err) + else console.log('pow!') +}); diff --git a/node_modules/express/node_modules/mkdirp/index.js b/node_modules/express/node_modules/mkdirp/index.js new file mode 100644 index 0000000..fda6de8 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/index.js @@ -0,0 +1,82 @@ +var path = require('path'); +var fs = require('fs'); + +module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP; + +function mkdirP (p, mode, f, made) { + if (typeof mode === 'function' || mode === undefined) { + f = mode; + mode = 0777 & (~process.umask()); + } + if (!made) made = null; + + var cb = f || function () {}; + if (typeof mode === 'string') mode = parseInt(mode, 8); + p = path.resolve(p); + + fs.mkdir(p, mode, function (er) { + if (!er) { + made = made || p; + return cb(null, made); + } + switch (er.code) { + case 'ENOENT': + mkdirP(path.dirname(p), mode, function (er, made) { + if (er) cb(er, made); + else mkdirP(p, mode, cb, made); + }); + break; + + // In the case of any other error, just see if there's a dir + // there already. If so, then hooray! If not, then something + // is borked. + default: + fs.stat(p, function (er2, stat) { + // if the stat fails, then that's super weird. + // let the original error be the failure reason. + if (er2 || !stat.isDirectory()) cb(er, made) + else cb(null, made); + }); + break; + } + }); +} + +mkdirP.sync = function sync (p, mode, made) { + if (mode === undefined) { + mode = 0777 & (~process.umask()); + } + if (!made) made = null; + + if (typeof mode === 'string') mode = parseInt(mode, 8); + p = path.resolve(p); + + try { + fs.mkdirSync(p, mode); + made = made || p; + } + catch (err0) { + switch (err0.code) { + case 'ENOENT' : + made = sync(path.dirname(p), mode, made); + sync(p, mode, made); + break; + + // In the case of any other error, just see if there's a dir + // there already. If so, then hooray! If not, then something + // is borked. + default: + var stat; + try { + stat = fs.statSync(p); + } + catch (err1) { + throw err0; + } + if (!stat.isDirectory()) throw err0; + break; + } + } + + return made; +}; diff --git a/node_modules/express/node_modules/mkdirp/package.json b/node_modules/express/node_modules/mkdirp/package.json new file mode 100644 index 0000000..58f6439 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/package.json @@ -0,0 +1,37 @@ +{ + "name": "mkdirp", + "description": "Recursively mkdir, like `mkdir -p`", + "version": "0.3.5", + "author": { + "name": "James Halliday", + "email": "mail@substack.net", + "url": "http://substack.net" + }, + "main": "./index", + "keywords": [ + "mkdir", + "directory" + ], + "repository": { + "type": "git", + "url": "http://github.com/substack/node-mkdirp.git" + }, + "scripts": { + "test": "tap test/*.js" + }, + "devDependencies": { + "tap": "~0.4.0" + }, + "license": "MIT", + "readme": "# mkdirp\n\nLike `mkdir -p`, but in node.js!\n\n[![build status](https://secure.travis-ci.org/substack/node-mkdirp.png)](http://travis-ci.org/substack/node-mkdirp)\n\n# example\n\n## pow.js\n\n```js\nvar mkdirp = require('mkdirp');\n \nmkdirp('/tmp/foo/bar/baz', function (err) {\n if (err) console.error(err)\n else console.log('pow!')\n});\n```\n\nOutput\n\n```\npow!\n```\n\nAnd now /tmp/foo/bar/baz exists, huzzah!\n\n# methods\n\n```js\nvar mkdirp = require('mkdirp');\n```\n\n## mkdirp(dir, mode, cb)\n\nCreate a new directory and any necessary subdirectories at `dir` with octal\npermission string `mode`.\n\nIf `mode` isn't specified, it defaults to `0777 & (~process.umask())`.\n\n`cb(err, made)` fires with the error or the first directory `made`\nthat had to be created, if any.\n\n## mkdirp.sync(dir, mode)\n\nSynchronously create a new directory and any necessary subdirectories at `dir`\nwith octal permission string `mode`.\n\nIf `mode` isn't specified, it defaults to `0777 & (~process.umask())`.\n\nReturns the first directory that had to be created, if any.\n\n# install\n\nWith [npm](http://npmjs.org) do:\n\n```\nnpm install mkdirp\n```\n\n# license\n\nMIT\n", + "readmeFilename": "readme.markdown", + "bugs": { + "url": "https://github.com/substack/node-mkdirp/issues" + }, + "_id": "mkdirp@0.3.5", + "dist": { + "shasum": "3ca8fc91ed924e281236eec99e74505873ac5a45" + }, + "_from": "mkdirp@0.3.5", + "_resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz" +} diff --git a/node_modules/express/node_modules/mkdirp/readme.markdown b/node_modules/express/node_modules/mkdirp/readme.markdown new file mode 100644 index 0000000..83b0216 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/readme.markdown @@ -0,0 +1,63 @@ +# mkdirp + +Like `mkdir -p`, but in node.js! + +[![build status](https://secure.travis-ci.org/substack/node-mkdirp.png)](http://travis-ci.org/substack/node-mkdirp) + +# example + +## pow.js + +```js +var mkdirp = require('mkdirp'); + +mkdirp('/tmp/foo/bar/baz', function (err) { + if (err) console.error(err) + else console.log('pow!') +}); +``` + +Output + +``` +pow! +``` + +And now /tmp/foo/bar/baz exists, huzzah! + +# methods + +```js +var mkdirp = require('mkdirp'); +``` + +## mkdirp(dir, mode, cb) + +Create a new directory and any necessary subdirectories at `dir` with octal +permission string `mode`. + +If `mode` isn't specified, it defaults to `0777 & (~process.umask())`. + +`cb(err, made)` fires with the error or the first directory `made` +that had to be created, if any. + +## mkdirp.sync(dir, mode) + +Synchronously create a new directory and any necessary subdirectories at `dir` +with octal permission string `mode`. + +If `mode` isn't specified, it defaults to `0777 & (~process.umask())`. + +Returns the first directory that had to be created, if any. + +# install + +With [npm](http://npmjs.org) do: + +``` +npm install mkdirp +``` + +# license + +MIT diff --git a/node_modules/express/node_modules/mkdirp/test/chmod.js b/node_modules/express/node_modules/mkdirp/test/chmod.js new file mode 100644 index 0000000..520dcb8 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/chmod.js @@ -0,0 +1,38 @@ +var mkdirp = require('../').mkdirp; +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +var ps = [ '', 'tmp' ]; + +for (var i = 0; i < 25; i++) { + var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + ps.push(dir); +} + +var file = ps.join('/'); + +test('chmod-pre', function (t) { + var mode = 0744 + mkdirp(file, mode, function (er) { + t.ifError(er, 'should not error'); + fs.stat(file, function (er, stat) { + t.ifError(er, 'should exist'); + t.ok(stat && stat.isDirectory(), 'should be directory'); + t.equal(stat && stat.mode & 0777, mode, 'should be 0744'); + t.end(); + }); + }); +}); + +test('chmod', function (t) { + var mode = 0755 + mkdirp(file, mode, function (er) { + t.ifError(er, 'should not error'); + fs.stat(file, function (er, stat) { + t.ifError(er, 'should exist'); + t.ok(stat && stat.isDirectory(), 'should be directory'); + t.end(); + }); + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/clobber.js b/node_modules/express/node_modules/mkdirp/test/clobber.js new file mode 100644 index 0000000..0eb7099 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/clobber.js @@ -0,0 +1,37 @@ +var mkdirp = require('../').mkdirp; +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +var ps = [ '', 'tmp' ]; + +for (var i = 0; i < 25; i++) { + var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + ps.push(dir); +} + +var file = ps.join('/'); + +// a file in the way +var itw = ps.slice(0, 3).join('/'); + + +test('clobber-pre', function (t) { + console.error("about to write to "+itw) + fs.writeFileSync(itw, 'I AM IN THE WAY, THE TRUTH, AND THE LIGHT.'); + + fs.stat(itw, function (er, stat) { + t.ifError(er) + t.ok(stat && stat.isFile(), 'should be file') + t.end() + }) +}) + +test('clobber', function (t) { + t.plan(2); + mkdirp(file, 0755, function (err) { + t.ok(err); + t.equal(err.code, 'ENOTDIR'); + t.end(); + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/mkdirp.js b/node_modules/express/node_modules/mkdirp/test/mkdirp.js new file mode 100644 index 0000000..b07cd70 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/mkdirp.js @@ -0,0 +1,28 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('woo', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/perm.js b/node_modules/express/node_modules/mkdirp/test/perm.js new file mode 100644 index 0000000..23a7abb --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/perm.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('async perm', function (t) { + t.plan(2); + var file = '/tmp/' + (Math.random() * (1<<30)).toString(16); + + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); + +test('async root perm', function (t) { + mkdirp('/tmp', 0755, function (err) { + if (err) t.fail(err); + t.end(); + }); + t.end(); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/perm_sync.js b/node_modules/express/node_modules/mkdirp/test/perm_sync.js new file mode 100644 index 0000000..f685f60 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/perm_sync.js @@ -0,0 +1,39 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('sync perm', function (t) { + t.plan(2); + var file = '/tmp/' + (Math.random() * (1<<30)).toString(16) + '.json'; + + mkdirp.sync(file, 0755); + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }); +}); + +test('sync root perm', function (t) { + t.plan(1); + + var file = '/tmp'; + mkdirp.sync(file, 0755); + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/race.js b/node_modules/express/node_modules/mkdirp/test/race.js new file mode 100644 index 0000000..96a0447 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/race.js @@ -0,0 +1,41 @@ +var mkdirp = require('../').mkdirp; +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('race', function (t) { + t.plan(4); + var ps = [ '', 'tmp' ]; + + for (var i = 0; i < 25; i++) { + var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + ps.push(dir); + } + var file = ps.join('/'); + + var res = 2; + mk(file, function () { + if (--res === 0) t.end(); + }); + + mk(file, function () { + if (--res === 0) t.end(); + }); + + function mk (file, cb) { + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + if (cb) cb(); + } + }) + }) + }); + } +}); diff --git a/node_modules/express/node_modules/mkdirp/test/rel.js b/node_modules/express/node_modules/mkdirp/test/rel.js new file mode 100644 index 0000000..7985824 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/rel.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('rel', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var cwd = process.cwd(); + process.chdir('/tmp'); + + var file = [x,y,z].join('/'); + + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + process.chdir(cwd); + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/return.js b/node_modules/express/node_modules/mkdirp/test/return.js new file mode 100644 index 0000000..bce68e5 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/return.js @@ -0,0 +1,25 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('return value', function (t) { + t.plan(4); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + // should return the first dir created. + // By this point, it would be profoundly surprising if /tmp didn't + // already exist, since every other test makes things in there. + mkdirp(file, function (err, made) { + t.ifError(err); + t.equal(made, '/tmp/' + x); + mkdirp(file, function (err, made) { + t.ifError(err); + t.equal(made, null); + }); + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/return_sync.js b/node_modules/express/node_modules/mkdirp/test/return_sync.js new file mode 100644 index 0000000..7c222d3 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/return_sync.js @@ -0,0 +1,24 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('return value', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + // should return the first dir created. + // By this point, it would be profoundly surprising if /tmp didn't + // already exist, since every other test makes things in there. + // Note that this will throw on failure, which will fail the test. + var made = mkdirp.sync(file); + t.equal(made, '/tmp/' + x); + + // making the same file again should have no effect. + made = mkdirp.sync(file); + t.equal(made, null); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/root.js b/node_modules/express/node_modules/mkdirp/test/root.js new file mode 100644 index 0000000..97ad7a2 --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/root.js @@ -0,0 +1,18 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('root', function (t) { + // '/' on unix, 'c:/' on windows. + var file = path.resolve('/'); + + mkdirp(file, 0755, function (err) { + if (err) throw err + fs.stat(file, function (er, stat) { + if (er) throw er + t.ok(stat.isDirectory(), 'target is a directory'); + t.end(); + }) + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/sync.js b/node_modules/express/node_modules/mkdirp/test/sync.js new file mode 100644 index 0000000..7530cad --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/sync.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('sync', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + try { + mkdirp.sync(file, 0755); + } catch (err) { + t.fail(err); + return t.end(); + } + + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }); + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/umask.js b/node_modules/express/node_modules/mkdirp/test/umask.js new file mode 100644 index 0000000..64ccafe --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/umask.js @@ -0,0 +1,28 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('implicit mode from umask', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + mkdirp(file, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0777 & (~process.umask())); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); diff --git a/node_modules/express/node_modules/mkdirp/test/umask_sync.js b/node_modules/express/node_modules/mkdirp/test/umask_sync.js new file mode 100644 index 0000000..35bd5cb --- /dev/null +++ b/node_modules/express/node_modules/mkdirp/test/umask_sync.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('umask sync modes', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + try { + mkdirp.sync(file); + } catch (err) { + t.fail(err); + return t.end(); + } + + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, (0777 & (~process.umask()))); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }); + }); +}); diff --git a/node_modules/express/node_modules/range-parser/.npmignore b/node_modules/express/node_modules/range-parser/.npmignore new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/node_modules/express/node_modules/range-parser/.npmignore @@ -0,0 +1 @@ +test diff --git a/node_modules/express/node_modules/range-parser/History.md b/node_modules/express/node_modules/range-parser/History.md new file mode 100644 index 0000000..82df7b1 --- /dev/null +++ b/node_modules/express/node_modules/range-parser/History.md @@ -0,0 +1,15 @@ + +0.0.4 / 2012-06-17 +================== + + * changed: ret -1 for unsatisfiable and -2 when invalid + +0.0.3 / 2012-06-17 +================== + + * fix last-byte-pos default to len - 1 + +0.0.2 / 2012-06-14 +================== + + * add `.type` diff --git a/node_modules/express/node_modules/range-parser/Makefile b/node_modules/express/node_modules/range-parser/Makefile new file mode 100644 index 0000000..8e8640f --- /dev/null +++ b/node_modules/express/node_modules/range-parser/Makefile @@ -0,0 +1,7 @@ + +test: + @./node_modules/.bin/mocha \ + --reporter spec \ + --require should + +.PHONY: test \ No newline at end of file diff --git a/node_modules/express/node_modules/range-parser/Readme.md b/node_modules/express/node_modules/range-parser/Readme.md new file mode 100644 index 0000000..b2a67fe --- /dev/null +++ b/node_modules/express/node_modules/range-parser/Readme.md @@ -0,0 +1,28 @@ + +# node-range-parser + + Range header field parser. + +## Example: + +```js +assert(-1 == parse(200, 'bytes=500-20')); +assert(-2 == parse(200, 'bytes=malformed')); +parse(200, 'bytes=0-499').should.eql(arr('bytes', [{ start: 0, end: 199 }])); +parse(1000, 'bytes=0-499').should.eql(arr('bytes', [{ start: 0, end: 499 }])); +parse(1000, 'bytes=40-80').should.eql(arr('bytes', [{ start: 40, end: 80 }])); +parse(1000, 'bytes=-500').should.eql(arr('bytes', [{ start: 500, end: 999 }])); +parse(1000, 'bytes=-400').should.eql(arr('bytes', [{ start: 600, end: 999 }])); +parse(1000, 'bytes=500-').should.eql(arr('bytes', [{ start: 500, end: 999 }])); +parse(1000, 'bytes=400-').should.eql(arr('bytes', [{ start: 400, end: 999 }])); +parse(1000, 'bytes=0-0').should.eql(arr('bytes', [{ start: 0, end: 0 }])); +parse(1000, 'bytes=-1').should.eql(arr('bytes', [{ start: 999, end: 999 }])); +parse(1000, 'items=0-5').should.eql(arr('items', [{ start: 0, end: 5 }])); +parse(1000, 'bytes=40-80,-1').should.eql(arr('bytes', [{ start: 40, end: 80 }, { start: 999, end: 999 }])); +``` + +## Installation + +``` +$ npm install range-parser +``` \ No newline at end of file diff --git a/node_modules/express/node_modules/range-parser/index.js b/node_modules/express/node_modules/range-parser/index.js new file mode 100644 index 0000000..9b0f7a8 --- /dev/null +++ b/node_modules/express/node_modules/range-parser/index.js @@ -0,0 +1,49 @@ + +/** + * Parse "Range" header `str` relative to the given file `size`. + * + * @param {Number} size + * @param {String} str + * @return {Array} + * @api public + */ + +module.exports = function(size, str){ + var valid = true; + var i = str.indexOf('='); + + if (-1 == i) return -2; + + var arr = str.slice(i + 1).split(',').map(function(range){ + var range = range.split('-') + , start = parseInt(range[0], 10) + , end = parseInt(range[1], 10); + + // -nnn + if (isNaN(start)) { + start = size - end; + end = size - 1; + // nnn- + } else if (isNaN(end)) { + end = size - 1; + } + + // limit last-byte-pos to current length + if (end > size - 1) end = size - 1; + + // invalid + if (isNaN(start) + || isNaN(end) + || start > end + || start < 0) valid = false; + + return { + start: start, + end: end + }; + }); + + arr.type = str.slice(0, i); + + return valid ? arr : -1; +}; \ No newline at end of file diff --git a/node_modules/express/node_modules/range-parser/package.json b/node_modules/express/node_modules/range-parser/package.json new file mode 100644 index 0000000..0e048f7 --- /dev/null +++ b/node_modules/express/node_modules/range-parser/package.json @@ -0,0 +1,24 @@ +{ + "name": "range-parser", + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca", + "url": "http://tjholowaychuk.com" + }, + "description": "Range header field string parser", + "version": "0.0.4", + "main": "index.js", + "dependencies": {}, + "devDependencies": { + "mocha": "*", + "should": "*" + }, + "readme": "\n# node-range-parser\n\n Range header field parser.\n\n## Example:\n\n```js\nassert(-1 == parse(200, 'bytes=500-20'));\nassert(-2 == parse(200, 'bytes=malformed'));\nparse(200, 'bytes=0-499').should.eql(arr('bytes', [{ start: 0, end: 199 }]));\nparse(1000, 'bytes=0-499').should.eql(arr('bytes', [{ start: 0, end: 499 }]));\nparse(1000, 'bytes=40-80').should.eql(arr('bytes', [{ start: 40, end: 80 }]));\nparse(1000, 'bytes=-500').should.eql(arr('bytes', [{ start: 500, end: 999 }]));\nparse(1000, 'bytes=-400').should.eql(arr('bytes', [{ start: 600, end: 999 }]));\nparse(1000, 'bytes=500-').should.eql(arr('bytes', [{ start: 500, end: 999 }]));\nparse(1000, 'bytes=400-').should.eql(arr('bytes', [{ start: 400, end: 999 }]));\nparse(1000, 'bytes=0-0').should.eql(arr('bytes', [{ start: 0, end: 0 }]));\nparse(1000, 'bytes=-1').should.eql(arr('bytes', [{ start: 999, end: 999 }]));\nparse(1000, 'items=0-5').should.eql(arr('items', [{ start: 0, end: 5 }]));\nparse(1000, 'bytes=40-80,-1').should.eql(arr('bytes', [{ start: 40, end: 80 }, { start: 999, end: 999 }]));\n```\n\n## Installation\n\n```\n$ npm install range-parser\n```", + "readmeFilename": "Readme.md", + "_id": "range-parser@0.0.4", + "dist": { + "shasum": "c0427ffef51c10acba0782a46c9602e744ff620b" + }, + "_from": "range-parser@0.0.4", + "_resolved": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz" +} diff --git a/node_modules/express/node_modules/send/.npmignore b/node_modules/express/node_modules/send/.npmignore new file mode 100644 index 0000000..f1250e5 --- /dev/null +++ b/node_modules/express/node_modules/send/.npmignore @@ -0,0 +1,4 @@ +support +test +examples +*.sock diff --git a/node_modules/express/node_modules/send/History.md b/node_modules/express/node_modules/send/History.md new file mode 100644 index 0000000..55c4af7 --- /dev/null +++ b/node_modules/express/node_modules/send/History.md @@ -0,0 +1,40 @@ + +0.1.4 / 2013-08-11 +================== + + * update fresh + +0.1.3 / 2013-07-08 +================== + + * Revert "Fix fd leak" + +0.1.2 / 2013-07-03 +================== + + * Fix fd leak + +0.1.0 / 2012-08-25 +================== + + * add options parameter to send() that is passed to fs.createReadStream() [kanongil] + +0.0.4 / 2012-08-16 +================== + + * allow custom "Accept-Ranges" definition + +0.0.3 / 2012-07-16 +================== + + * fix normalization of the root directory. Closes #3 + +0.0.2 / 2012-07-09 +================== + + * add passing of req explicitly for now (YUCK) + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/express/node_modules/send/Makefile b/node_modules/express/node_modules/send/Makefile new file mode 100644 index 0000000..a9dcfd5 --- /dev/null +++ b/node_modules/express/node_modules/send/Makefile @@ -0,0 +1,8 @@ + +test: + @./node_modules/.bin/mocha \ + --require should \ + --reporter spec \ + --bail + +.PHONY: test \ No newline at end of file diff --git a/node_modules/express/node_modules/send/Readme.md b/node_modules/express/node_modules/send/Readme.md new file mode 100644 index 0000000..ea7b234 --- /dev/null +++ b/node_modules/express/node_modules/send/Readme.md @@ -0,0 +1,128 @@ +# send + + Send is Connect's `static()` extracted for generalized use, a streaming static file + server supporting partial responses (Ranges), conditional-GET negotiation, high test coverage, and granular events which may be leveraged to take appropriate actions in your application or framework. + +## Installation + + $ npm install send + +## Examples + + Small: + +```js +var http = require('http'); +var send = require('send'); + +var app = http.createServer(function(req, res){ + send(req, req.url).pipe(res); +}).listen(3000); +``` + + Serving from a root directory with custom error-handling: + +```js +var http = require('http'); +var send = require('send'); +var url = require('url'); + +var app = http.createServer(function(req, res){ + // your custom error-handling logic: + function error(err) { + res.statusCode = err.status || 500; + res.end(err.message); + } + + // your custom directory handling logic: + function redirect() { + res.statusCode = 301; + res.setHeader('Location', req.url + '/'); + res.end('Redirecting to ' + req.url + '/'); + } + + // transfer arbitrary files from within + // /www/example.com/public/* + send(req, url.parse(req.url).pathname) + .root('/www/example.com/public') + .on('error', error) + .on('directory', redirect) + .pipe(res); +}).listen(3000); +``` + +## API + +### Events + + - `error` an error occurred `(err)` + - `directory` a directory was requested + - `file` a file was requested `(path, stat)` + - `stream` file streaming has started `(stream)` + - `end` streaming has completed + +### .root(dir) + + Serve files relative to `path`. Aliased as `.from(dir)`. + +### .index(path) + + By default send supports "index.html" files, to disable this + invoke `.index(false)` or to supply a new index pass a string. + +### .maxage(ms) + + Provide a max-age in milliseconds for http caching, defaults to 0. + +### .hidden(bool) + + Enable or disable transfer of hidden files, defaults to false. + +## Error-handling + + By default when no `error` listeners are present an automatic response will be made, otherwise you have full control over the response, aka you may show a 5xx page etc. + +## Caching + + It does _not_ perform internal caching, you should use a reverse proxy cache such + as Varnish for this, or those fancy things called CDNs. If your application is small enough that it would benefit from single-node memory caching, it's small enough that it does not need caching at all ;). + +## Debugging + + To enable `debug()` instrumentation output export __DEBUG__: + +``` +$ DEBUG=send node app +``` + +## Running tests + +``` +$ npm install +$ make test +``` + +## License + +(The MIT License) + +Copyright (c) 2012 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/node_modules/express/node_modules/send/index.js b/node_modules/express/node_modules/send/index.js new file mode 100644 index 0000000..f17158d --- /dev/null +++ b/node_modules/express/node_modules/send/index.js @@ -0,0 +1,2 @@ + +module.exports = require('./lib/send'); \ No newline at end of file diff --git a/node_modules/express/node_modules/send/lib/send.js b/node_modules/express/node_modules/send/lib/send.js new file mode 100644 index 0000000..a3d94a6 --- /dev/null +++ b/node_modules/express/node_modules/send/lib/send.js @@ -0,0 +1,474 @@ + +/** + * Module dependencies. + */ + +var debug = require('debug')('send') + , parseRange = require('range-parser') + , Stream = require('stream') + , mime = require('mime') + , fresh = require('fresh') + , path = require('path') + , http = require('http') + , fs = require('fs') + , basename = path.basename + , normalize = path.normalize + , join = path.join + , utils = require('./utils'); + +/** + * Expose `send`. + */ + +exports = module.exports = send; + +/** + * Expose mime module. + */ + +exports.mime = mime; + +/** + * Return a `SendStream` for `req` and `path`. + * + * @param {Request} req + * @param {String} path + * @param {Object} options + * @return {SendStream} + * @api public + */ + +function send(req, path, options) { + return new SendStream(req, path, options); +} + +/** + * Initialize a `SendStream` with the given `path`. + * + * Events: + * + * - `error` an error occurred + * - `stream` file streaming has started + * - `end` streaming has completed + * - `directory` a directory was requested + * + * @param {Request} req + * @param {String} path + * @param {Object} options + * @api private + */ + +function SendStream(req, path, options) { + var self = this; + this.req = req; + this.path = path; + this.options = options || {}; + this.maxage(0); + this.hidden(false); + this.index('index.html'); +} + +/** + * Inherits from `Stream.prototype`. + */ + +SendStream.prototype.__proto__ = Stream.prototype; + +/** + * Enable or disable "hidden" (dot) files. + * + * @param {Boolean} path + * @return {SendStream} + * @api public + */ + +SendStream.prototype.hidden = function(val){ + debug('hidden %s', val); + this._hidden = val; + return this; +}; + +/** + * Set index `path`, set to a falsy + * value to disable index support. + * + * @param {String|Boolean} path + * @return {SendStream} + * @api public + */ + +SendStream.prototype.index = function(path){ + debug('index %s', path); + this._index = path; + return this; +}; + +/** + * Set root `path`. + * + * @param {String} path + * @return {SendStream} + * @api public + */ + +SendStream.prototype.root = +SendStream.prototype.from = function(path){ + this._root = normalize(path); + return this; +}; + +/** + * Set max-age to `ms`. + * + * @param {Number} ms + * @return {SendStream} + * @api public + */ + +SendStream.prototype.maxage = function(ms){ + if (Infinity == ms) ms = 60 * 60 * 24 * 365 * 1000; + debug('max-age %d', ms); + this._maxage = ms; + return this; +}; + +/** + * Emit error with `status`. + * + * @param {Number} status + * @api private + */ + +SendStream.prototype.error = function(status, err){ + var res = this.res; + var msg = http.STATUS_CODES[status]; + err = err || new Error(msg); + err.status = status; + if (this.listeners('error').length) return this.emit('error', err); + res.statusCode = err.status; + res.end(msg); +}; + +/** + * Check if the pathname is potentially malicious. + * + * @return {Boolean} + * @api private + */ + +SendStream.prototype.isMalicious = function(){ + return !this._root && ~this.path.indexOf('..'); +}; + +/** + * Check if the pathname ends with "/". + * + * @return {Boolean} + * @api private + */ + +SendStream.prototype.hasTrailingSlash = function(){ + return '/' == this.path[this.path.length - 1]; +}; + +/** + * Check if the basename leads with ".". + * + * @return {Boolean} + * @api private + */ + +SendStream.prototype.hasLeadingDot = function(){ + return '.' == basename(this.path)[0]; +}; + +/** + * Check if this is a conditional GET request. + * + * @return {Boolean} + * @api private + */ + +SendStream.prototype.isConditionalGET = function(){ + return this.req.headers['if-none-match'] + || this.req.headers['if-modified-since']; +}; + +/** + * Strip content-* header fields. + * + * @api private + */ + +SendStream.prototype.removeContentHeaderFields = function(){ + var res = this.res; + Object.keys(res._headers).forEach(function(field){ + if (0 == field.indexOf('content')) { + res.removeHeader(field); + } + }); +}; + +/** + * Respond with 304 not modified. + * + * @api private + */ + +SendStream.prototype.notModified = function(){ + var res = this.res; + debug('not modified'); + this.removeContentHeaderFields(); + res.statusCode = 304; + res.end(); +}; + +/** + * Check if the request is cacheable, aka + * responded with 2xx or 304 (see RFC 2616 section 14.2{5,6}). + * + * @return {Boolean} + * @api private + */ + +SendStream.prototype.isCachable = function(){ + var res = this.res; + return (res.statusCode >= 200 && res.statusCode < 300) || 304 == res.statusCode; +}; + +/** + * Handle stat() error. + * + * @param {Error} err + * @api private + */ + +SendStream.prototype.onStatError = function(err){ + var notfound = ['ENOENT', 'ENAMETOOLONG', 'ENOTDIR']; + if (~notfound.indexOf(err.code)) return this.error(404, err); + this.error(500, err); +}; + +/** + * Check if the cache is fresh. + * + * @return {Boolean} + * @api private + */ + +SendStream.prototype.isFresh = function(){ + return fresh(this.req.headers, this.res._headers); +}; + +/** + * Redirect to `path`. + * + * @param {String} path + * @api private + */ + +SendStream.prototype.redirect = function(path){ + if (this.listeners('directory').length) return this.emit('directory'); + var res = this.res; + path += '/'; + res.statusCode = 301; + res.setHeader('Location', path); + res.end('Redirecting to ' + utils.escape(path)); +}; + +/** + * Pipe to `res. + * + * @param {Stream} res + * @return {Stream} res + * @api public + */ + +SendStream.prototype.pipe = function(res){ + var self = this + , args = arguments + , path = this.path + , root = this._root; + + // references + this.res = res; + + // invalid request uri + path = utils.decode(path); + if (-1 == path) return this.error(400); + + // null byte(s) + if (~path.indexOf('\0')) return this.error(400); + + // join / normalize from optional root dir + if (root) path = normalize(join(this._root, path)); + + // ".." is malicious without "root" + if (this.isMalicious()) return this.error(403); + + // malicious path + if (root && 0 != path.indexOf(root)) return this.error(403); + + // hidden file support + if (!this._hidden && this.hasLeadingDot()) return this.error(404); + + // index file support + if (this._index && this.hasTrailingSlash()) path += this._index; + + debug('stat "%s"', path); + fs.stat(path, function(err, stat){ + if (err) return self.onStatError(err); + if (stat.isDirectory()) return self.redirect(self.path); + self.emit('file', path, stat); + self.send(path, stat); + }); + + return res; +}; + +/** + * Transfer `path`. + * + * @param {String} path + * @api public + */ + +SendStream.prototype.send = function(path, stat){ + var options = this.options; + var len = stat.size; + var res = this.res; + var req = this.req; + var ranges = req.headers.range; + var offset = options.start || 0; + + // set header fields + this.setHeader(stat); + + // set content-type + this.type(path); + + // conditional GET support + if (this.isConditionalGET() + && this.isCachable() + && this.isFresh()) { + return this.notModified(); + } + + // adjust len to start/end options + len = Math.max(0, len - offset); + if (options.end !== undefined) { + var bytes = options.end - offset + 1; + if (len > bytes) len = bytes; + } + + // Range support + if (ranges) { + ranges = parseRange(len, ranges); + + // unsatisfiable + if (-1 == ranges) { + res.setHeader('Content-Range', 'bytes */' + stat.size); + return this.error(416); + } + + // valid (syntactically invalid ranges are treated as a regular response) + if (-2 != ranges) { + options.start = offset + ranges[0].start; + options.end = offset + ranges[0].end; + + // Content-Range + res.statusCode = 206; + res.setHeader('Content-Range', 'bytes ' + + ranges[0].start + + '-' + + ranges[0].end + + '/' + + len); + len = options.end - options.start + 1; + } + } + + // content-length + res.setHeader('Content-Length', len); + + // HEAD support + if ('HEAD' == req.method) return res.end(); + + this.stream(path, options); +}; + +/** + * Stream `path` to the response. + * + * @param {String} path + * @param {Object} options + * @api private + */ + +SendStream.prototype.stream = function(path, options){ + // TODO: this is all lame, refactor meeee + var self = this; + var res = this.res; + var req = this.req; + + // pipe + var stream = fs.createReadStream(path, options); + this.emit('stream', stream); + stream.pipe(res); + + // socket closed, done with the fd + req.on('close', stream.destroy.bind(stream)); + + // error handling code-smell + stream.on('error', function(err){ + // no hope in responding + if (res._header) { + console.error(err.stack); + req.destroy(); + return; + } + + // 500 + err.status = 500; + self.emit('error', err); + }); + + // end + stream.on('end', function(){ + self.emit('end'); + }); +}; + +/** + * Set content-type based on `path` + * if it hasn't been explicitly set. + * + * @param {String} path + * @api private + */ + +SendStream.prototype.type = function(path){ + var res = this.res; + if (res.getHeader('Content-Type')) return; + var type = mime.lookup(path); + var charset = mime.charsets.lookup(type); + debug('content-type %s', type); + res.setHeader('Content-Type', type + (charset ? '; charset=' + charset : '')); +}; + +/** + * Set reaponse header fields, most + * fields may be pre-defined. + * + * @param {Object} stat + * @api private + */ + +SendStream.prototype.setHeader = function(stat){ + var res = this.res; + if (!res.getHeader('Accept-Ranges')) res.setHeader('Accept-Ranges', 'bytes'); + if (!res.getHeader('ETag')) res.setHeader('ETag', utils.etag(stat)); + if (!res.getHeader('Date')) res.setHeader('Date', new Date().toUTCString()); + if (!res.getHeader('Cache-Control')) res.setHeader('Cache-Control', 'public, max-age=' + (this._maxage / 1000)); + if (!res.getHeader('Last-Modified')) res.setHeader('Last-Modified', stat.mtime.toUTCString()); +}; diff --git a/node_modules/express/node_modules/send/lib/utils.js b/node_modules/express/node_modules/send/lib/utils.js new file mode 100644 index 0000000..950e5a2 --- /dev/null +++ b/node_modules/express/node_modules/send/lib/utils.js @@ -0,0 +1,47 @@ + +/** + * Return an ETag in the form of `"-"` + * from the given `stat`. + * + * @param {Object} stat + * @return {String} + * @api private + */ + +exports.etag = function(stat) { + return '"' + stat.size + '-' + Number(stat.mtime) + '"'; +}; + +/** + * decodeURIComponent. + * + * Allows V8 to only deoptimize this fn instead of all + * of send(). + * + * @param {String} path + * @api private + */ + +exports.decode = function(path){ + try { + return decodeURIComponent(path); + } catch (err) { + return -1; + } +}; + +/** + * Escape the given string of `html`. + * + * @param {String} html + * @return {String} + * @api private + */ + +exports.escape = function(html){ + return String(html) + .replace(/&(?!\w+;)/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +}; \ No newline at end of file diff --git a/node_modules/express/node_modules/send/node_modules/mime/LICENSE b/node_modules/express/node_modules/send/node_modules/mime/LICENSE new file mode 100644 index 0000000..451fc45 --- /dev/null +++ b/node_modules/express/node_modules/send/node_modules/mime/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010 Benjamin Thomas, Robert Kieffer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/express/node_modules/send/node_modules/mime/README.md b/node_modules/express/node_modules/send/node_modules/mime/README.md new file mode 100644 index 0000000..6ca19bd --- /dev/null +++ b/node_modules/express/node_modules/send/node_modules/mime/README.md @@ -0,0 +1,66 @@ +# mime + +Comprehensive MIME type mapping API. Includes all 600+ types and 800+ extensions defined by the Apache project, plus additional types submitted by the node.js community. + +## Install + +Install with [npm](http://github.com/isaacs/npm): + + npm install mime + +## API - Queries + +### mime.lookup(path) +Get the mime type associated with a file, if no mime type is found `application/octet-stream` is returned. Performs a case-insensitive lookup using the extension in `path` (the substring after the last '/' or '.'). E.g. + + var mime = require('mime'); + + mime.lookup('/path/to/file.txt'); // => 'text/plain' + mime.lookup('file.txt'); // => 'text/plain' + mime.lookup('.TXT'); // => 'text/plain' + mime.lookup('htm'); // => 'text/html' + +### mime.default_type +Sets the mime type returned when `mime.lookup` fails to find the extension searched for. (Default is `application/octet-stream`.) + +### mime.extension(type) +Get the default extension for `type` + + mime.extension('text/html'); // => 'html' + mime.extension('application/octet-stream'); // => 'bin' + +### mime.charsets.lookup() + +Map mime-type to charset + + mime.charsets.lookup('text/plain'); // => 'UTF-8' + +(The logic for charset lookups is pretty rudimentary. Feel free to suggest improvements.) + +## API - Defining Custom Types + +The following APIs allow you to add your own type mappings within your project. If you feel a type should be included as part of node-mime, see [requesting new types](https://github.com/broofa/node-mime/wiki/Requesting-New-Types). + +### mime.define() + +Add custom mime/extension mappings + + mime.define({ + 'text/x-some-format': ['x-sf', 'x-sft', 'x-sfml'], + 'application/x-my-type': ['x-mt', 'x-mtt'], + // etc ... + }); + + mime.lookup('x-sft'); // => 'text/x-some-format' + +The first entry in the extensions array is returned by `mime.extension()`. E.g. + + mime.extension('text/x-some-format'); // => 'x-sf' + +### mime.load(filepath) + +Load mappings from an Apache ".types" format file + + mime.load('./my_project.types'); + +The .types file format is simple - See the `types` dir for examples. diff --git a/node_modules/express/node_modules/send/node_modules/mime/mime.js b/node_modules/express/node_modules/send/node_modules/mime/mime.js new file mode 100644 index 0000000..48be0c5 --- /dev/null +++ b/node_modules/express/node_modules/send/node_modules/mime/mime.js @@ -0,0 +1,114 @@ +var path = require('path'); +var fs = require('fs'); + +function Mime() { + // Map of extension -> mime type + this.types = Object.create(null); + + // Map of mime type -> extension + this.extensions = Object.create(null); +} + +/** + * Define mimetype -> extension mappings. Each key is a mime-type that maps + * to an array of extensions associated with the type. The first extension is + * used as the default extension for the type. + * + * e.g. mime.define({'audio/ogg', ['oga', 'ogg', 'spx']}); + * + * @param map (Object) type definitions + */ +Mime.prototype.define = function (map) { + for (var type in map) { + var exts = map[type]; + + for (var i = 0; i < exts.length; i++) { + if (process.env.DEBUG_MIME && this.types[exts]) { + console.warn(this._loading.replace(/.*\//, ''), 'changes "' + exts[i] + '" extension type from ' + + this.types[exts] + ' to ' + type); + } + + this.types[exts[i]] = type; + } + + // Default extension is the first one we encounter + if (!this.extensions[type]) { + this.extensions[type] = exts[0]; + } + } +}; + +/** + * Load an Apache2-style ".types" file + * + * This may be called multiple times (it's expected). Where files declare + * overlapping types/extensions, the last file wins. + * + * @param file (String) path of file to load. + */ +Mime.prototype.load = function(file) { + + this._loading = file; + // Read file and split into lines + var map = {}, + content = fs.readFileSync(file, 'ascii'), + lines = content.split(/[\r\n]+/); + + lines.forEach(function(line) { + // Clean up whitespace/comments, and split into fields + var fields = line.replace(/\s*#.*|^\s*|\s*$/g, '').split(/\s+/); + map[fields.shift()] = fields; + }); + + this.define(map); + + this._loading = null; +}; + +/** + * Lookup a mime type based on extension + */ +Mime.prototype.lookup = function(path, fallback) { + var ext = path.replace(/.*[\.\/\\]/, '').toLowerCase(); + + return this.types[ext] || fallback || this.default_type; +}; + +/** + * Return file extension associated with a mime type + */ +Mime.prototype.extension = function(mimeType) { + var type = mimeType.match(/^\s*([^;\s]*)(?:;|\s|$)/)[1].toLowerCase(); + return this.extensions[type]; +}; + +// Default instance +var mime = new Mime(); + +// Load local copy of +// http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types +mime.load(path.join(__dirname, 'types/mime.types')); + +// Load additional types from node.js community +mime.load(path.join(__dirname, 'types/node.types')); + +// Default type +mime.default_type = mime.lookup('bin'); + +// +// Additional API specific to the default instance +// + +mime.Mime = Mime; + +/** + * Lookup a charset based on mime type. + */ +mime.charsets = { + lookup: function(mimeType, fallback) { + // Assume text types are utf8 + return (/^text\//).test(mimeType) ? 'UTF-8' : fallback; + } +}; + +module.exports = mime; diff --git a/node_modules/express/node_modules/send/node_modules/mime/package.json b/node_modules/express/node_modules/send/node_modules/mime/package.json new file mode 100644 index 0000000..95098da --- /dev/null +++ b/node_modules/express/node_modules/send/node_modules/mime/package.json @@ -0,0 +1,39 @@ +{ + "author": { + "name": "Robert Kieffer", + "email": "robert@broofa.com", + "url": "http://github.com/broofa" + }, + "contributors": [ + { + "name": "Benjamin Thomas", + "email": "benjamin@benjaminthomas.org", + "url": "http://github.com/bentomas" + } + ], + "dependencies": {}, + "description": "A comprehensive library for mime-type mapping", + "devDependencies": {}, + "keywords": [ + "util", + "mime" + ], + "main": "mime.js", + "name": "mime", + "repository": { + "url": "https://github.com/broofa/node-mime", + "type": "git" + }, + "version": "1.2.11", + "readme": "# mime\n\nComprehensive MIME type mapping API. Includes all 600+ types and 800+ extensions defined by the Apache project, plus additional types submitted by the node.js community.\n\n## Install\n\nInstall with [npm](http://github.com/isaacs/npm):\n\n npm install mime\n\n## API - Queries\n\n### mime.lookup(path)\nGet the mime type associated with a file, if no mime type is found `application/octet-stream` is returned. Performs a case-insensitive lookup using the extension in `path` (the substring after the last '/' or '.'). E.g.\n\n var mime = require('mime');\n\n mime.lookup('/path/to/file.txt'); // => 'text/plain'\n mime.lookup('file.txt'); // => 'text/plain'\n mime.lookup('.TXT'); // => 'text/plain'\n mime.lookup('htm'); // => 'text/html'\n\n### mime.default_type\nSets the mime type returned when `mime.lookup` fails to find the extension searched for. (Default is `application/octet-stream`.)\n\n### mime.extension(type)\nGet the default extension for `type`\n\n mime.extension('text/html'); // => 'html'\n mime.extension('application/octet-stream'); // => 'bin'\n\n### mime.charsets.lookup()\n\nMap mime-type to charset\n\n mime.charsets.lookup('text/plain'); // => 'UTF-8'\n\n(The logic for charset lookups is pretty rudimentary. Feel free to suggest improvements.)\n\n## API - Defining Custom Types\n\nThe following APIs allow you to add your own type mappings within your project. If you feel a type should be included as part of node-mime, see [requesting new types](https://github.com/broofa/node-mime/wiki/Requesting-New-Types).\n\n### mime.define()\n\nAdd custom mime/extension mappings\n\n mime.define({\n 'text/x-some-format': ['x-sf', 'x-sft', 'x-sfml'],\n 'application/x-my-type': ['x-mt', 'x-mtt'],\n // etc ...\n });\n\n mime.lookup('x-sft'); // => 'text/x-some-format'\n\nThe first entry in the extensions array is returned by `mime.extension()`. E.g.\n\n mime.extension('text/x-some-format'); // => 'x-sf'\n\n### mime.load(filepath)\n\nLoad mappings from an Apache \".types\" format file\n\n mime.load('./my_project.types');\n\nThe .types file format is simple - See the `types` dir for examples.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/broofa/node-mime/issues" + }, + "_id": "mime@1.2.11", + "dist": { + "shasum": "3d67fcb4feb09a8a2092769b70d590622f92f36c" + }, + "_from": "mime@~1.2.9", + "_resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz" +} diff --git a/node_modules/express/node_modules/send/node_modules/mime/test.js b/node_modules/express/node_modules/send/node_modules/mime/test.js new file mode 100644 index 0000000..2cda1c7 --- /dev/null +++ b/node_modules/express/node_modules/send/node_modules/mime/test.js @@ -0,0 +1,84 @@ +/** + * Usage: node test.js + */ + +var mime = require('./mime'); +var assert = require('assert'); +var path = require('path'); + +function eq(a, b) { + console.log('Test: ' + a + ' === ' + b); + assert.strictEqual.apply(null, arguments); +} + +console.log(Object.keys(mime.extensions).length + ' types'); +console.log(Object.keys(mime.types).length + ' extensions\n'); + +// +// Test mime lookups +// + +eq('text/plain', mime.lookup('text.txt')); // normal file +eq('text/plain', mime.lookup('TEXT.TXT')); // uppercase +eq('text/plain', mime.lookup('dir/text.txt')); // dir + file +eq('text/plain', mime.lookup('.text.txt')); // hidden file +eq('text/plain', mime.lookup('.txt')); // nameless +eq('text/plain', mime.lookup('txt')); // extension-only +eq('text/plain', mime.lookup('/txt')); // extension-less () +eq('text/plain', mime.lookup('\\txt')); // Windows, extension-less +eq('application/octet-stream', mime.lookup('text.nope')); // unrecognized +eq('fallback', mime.lookup('text.fallback', 'fallback')); // alternate default + +// +// Test extensions +// + +eq('txt', mime.extension(mime.types.text)); +eq('html', mime.extension(mime.types.htm)); +eq('bin', mime.extension('application/octet-stream')); +eq('bin', mime.extension('application/octet-stream ')); +eq('html', mime.extension(' text/html; charset=UTF-8')); +eq('html', mime.extension('text/html; charset=UTF-8 ')); +eq('html', mime.extension('text/html; charset=UTF-8')); +eq('html', mime.extension('text/html ; charset=UTF-8')); +eq('html', mime.extension('text/html;charset=UTF-8')); +eq('html', mime.extension('text/Html;charset=UTF-8')); +eq(undefined, mime.extension('unrecognized')); + +// +// Test node.types lookups +// + +eq('application/font-woff', mime.lookup('file.woff')); +eq('application/octet-stream', mime.lookup('file.buffer')); +eq('audio/mp4', mime.lookup('file.m4a')); +eq('font/opentype', mime.lookup('file.otf')); + +// +// Test charsets +// + +eq('UTF-8', mime.charsets.lookup('text/plain')); +eq(undefined, mime.charsets.lookup(mime.types.js)); +eq('fallback', mime.charsets.lookup('application/octet-stream', 'fallback')); + +// +// Test for overlaps between mime.types and node.types +// + +var apacheTypes = new mime.Mime(), nodeTypes = new mime.Mime(); +apacheTypes.load(path.join(__dirname, 'types/mime.types')); +nodeTypes.load(path.join(__dirname, 'types/node.types')); + +var keys = [].concat(Object.keys(apacheTypes.types)) + .concat(Object.keys(nodeTypes.types)); +keys.sort(); +for (var i = 1; i < keys.length; i++) { + if (keys[i] == keys[i-1]) { + console.warn('Warning: ' + + 'node.types defines ' + keys[i] + '->' + nodeTypes.types[keys[i]] + + ', mime.types defines ' + keys[i] + '->' + apacheTypes.types[keys[i]]); + } +} + +console.log('\nOK'); diff --git a/node_modules/express/node_modules/send/node_modules/mime/types/mime.types b/node_modules/express/node_modules/send/node_modules/mime/types/mime.types new file mode 100644 index 0000000..da8cd69 --- /dev/null +++ b/node_modules/express/node_modules/send/node_modules/mime/types/mime.types @@ -0,0 +1,1588 @@ +# This file maps Internet media types to unique file extension(s). +# Although created for httpd, this file is used by many software systems +# and has been placed in the public domain for unlimited redisribution. +# +# The table below contains both registered and (common) unregistered types. +# A type that has no unique extension can be ignored -- they are listed +# here to guide configurations toward known types and to make it easier to +# identify "new" types. File extensions are also commonly used to indicate +# content languages and encodings, so choose them carefully. +# +# Internet media types should be registered as described in RFC 4288. +# The registry is at . +# +# MIME type (lowercased) Extensions +# ============================================ ========== +# application/1d-interleaved-parityfec +# application/3gpp-ims+xml +# application/activemessage +application/andrew-inset ez +# application/applefile +application/applixware aw +application/atom+xml atom +application/atomcat+xml atomcat +# application/atomicmail +application/atomsvc+xml atomsvc +# application/auth-policy+xml +# application/batch-smtp +# application/beep+xml +# application/calendar+xml +# application/cals-1840 +# application/ccmp+xml +application/ccxml+xml ccxml +application/cdmi-capability cdmia +application/cdmi-container cdmic +application/cdmi-domain cdmid +application/cdmi-object cdmio +application/cdmi-queue cdmiq +# application/cea-2018+xml +# application/cellml+xml +# application/cfw +# application/cnrp+xml +# application/commonground +# application/conference-info+xml +# application/cpl+xml +# application/csta+xml +# application/cstadata+xml +application/cu-seeme cu +# application/cybercash +application/davmount+xml davmount +# application/dca-rft +# application/dec-dx +# application/dialog-info+xml +# application/dicom +# application/dns +application/docbook+xml dbk +# application/dskpp+xml +application/dssc+der dssc +application/dssc+xml xdssc +# application/dvcs +application/ecmascript ecma +# application/edi-consent +# application/edi-x12 +# application/edifact +application/emma+xml emma +# application/epp+xml +application/epub+zip epub +# application/eshop +# application/example +application/exi exi +# application/fastinfoset +# application/fastsoap +# application/fits +application/font-tdpfr pfr +# application/framework-attributes+xml +application/gml+xml gml +application/gpx+xml gpx +application/gxf gxf +# application/h224 +# application/held+xml +# application/http +application/hyperstudio stk +# application/ibe-key-request+xml +# application/ibe-pkg-reply+xml +# application/ibe-pp-data +# application/iges +# application/im-iscomposing+xml +# application/index +# application/index.cmd +# application/index.obj +# application/index.response +# application/index.vnd +application/inkml+xml ink inkml +# application/iotp +application/ipfix ipfix +# application/ipp +# application/isup +application/java-archive jar +application/java-serialized-object ser +application/java-vm class +application/javascript js +application/json json +application/jsonml+json jsonml +# application/kpml-request+xml +# application/kpml-response+xml +application/lost+xml lostxml +application/mac-binhex40 hqx +application/mac-compactpro cpt +# application/macwriteii +application/mads+xml mads +application/marc mrc +application/marcxml+xml mrcx +application/mathematica ma nb mb +# application/mathml-content+xml +# application/mathml-presentation+xml +application/mathml+xml mathml +# application/mbms-associated-procedure-description+xml +# application/mbms-deregister+xml +# application/mbms-envelope+xml +# application/mbms-msk+xml +# application/mbms-msk-response+xml +# application/mbms-protection-description+xml +# application/mbms-reception-report+xml +# application/mbms-register+xml +# application/mbms-register-response+xml +# application/mbms-user-service-description+xml +application/mbox mbox +# application/media_control+xml +application/mediaservercontrol+xml mscml +application/metalink+xml metalink +application/metalink4+xml meta4 +application/mets+xml mets +# application/mikey +application/mods+xml mods +# application/moss-keys +# application/moss-signature +# application/mosskey-data +# application/mosskey-request +application/mp21 m21 mp21 +application/mp4 mp4s +# application/mpeg4-generic +# application/mpeg4-iod +# application/mpeg4-iod-xmt +# application/msc-ivr+xml +# application/msc-mixer+xml +application/msword doc dot +application/mxf mxf +# application/nasdata +# application/news-checkgroups +# application/news-groupinfo +# application/news-transmission +# application/nss +# application/ocsp-request +# application/ocsp-response +application/octet-stream bin dms lrf mar so dist distz pkg bpk dump elc deploy +application/oda oda +application/oebps-package+xml opf +application/ogg ogx +application/omdoc+xml omdoc +application/onenote onetoc onetoc2 onetmp onepkg +application/oxps oxps +# application/parityfec +application/patch-ops-error+xml xer +application/pdf pdf +application/pgp-encrypted pgp +# application/pgp-keys +application/pgp-signature asc sig +application/pics-rules prf +# application/pidf+xml +# application/pidf-diff+xml +application/pkcs10 p10 +application/pkcs7-mime p7m p7c +application/pkcs7-signature p7s +application/pkcs8 p8 +application/pkix-attr-cert ac +application/pkix-cert cer +application/pkix-crl crl +application/pkix-pkipath pkipath +application/pkixcmp pki +application/pls+xml pls +# application/poc-settings+xml +application/postscript ai eps ps +# application/prs.alvestrand.titrax-sheet +application/prs.cww cww +# application/prs.nprend +# application/prs.plucker +# application/prs.rdf-xml-crypt +# application/prs.xsf+xml +application/pskc+xml pskcxml +# application/qsig +application/rdf+xml rdf +application/reginfo+xml rif +application/relax-ng-compact-syntax rnc +# application/remote-printing +application/resource-lists+xml rl +application/resource-lists-diff+xml rld +# application/riscos +# application/rlmi+xml +application/rls-services+xml rs +application/rpki-ghostbusters gbr +application/rpki-manifest mft +application/rpki-roa roa +# application/rpki-updown +application/rsd+xml rsd +application/rss+xml rss +application/rtf rtf +# application/rtx +# application/samlassertion+xml +# application/samlmetadata+xml +application/sbml+xml sbml +application/scvp-cv-request scq +application/scvp-cv-response scs +application/scvp-vp-request spq +application/scvp-vp-response spp +application/sdp sdp +# application/set-payment +application/set-payment-initiation setpay +# application/set-registration +application/set-registration-initiation setreg +# application/sgml +# application/sgml-open-catalog +application/shf+xml shf +# application/sieve +# application/simple-filter+xml +# application/simple-message-summary +# application/simplesymbolcontainer +# application/slate +# application/smil +application/smil+xml smi smil +# application/soap+fastinfoset +# application/soap+xml +application/sparql-query rq +application/sparql-results+xml srx +# application/spirits-event+xml +application/srgs gram +application/srgs+xml grxml +application/sru+xml sru +application/ssdl+xml ssdl +application/ssml+xml ssml +# application/tamp-apex-update +# application/tamp-apex-update-confirm +# application/tamp-community-update +# application/tamp-community-update-confirm +# application/tamp-error +# application/tamp-sequence-adjust +# application/tamp-sequence-adjust-confirm +# application/tamp-status-query +# application/tamp-status-response +# application/tamp-update +# application/tamp-update-confirm +application/tei+xml tei teicorpus +application/thraud+xml tfi +# application/timestamp-query +# application/timestamp-reply +application/timestamped-data tsd +# application/tve-trigger +# application/ulpfec +# application/vcard+xml +# application/vemmi +# application/vividence.scriptfile +# application/vnd.3gpp.bsf+xml +application/vnd.3gpp.pic-bw-large plb +application/vnd.3gpp.pic-bw-small psb +application/vnd.3gpp.pic-bw-var pvb +# application/vnd.3gpp.sms +# application/vnd.3gpp2.bcmcsinfo+xml +# application/vnd.3gpp2.sms +application/vnd.3gpp2.tcap tcap +application/vnd.3m.post-it-notes pwn +application/vnd.accpac.simply.aso aso +application/vnd.accpac.simply.imp imp +application/vnd.acucobol acu +application/vnd.acucorp atc acutc +application/vnd.adobe.air-application-installer-package+zip air +application/vnd.adobe.formscentral.fcdt fcdt +application/vnd.adobe.fxp fxp fxpl +# application/vnd.adobe.partial-upload +application/vnd.adobe.xdp+xml xdp +application/vnd.adobe.xfdf xfdf +# application/vnd.aether.imp +# application/vnd.ah-barcode +application/vnd.ahead.space ahead +application/vnd.airzip.filesecure.azf azf +application/vnd.airzip.filesecure.azs azs +application/vnd.amazon.ebook azw +application/vnd.americandynamics.acc acc +application/vnd.amiga.ami ami +# application/vnd.amundsen.maze+xml +application/vnd.android.package-archive apk +application/vnd.anser-web-certificate-issue-initiation cii +application/vnd.anser-web-funds-transfer-initiation fti +application/vnd.antix.game-component atx +application/vnd.apple.installer+xml mpkg +application/vnd.apple.mpegurl m3u8 +# application/vnd.arastra.swi +application/vnd.aristanetworks.swi swi +application/vnd.astraea-software.iota iota +application/vnd.audiograph aep +# application/vnd.autopackage +# application/vnd.avistar+xml +application/vnd.blueice.multipass mpm +# application/vnd.bluetooth.ep.oob +application/vnd.bmi bmi +application/vnd.businessobjects rep +# application/vnd.cab-jscript +# application/vnd.canon-cpdl +# application/vnd.canon-lips +# application/vnd.cendio.thinlinc.clientconf +application/vnd.chemdraw+xml cdxml +application/vnd.chipnuts.karaoke-mmd mmd +application/vnd.cinderella cdy +# application/vnd.cirpack.isdn-ext +application/vnd.claymore cla +application/vnd.cloanto.rp9 rp9 +application/vnd.clonk.c4group c4g c4d c4f c4p c4u +application/vnd.cluetrust.cartomobile-config c11amc +application/vnd.cluetrust.cartomobile-config-pkg c11amz +# application/vnd.collection+json +# application/vnd.commerce-battelle +application/vnd.commonspace csp +application/vnd.contact.cmsg cdbcmsg +application/vnd.cosmocaller cmc +application/vnd.crick.clicker clkx +application/vnd.crick.clicker.keyboard clkk +application/vnd.crick.clicker.palette clkp +application/vnd.crick.clicker.template clkt +application/vnd.crick.clicker.wordbank clkw +application/vnd.criticaltools.wbs+xml wbs +application/vnd.ctc-posml pml +# application/vnd.ctct.ws+xml +# application/vnd.cups-pdf +# application/vnd.cups-postscript +application/vnd.cups-ppd ppd +# application/vnd.cups-raster +# application/vnd.cups-raw +# application/vnd.curl +application/vnd.curl.car car +application/vnd.curl.pcurl pcurl +# application/vnd.cybank +application/vnd.dart dart +application/vnd.data-vision.rdz rdz +application/vnd.dece.data uvf uvvf uvd uvvd +application/vnd.dece.ttml+xml uvt uvvt +application/vnd.dece.unspecified uvx uvvx +application/vnd.dece.zip uvz uvvz +application/vnd.denovo.fcselayout-link fe_launch +# application/vnd.dir-bi.plate-dl-nosuffix +application/vnd.dna dna +application/vnd.dolby.mlp mlp +# application/vnd.dolby.mobile.1 +# application/vnd.dolby.mobile.2 +application/vnd.dpgraph dpg +application/vnd.dreamfactory dfac +application/vnd.ds-keypoint kpxx +application/vnd.dvb.ait ait +# application/vnd.dvb.dvbj +# application/vnd.dvb.esgcontainer +# application/vnd.dvb.ipdcdftnotifaccess +# application/vnd.dvb.ipdcesgaccess +# application/vnd.dvb.ipdcesgaccess2 +# application/vnd.dvb.ipdcesgpdd +# application/vnd.dvb.ipdcroaming +# application/vnd.dvb.iptv.alfec-base +# application/vnd.dvb.iptv.alfec-enhancement +# application/vnd.dvb.notif-aggregate-root+xml +# application/vnd.dvb.notif-container+xml +# application/vnd.dvb.notif-generic+xml +# application/vnd.dvb.notif-ia-msglist+xml +# application/vnd.dvb.notif-ia-registration-request+xml +# application/vnd.dvb.notif-ia-registration-response+xml +# application/vnd.dvb.notif-init+xml +# application/vnd.dvb.pfr +application/vnd.dvb.service svc +# application/vnd.dxr +application/vnd.dynageo geo +# application/vnd.easykaraoke.cdgdownload +# application/vnd.ecdis-update +application/vnd.ecowin.chart mag +# application/vnd.ecowin.filerequest +# application/vnd.ecowin.fileupdate +# application/vnd.ecowin.series +# application/vnd.ecowin.seriesrequest +# application/vnd.ecowin.seriesupdate +# application/vnd.emclient.accessrequest+xml +application/vnd.enliven nml +# application/vnd.eprints.data+xml +application/vnd.epson.esf esf +application/vnd.epson.msf msf +application/vnd.epson.quickanime qam +application/vnd.epson.salt slt +application/vnd.epson.ssf ssf +# application/vnd.ericsson.quickcall +application/vnd.eszigno3+xml es3 et3 +# application/vnd.etsi.aoc+xml +# application/vnd.etsi.cug+xml +# application/vnd.etsi.iptvcommand+xml +# application/vnd.etsi.iptvdiscovery+xml +# application/vnd.etsi.iptvprofile+xml +# application/vnd.etsi.iptvsad-bc+xml +# application/vnd.etsi.iptvsad-cod+xml +# application/vnd.etsi.iptvsad-npvr+xml +# application/vnd.etsi.iptvservice+xml +# application/vnd.etsi.iptvsync+xml +# application/vnd.etsi.iptvueprofile+xml +# application/vnd.etsi.mcid+xml +# application/vnd.etsi.overload-control-policy-dataset+xml +# application/vnd.etsi.sci+xml +# application/vnd.etsi.simservs+xml +# application/vnd.etsi.tsl+xml +# application/vnd.etsi.tsl.der +# application/vnd.eudora.data +application/vnd.ezpix-album ez2 +application/vnd.ezpix-package ez3 +# application/vnd.f-secure.mobile +application/vnd.fdf fdf +application/vnd.fdsn.mseed mseed +application/vnd.fdsn.seed seed dataless +# application/vnd.ffsns +# application/vnd.fints +application/vnd.flographit gph +application/vnd.fluxtime.clip ftc +# application/vnd.font-fontforge-sfd +application/vnd.framemaker fm frame maker book +application/vnd.frogans.fnc fnc +application/vnd.frogans.ltf ltf +application/vnd.fsc.weblaunch fsc +application/vnd.fujitsu.oasys oas +application/vnd.fujitsu.oasys2 oa2 +application/vnd.fujitsu.oasys3 oa3 +application/vnd.fujitsu.oasysgp fg5 +application/vnd.fujitsu.oasysprs bh2 +# application/vnd.fujixerox.art-ex +# application/vnd.fujixerox.art4 +# application/vnd.fujixerox.hbpl +application/vnd.fujixerox.ddd ddd +application/vnd.fujixerox.docuworks xdw +application/vnd.fujixerox.docuworks.binder xbd +# application/vnd.fut-misnet +application/vnd.fuzzysheet fzs +application/vnd.genomatix.tuxedo txd +# application/vnd.geocube+xml +application/vnd.geogebra.file ggb +application/vnd.geogebra.tool ggt +application/vnd.geometry-explorer gex gre +application/vnd.geonext gxt +application/vnd.geoplan g2w +application/vnd.geospace g3w +# application/vnd.globalplatform.card-content-mgt +# application/vnd.globalplatform.card-content-mgt-response +application/vnd.gmx gmx +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.grafeq gqf gqs +# application/vnd.gridmp +application/vnd.groove-account gac +application/vnd.groove-help ghf +application/vnd.groove-identity-message gim +application/vnd.groove-injector grv +application/vnd.groove-tool-message gtm +application/vnd.groove-tool-template tpl +application/vnd.groove-vcard vcg +# application/vnd.hal+json +application/vnd.hal+xml hal +application/vnd.handheld-entertainment+xml zmm +application/vnd.hbci hbci +# application/vnd.hcl-bireports +application/vnd.hhe.lesson-player les +application/vnd.hp-hpgl hpgl +application/vnd.hp-hpid hpid +application/vnd.hp-hps hps +application/vnd.hp-jlyt jlt +application/vnd.hp-pcl pcl +application/vnd.hp-pclxl pclxl +# application/vnd.httphone +application/vnd.hydrostatix.sof-data sfd-hdstx +# application/vnd.hzn-3d-crossword +# application/vnd.ibm.afplinedata +# application/vnd.ibm.electronic-media +application/vnd.ibm.minipay mpy +application/vnd.ibm.modcap afp listafp list3820 +application/vnd.ibm.rights-management irm +application/vnd.ibm.secure-container sc +application/vnd.iccprofile icc icm +application/vnd.igloader igl +application/vnd.immervision-ivp ivp +application/vnd.immervision-ivu ivu +# application/vnd.informedcontrol.rms+xml +# application/vnd.informix-visionary +# application/vnd.infotech.project +# application/vnd.infotech.project+xml +# application/vnd.innopath.wamp.notification +application/vnd.insors.igm igm +application/vnd.intercon.formnet xpw xpx +application/vnd.intergeo i2g +# application/vnd.intertrust.digibox +# application/vnd.intertrust.nncp +application/vnd.intu.qbo qbo +application/vnd.intu.qfx qfx +# application/vnd.iptc.g2.conceptitem+xml +# application/vnd.iptc.g2.knowledgeitem+xml +# application/vnd.iptc.g2.newsitem+xml +# application/vnd.iptc.g2.newsmessage+xml +# application/vnd.iptc.g2.packageitem+xml +# application/vnd.iptc.g2.planningitem+xml +application/vnd.ipunplugged.rcprofile rcprofile +application/vnd.irepository.package+xml irp +application/vnd.is-xpr xpr +application/vnd.isac.fcs fcs +application/vnd.jam jam +# application/vnd.japannet-directory-service +# application/vnd.japannet-jpnstore-wakeup +# application/vnd.japannet-payment-wakeup +# application/vnd.japannet-registration +# application/vnd.japannet-registration-wakeup +# application/vnd.japannet-setstore-wakeup +# application/vnd.japannet-verification +# application/vnd.japannet-verification-wakeup +application/vnd.jcp.javame.midlet-rms rms +application/vnd.jisp jisp +application/vnd.joost.joda-archive joda +application/vnd.kahootz ktz ktr +application/vnd.kde.karbon karbon +application/vnd.kde.kchart chrt +application/vnd.kde.kformula kfo +application/vnd.kde.kivio flw +application/vnd.kde.kontour kon +application/vnd.kde.kpresenter kpr kpt +application/vnd.kde.kspread ksp +application/vnd.kde.kword kwd kwt +application/vnd.kenameaapp htke +application/vnd.kidspiration kia +application/vnd.kinar kne knp +application/vnd.koan skp skd skt skm +application/vnd.kodak-descriptor sse +application/vnd.las.las+xml lasxml +# application/vnd.liberty-request+xml +application/vnd.llamagraphics.life-balance.desktop lbd +application/vnd.llamagraphics.life-balance.exchange+xml lbe +application/vnd.lotus-1-2-3 123 +application/vnd.lotus-approach apr +application/vnd.lotus-freelance pre +application/vnd.lotus-notes nsf +application/vnd.lotus-organizer org +application/vnd.lotus-screencam scm +application/vnd.lotus-wordpro lwp +application/vnd.macports.portpkg portpkg +# application/vnd.marlin.drm.actiontoken+xml +# application/vnd.marlin.drm.conftoken+xml +# application/vnd.marlin.drm.license+xml +# application/vnd.marlin.drm.mdcf +application/vnd.mcd mcd +application/vnd.medcalcdata mc1 +application/vnd.mediastation.cdkey cdkey +# application/vnd.meridian-slingshot +application/vnd.mfer mwf +application/vnd.mfmp mfm +application/vnd.micrografx.flo flo +application/vnd.micrografx.igx igx +application/vnd.mif mif +# application/vnd.minisoft-hp3000-save +# application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.mobius.daf daf +application/vnd.mobius.dis dis +application/vnd.mobius.mbk mbk +application/vnd.mobius.mqy mqy +application/vnd.mobius.msl msl +application/vnd.mobius.plc plc +application/vnd.mobius.txf txf +application/vnd.mophun.application mpn +application/vnd.mophun.certificate mpc +# application/vnd.motorola.flexsuite +# application/vnd.motorola.flexsuite.adsi +# application/vnd.motorola.flexsuite.fis +# application/vnd.motorola.flexsuite.gotap +# application/vnd.motorola.flexsuite.kmr +# application/vnd.motorola.flexsuite.ttc +# application/vnd.motorola.flexsuite.wem +# application/vnd.motorola.iprm +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry cil +# application/vnd.ms-asf +application/vnd.ms-cab-compressed cab +# application/vnd.ms-color.iccprofile +application/vnd.ms-excel xls xlm xla xlc xlt xlw +application/vnd.ms-excel.addin.macroenabled.12 xlam +application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb +application/vnd.ms-excel.sheet.macroenabled.12 xlsm +application/vnd.ms-excel.template.macroenabled.12 xltm +application/vnd.ms-fontobject eot +application/vnd.ms-htmlhelp chm +application/vnd.ms-ims ims +application/vnd.ms-lrm lrm +# application/vnd.ms-office.activex+xml +application/vnd.ms-officetheme thmx +# application/vnd.ms-opentype +# application/vnd.ms-package.obfuscated-opentype +application/vnd.ms-pki.seccat cat +application/vnd.ms-pki.stl stl +# application/vnd.ms-playready.initiator+xml +application/vnd.ms-powerpoint ppt pps pot +application/vnd.ms-powerpoint.addin.macroenabled.12 ppam +application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm +application/vnd.ms-powerpoint.slide.macroenabled.12 sldm +application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm +application/vnd.ms-powerpoint.template.macroenabled.12 potm +# application/vnd.ms-printing.printticket+xml +application/vnd.ms-project mpp mpt +# application/vnd.ms-tnef +# application/vnd.ms-wmdrm.lic-chlg-req +# application/vnd.ms-wmdrm.lic-resp +# application/vnd.ms-wmdrm.meter-chlg-req +# application/vnd.ms-wmdrm.meter-resp +application/vnd.ms-word.document.macroenabled.12 docm +application/vnd.ms-word.template.macroenabled.12 dotm +application/vnd.ms-works wps wks wcm wdb +application/vnd.ms-wpl wpl +application/vnd.ms-xpsdocument xps +application/vnd.mseq mseq +# application/vnd.msign +# application/vnd.multiad.creator +# application/vnd.multiad.creator.cif +# application/vnd.music-niff +application/vnd.musician mus +application/vnd.muvee.style msty +application/vnd.mynfc taglet +# application/vnd.ncd.control +# application/vnd.ncd.reference +# application/vnd.nervana +# application/vnd.netfpx +application/vnd.neurolanguage.nlu nlu +application/vnd.nitf ntf nitf +application/vnd.noblenet-directory nnd +application/vnd.noblenet-sealer nns +application/vnd.noblenet-web nnw +# application/vnd.nokia.catalogs +# application/vnd.nokia.conml+wbxml +# application/vnd.nokia.conml+xml +# application/vnd.nokia.isds-radio-presets +# application/vnd.nokia.iptv.config+xml +# application/vnd.nokia.landmark+wbxml +# application/vnd.nokia.landmark+xml +# application/vnd.nokia.landmarkcollection+xml +# application/vnd.nokia.n-gage.ac+xml +application/vnd.nokia.n-gage.data ngdat +application/vnd.nokia.n-gage.symbian.install n-gage +# application/vnd.nokia.ncd +# application/vnd.nokia.pcd+wbxml +# application/vnd.nokia.pcd+xml +application/vnd.nokia.radio-preset rpst +application/vnd.nokia.radio-presets rpss +application/vnd.novadigm.edm edm +application/vnd.novadigm.edx edx +application/vnd.novadigm.ext ext +# application/vnd.ntt-local.file-transfer +# application/vnd.ntt-local.sip-ta_remote +# application/vnd.ntt-local.sip-ta_tcp_stream +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.chart-template otc +application/vnd.oasis.opendocument.database odb +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.formula-template odft +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.image-template oti +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master odm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +# application/vnd.obn +# application/vnd.oftn.l10n+json +# application/vnd.oipf.contentaccessdownload+xml +# application/vnd.oipf.contentaccessstreaming+xml +# application/vnd.oipf.cspg-hexbinary +# application/vnd.oipf.dae.svg+xml +# application/vnd.oipf.dae.xhtml+xml +# application/vnd.oipf.mippvcontrolmessage+xml +# application/vnd.oipf.pae.gem +# application/vnd.oipf.spdiscovery+xml +# application/vnd.oipf.spdlist+xml +# application/vnd.oipf.ueprofile+xml +# application/vnd.oipf.userprofile+xml +application/vnd.olpc-sugar xo +# application/vnd.oma-scws-config +# application/vnd.oma-scws-http-request +# application/vnd.oma-scws-http-response +# application/vnd.oma.bcast.associated-procedure-parameter+xml +# application/vnd.oma.bcast.drm-trigger+xml +# application/vnd.oma.bcast.imd+xml +# application/vnd.oma.bcast.ltkm +# application/vnd.oma.bcast.notification+xml +# application/vnd.oma.bcast.provisioningtrigger +# application/vnd.oma.bcast.sgboot +# application/vnd.oma.bcast.sgdd+xml +# application/vnd.oma.bcast.sgdu +# application/vnd.oma.bcast.simple-symbol-container +# application/vnd.oma.bcast.smartcard-trigger+xml +# application/vnd.oma.bcast.sprov+xml +# application/vnd.oma.bcast.stkm +# application/vnd.oma.cab-address-book+xml +# application/vnd.oma.cab-feature-handler+xml +# application/vnd.oma.cab-pcc+xml +# application/vnd.oma.cab-user-prefs+xml +# application/vnd.oma.dcd +# application/vnd.oma.dcdc +application/vnd.oma.dd2+xml dd2 +# application/vnd.oma.drm.risd+xml +# application/vnd.oma.group-usage-list+xml +# application/vnd.oma.pal+xml +# application/vnd.oma.poc.detailed-progress-report+xml +# application/vnd.oma.poc.final-report+xml +# application/vnd.oma.poc.groups+xml +# application/vnd.oma.poc.invocation-descriptor+xml +# application/vnd.oma.poc.optimized-progress-report+xml +# application/vnd.oma.push +# application/vnd.oma.scidm.messages+xml +# application/vnd.oma.xcap-directory+xml +# application/vnd.omads-email+xml +# application/vnd.omads-file+xml +# application/vnd.omads-folder+xml +# application/vnd.omaloc-supl-init +application/vnd.openofficeorg.extension oxt +# application/vnd.openxmlformats-officedocument.custom-properties+xml +# application/vnd.openxmlformats-officedocument.customxmlproperties+xml +# application/vnd.openxmlformats-officedocument.drawing+xml +# application/vnd.openxmlformats-officedocument.drawingml.chart+xml +# application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml +# application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml +# application/vnd.openxmlformats-officedocument.extended-properties+xml +# application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml +# application/vnd.openxmlformats-officedocument.presentationml.comments+xml +# application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml +# application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml +# application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml +application/vnd.openxmlformats-officedocument.presentationml.presentation pptx +# application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.presprops+xml +application/vnd.openxmlformats-officedocument.presentationml.slide sldx +# application/vnd.openxmlformats-officedocument.presentationml.slide+xml +# application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml +# application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml +application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx +# application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml +# application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml +# application/vnd.openxmlformats-officedocument.presentationml.tags+xml +application/vnd.openxmlformats-officedocument.presentationml.template potx +# application/vnd.openxmlformats-officedocument.presentationml.template.main+xml +# application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx +# application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml +application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx +# application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml +# application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml +# application/vnd.openxmlformats-officedocument.theme+xml +# application/vnd.openxmlformats-officedocument.themeoverride+xml +# application/vnd.openxmlformats-officedocument.vmldrawing +# application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.document docx +# application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml +application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx +# application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml +# application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml +# application/vnd.openxmlformats-package.core-properties+xml +# application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml +# application/vnd.openxmlformats-package.relationships+xml +# application/vnd.quobject-quoxdocument +# application/vnd.osa.netdeploy +application/vnd.osgeo.mapguide.package mgp +# application/vnd.osgi.bundle +application/vnd.osgi.dp dp +application/vnd.osgi.subsystem esa +# application/vnd.otps.ct-kip+xml +application/vnd.palm pdb pqa oprc +# application/vnd.paos.xml +application/vnd.pawaafile paw +application/vnd.pg.format str +application/vnd.pg.osasli ei6 +# application/vnd.piaccess.application-licence +application/vnd.picsel efif +application/vnd.pmi.widget wg +# application/vnd.poc.group-advertisement+xml +application/vnd.pocketlearn plf +application/vnd.powerbuilder6 pbd +# application/vnd.powerbuilder6-s +# application/vnd.powerbuilder7 +# application/vnd.powerbuilder7-s +# application/vnd.powerbuilder75 +# application/vnd.powerbuilder75-s +# application/vnd.preminet +application/vnd.previewsystems.box box +application/vnd.proteus.magazine mgz +application/vnd.publishare-delta-tree qps +application/vnd.pvi.ptid1 ptid +# application/vnd.pwg-multiplexed +# application/vnd.pwg-xhtml-print+xml +# application/vnd.qualcomm.brew-app-res +application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb +# application/vnd.radisys.moml+xml +# application/vnd.radisys.msml+xml +# application/vnd.radisys.msml-audit+xml +# application/vnd.radisys.msml-audit-conf+xml +# application/vnd.radisys.msml-audit-conn+xml +# application/vnd.radisys.msml-audit-dialog+xml +# application/vnd.radisys.msml-audit-stream+xml +# application/vnd.radisys.msml-conf+xml +# application/vnd.radisys.msml-dialog+xml +# application/vnd.radisys.msml-dialog-base+xml +# application/vnd.radisys.msml-dialog-fax-detect+xml +# application/vnd.radisys.msml-dialog-fax-sendrecv+xml +# application/vnd.radisys.msml-dialog-group+xml +# application/vnd.radisys.msml-dialog-speech+xml +# application/vnd.radisys.msml-dialog-transform+xml +# application/vnd.rainstor.data +# application/vnd.rapid +application/vnd.realvnc.bed bed +application/vnd.recordare.musicxml mxl +application/vnd.recordare.musicxml+xml musicxml +# application/vnd.renlearn.rlprint +application/vnd.rig.cryptonote cryptonote +application/vnd.rim.cod cod +application/vnd.rn-realmedia rm +application/vnd.rn-realmedia-vbr rmvb +application/vnd.route66.link66+xml link66 +# application/vnd.rs-274x +# application/vnd.ruckus.download +# application/vnd.s3sms +application/vnd.sailingtracker.track st +# application/vnd.sbm.cid +# application/vnd.sbm.mid2 +# application/vnd.scribus +# application/vnd.sealed.3df +# application/vnd.sealed.csf +# application/vnd.sealed.doc +# application/vnd.sealed.eml +# application/vnd.sealed.mht +# application/vnd.sealed.net +# application/vnd.sealed.ppt +# application/vnd.sealed.tiff +# application/vnd.sealed.xls +# application/vnd.sealedmedia.softseal.html +# application/vnd.sealedmedia.softseal.pdf +application/vnd.seemail see +application/vnd.sema sema +application/vnd.semd semd +application/vnd.semf semf +application/vnd.shana.informed.formdata ifm +application/vnd.shana.informed.formtemplate itp +application/vnd.shana.informed.interchange iif +application/vnd.shana.informed.package ipk +application/vnd.simtech-mindmapper twd twds +application/vnd.smaf mmf +# application/vnd.smart.notebook +application/vnd.smart.teacher teacher +# application/vnd.software602.filler.form+xml +# application/vnd.software602.filler.form-xml-zip +application/vnd.solent.sdkm+xml sdkm sdkd +application/vnd.spotfire.dxp dxp +application/vnd.spotfire.sfs sfs +# application/vnd.sss-cod +# application/vnd.sss-dtf +# application/vnd.sss-ntf +application/vnd.stardivision.calc sdc +application/vnd.stardivision.draw sda +application/vnd.stardivision.impress sdd +application/vnd.stardivision.math smf +application/vnd.stardivision.writer sdw vor +application/vnd.stardivision.writer-global sgl +application/vnd.stepmania.package smzip +application/vnd.stepmania.stepchart sm +# application/vnd.street-stream +application/vnd.sun.xml.calc sxc +application/vnd.sun.xml.calc.template stc +application/vnd.sun.xml.draw sxd +application/vnd.sun.xml.draw.template std +application/vnd.sun.xml.impress sxi +application/vnd.sun.xml.impress.template sti +application/vnd.sun.xml.math sxm +application/vnd.sun.xml.writer sxw +application/vnd.sun.xml.writer.global sxg +application/vnd.sun.xml.writer.template stw +# application/vnd.sun.wadl+xml +application/vnd.sus-calendar sus susp +application/vnd.svd svd +# application/vnd.swiftview-ics +application/vnd.symbian.install sis sisx +application/vnd.syncml+xml xsm +application/vnd.syncml.dm+wbxml bdm +application/vnd.syncml.dm+xml xdm +# application/vnd.syncml.dm.notification +# application/vnd.syncml.ds.notification +application/vnd.tao.intent-module-archive tao +application/vnd.tcpdump.pcap pcap cap dmp +application/vnd.tmobile-livetv tmo +application/vnd.trid.tpt tpt +application/vnd.triscape.mxs mxs +application/vnd.trueapp tra +# application/vnd.truedoc +# application/vnd.ubisoft.webplayer +application/vnd.ufdl ufd ufdl +application/vnd.uiq.theme utz +application/vnd.umajin umj +application/vnd.unity unityweb +application/vnd.uoml+xml uoml +# application/vnd.uplanet.alert +# application/vnd.uplanet.alert-wbxml +# application/vnd.uplanet.bearer-choice +# application/vnd.uplanet.bearer-choice-wbxml +# application/vnd.uplanet.cacheop +# application/vnd.uplanet.cacheop-wbxml +# application/vnd.uplanet.channel +# application/vnd.uplanet.channel-wbxml +# application/vnd.uplanet.list +# application/vnd.uplanet.list-wbxml +# application/vnd.uplanet.listcmd +# application/vnd.uplanet.listcmd-wbxml +# application/vnd.uplanet.signal +application/vnd.vcx vcx +# application/vnd.vd-study +# application/vnd.vectorworks +# application/vnd.verimatrix.vcas +# application/vnd.vidsoft.vidconference +application/vnd.visio vsd vst vss vsw +application/vnd.visionary vis +# application/vnd.vividence.scriptfile +application/vnd.vsf vsf +# application/vnd.wap.sic +# application/vnd.wap.slc +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo wtb +# application/vnd.wfa.wsc +# application/vnd.wmc +# application/vnd.wmf.bootstrap +# application/vnd.wolfram.mathematica +# application/vnd.wolfram.mathematica.package +application/vnd.wolfram.player nbp +application/vnd.wordperfect wpd +application/vnd.wqd wqd +# application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf stf +# application/vnd.wv.csp+wbxml +# application/vnd.wv.csp+xml +# application/vnd.wv.ssp+xml +application/vnd.xara xar +application/vnd.xfdl xfdl +# application/vnd.xfdl.webform +# application/vnd.xmi+xml +# application/vnd.xmpie.cpkg +# application/vnd.xmpie.dpkg +# application/vnd.xmpie.plan +# application/vnd.xmpie.ppkg +# application/vnd.xmpie.xlim +application/vnd.yamaha.hv-dic hvd +application/vnd.yamaha.hv-script hvs +application/vnd.yamaha.hv-voice hvp +application/vnd.yamaha.openscoreformat osf +application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg +# application/vnd.yamaha.remote-setup +application/vnd.yamaha.smaf-audio saf +application/vnd.yamaha.smaf-phrase spf +# application/vnd.yamaha.through-ngn +# application/vnd.yamaha.tunnel-udpencap +application/vnd.yellowriver-custom-menu cmp +application/vnd.zul zir zirz +application/vnd.zzazz.deck+xml zaz +application/voicexml+xml vxml +# application/vq-rtcpxr +# application/watcherinfo+xml +# application/whoispp-query +# application/whoispp-response +application/widget wgt +application/winhlp hlp +# application/wita +# application/wordperfect5.1 +application/wsdl+xml wsdl +application/wspolicy+xml wspolicy +application/x-7z-compressed 7z +application/x-abiword abw +application/x-ace-compressed ace +# application/x-amf +application/x-apple-diskimage dmg +application/x-authorware-bin aab x32 u32 vox +application/x-authorware-map aam +application/x-authorware-seg aas +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-blorb blb blorb +application/x-bzip bz +application/x-bzip2 bz2 boz +application/x-cbr cbr cba cbt cbz cb7 +application/x-cdlink vcd +application/x-cfs-compressed cfs +application/x-chat chat +application/x-chess-pgn pgn +application/x-conference nsc +# application/x-compress +application/x-cpio cpio +application/x-csh csh +application/x-debian-package deb udeb +application/x-dgc-compressed dgc +application/x-director dir dcr dxr cst cct cxt w3d fgd swa +application/x-doom wad +application/x-dtbncx+xml ncx +application/x-dtbook+xml dtb +application/x-dtbresource+xml res +application/x-dvi dvi +application/x-envoy evy +application/x-eva eva +application/x-font-bdf bdf +# application/x-font-dos +# application/x-font-framemaker +application/x-font-ghostscript gsf +# application/x-font-libgrx +application/x-font-linux-psf psf +application/x-font-otf otf +application/x-font-pcf pcf +application/x-font-snf snf +# application/x-font-speedo +# application/x-font-sunos-news +application/x-font-ttf ttf ttc +application/x-font-type1 pfa pfb pfm afm +application/font-woff woff +# application/x-font-vfont +application/x-freearc arc +application/x-futuresplash spl +application/x-gca-compressed gca +application/x-glulx ulx +application/x-gnumeric gnumeric +application/x-gramps-xml gramps +application/x-gtar gtar +# application/x-gzip +application/x-hdf hdf +application/x-install-instructions install +application/x-iso9660-image iso +application/x-java-jnlp-file jnlp +application/x-latex latex +application/x-lzh-compressed lzh lha +application/x-mie mie +application/x-mobipocket-ebook prc mobi +application/x-ms-application application +application/x-ms-shortcut lnk +application/x-ms-wmd wmd +application/x-ms-wmz wmz +application/x-ms-xbap xbap +application/x-msaccess mdb +application/x-msbinder obd +application/x-mscardfile crd +application/x-msclip clp +application/x-msdownload exe dll com bat msi +application/x-msmediaview mvb m13 m14 +application/x-msmetafile wmf wmz emf emz +application/x-msmoney mny +application/x-mspublisher pub +application/x-msschedule scd +application/x-msterminal trm +application/x-mswrite wri +application/x-netcdf nc cdf +application/x-nzb nzb +application/x-pkcs12 p12 pfx +application/x-pkcs7-certificates p7b spc +application/x-pkcs7-certreqresp p7r +application/x-rar-compressed rar +application/x-research-info-systems ris +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-silverlight-app xap +application/x-sql sql +application/x-stuffit sit +application/x-stuffitx sitx +application/x-subrip srt +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-t3vm-image t3 +application/x-tads gam +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-tex-tfm tfm +application/x-texinfo texinfo texi +application/x-tgif obj +application/x-ustar ustar +application/x-wais-source src +application/x-x509-ca-cert der crt +application/x-xfig fig +application/x-xliff+xml xlf +application/x-xpinstall xpi +application/x-xz xz +application/x-zmachine z1 z2 z3 z4 z5 z6 z7 z8 +# application/x400-bp +application/xaml+xml xaml +# application/xcap-att+xml +# application/xcap-caps+xml +application/xcap-diff+xml xdf +# application/xcap-el+xml +# application/xcap-error+xml +# application/xcap-ns+xml +# application/xcon-conference-info-diff+xml +# application/xcon-conference-info+xml +application/xenc+xml xenc +application/xhtml+xml xhtml xht +# application/xhtml-voice+xml +application/xml xml xsl +application/xml-dtd dtd +# application/xml-external-parsed-entity +# application/xmpp+xml +application/xop+xml xop +application/xproc+xml xpl +application/xslt+xml xslt +application/xspf+xml xspf +application/xv+xml mxml xhvml xvml xvm +application/yang yang +application/yin+xml yin +application/zip zip +# audio/1d-interleaved-parityfec +# audio/32kadpcm +# audio/3gpp +# audio/3gpp2 +# audio/ac3 +audio/adpcm adp +# audio/amr +# audio/amr-wb +# audio/amr-wb+ +# audio/asc +# audio/atrac-advanced-lossless +# audio/atrac-x +# audio/atrac3 +audio/basic au snd +# audio/bv16 +# audio/bv32 +# audio/clearmode +# audio/cn +# audio/dat12 +# audio/dls +# audio/dsr-es201108 +# audio/dsr-es202050 +# audio/dsr-es202211 +# audio/dsr-es202212 +# audio/dv +# audio/dvi4 +# audio/eac3 +# audio/evrc +# audio/evrc-qcp +# audio/evrc0 +# audio/evrc1 +# audio/evrcb +# audio/evrcb0 +# audio/evrcb1 +# audio/evrcwb +# audio/evrcwb0 +# audio/evrcwb1 +# audio/example +# audio/fwdred +# audio/g719 +# audio/g722 +# audio/g7221 +# audio/g723 +# audio/g726-16 +# audio/g726-24 +# audio/g726-32 +# audio/g726-40 +# audio/g728 +# audio/g729 +# audio/g7291 +# audio/g729d +# audio/g729e +# audio/gsm +# audio/gsm-efr +# audio/gsm-hr-08 +# audio/ilbc +# audio/ip-mr_v2.5 +# audio/isac +# audio/l16 +# audio/l20 +# audio/l24 +# audio/l8 +# audio/lpc +audio/midi mid midi kar rmi +# audio/mobile-xmf +audio/mp4 mp4a +# audio/mp4a-latm +# audio/mpa +# audio/mpa-robust +audio/mpeg mpga mp2 mp2a mp3 m2a m3a +# audio/mpeg4-generic +# audio/musepack +audio/ogg oga ogg spx +# audio/opus +# audio/parityfec +# audio/pcma +# audio/pcma-wb +# audio/pcmu-wb +# audio/pcmu +# audio/prs.sid +# audio/qcelp +# audio/red +# audio/rtp-enc-aescm128 +# audio/rtp-midi +# audio/rtx +audio/s3m s3m +audio/silk sil +# audio/smv +# audio/smv0 +# audio/smv-qcp +# audio/sp-midi +# audio/speex +# audio/t140c +# audio/t38 +# audio/telephone-event +# audio/tone +# audio/uemclip +# audio/ulpfec +# audio/vdvi +# audio/vmr-wb +# audio/vnd.3gpp.iufp +# audio/vnd.4sb +# audio/vnd.audiokoz +# audio/vnd.celp +# audio/vnd.cisco.nse +# audio/vnd.cmles.radio-events +# audio/vnd.cns.anp1 +# audio/vnd.cns.inf1 +audio/vnd.dece.audio uva uvva +audio/vnd.digital-winds eol +# audio/vnd.dlna.adts +# audio/vnd.dolby.heaac.1 +# audio/vnd.dolby.heaac.2 +# audio/vnd.dolby.mlp +# audio/vnd.dolby.mps +# audio/vnd.dolby.pl2 +# audio/vnd.dolby.pl2x +# audio/vnd.dolby.pl2z +# audio/vnd.dolby.pulse.1 +audio/vnd.dra dra +audio/vnd.dts dts +audio/vnd.dts.hd dtshd +# audio/vnd.dvb.file +# audio/vnd.everad.plj +# audio/vnd.hns.audio +audio/vnd.lucent.voice lvp +audio/vnd.ms-playready.media.pya pya +# audio/vnd.nokia.mobile-xmf +# audio/vnd.nortel.vbk +audio/vnd.nuera.ecelp4800 ecelp4800 +audio/vnd.nuera.ecelp7470 ecelp7470 +audio/vnd.nuera.ecelp9600 ecelp9600 +# audio/vnd.octel.sbc +# audio/vnd.qcelp +# audio/vnd.rhetorex.32kadpcm +audio/vnd.rip rip +# audio/vnd.sealedmedia.softseal.mpeg +# audio/vnd.vmx.cvsd +# audio/vorbis +# audio/vorbis-config +audio/webm weba +audio/x-aac aac +audio/x-aiff aif aiff aifc +audio/x-caf caf +audio/x-flac flac +audio/x-matroska mka +audio/x-mpegurl m3u +audio/x-ms-wax wax +audio/x-ms-wma wma +audio/x-pn-realaudio ram ra +audio/x-pn-realaudio-plugin rmp +# audio/x-tta +audio/x-wav wav +audio/xm xm +chemical/x-cdx cdx +chemical/x-cif cif +chemical/x-cmdf cmdf +chemical/x-cml cml +chemical/x-csml csml +# chemical/x-pdb +chemical/x-xyz xyz +image/bmp bmp +image/cgm cgm +# image/example +# image/fits +image/g3fax g3 +image/gif gif +image/ief ief +# image/jp2 +image/jpeg jpeg jpg jpe +# image/jpm +# image/jpx +image/ktx ktx +# image/naplps +image/png png +image/prs.btif btif +# image/prs.pti +image/sgi sgi +image/svg+xml svg svgz +# image/t38 +image/tiff tiff tif +# image/tiff-fx +image/vnd.adobe.photoshop psd +# image/vnd.cns.inf2 +image/vnd.dece.graphic uvi uvvi uvg uvvg +image/vnd.dvb.subtitle sub +image/vnd.djvu djvu djv +image/vnd.dwg dwg +image/vnd.dxf dxf +image/vnd.fastbidsheet fbs +image/vnd.fpx fpx +image/vnd.fst fst +image/vnd.fujixerox.edmics-mmr mmr +image/vnd.fujixerox.edmics-rlc rlc +# image/vnd.globalgraphics.pgb +# image/vnd.microsoft.icon +# image/vnd.mix +image/vnd.ms-modi mdi +image/vnd.ms-photo wdp +image/vnd.net-fpx npx +# image/vnd.radiance +# image/vnd.sealed.png +# image/vnd.sealedmedia.softseal.gif +# image/vnd.sealedmedia.softseal.jpg +# image/vnd.svf +image/vnd.wap.wbmp wbmp +image/vnd.xiff xif +image/webp webp +image/x-3ds 3ds +image/x-cmu-raster ras +image/x-cmx cmx +image/x-freehand fh fhc fh4 fh5 fh7 +image/x-icon ico +image/x-mrsid-image sid +image/x-pcx pcx +image/x-pict pic pct +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-tga tga +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +# message/cpim +# message/delivery-status +# message/disposition-notification +# message/example +# message/external-body +# message/feedback-report +# message/global +# message/global-delivery-status +# message/global-disposition-notification +# message/global-headers +# message/http +# message/imdn+xml +# message/news +# message/partial +message/rfc822 eml mime +# message/s-http +# message/sip +# message/sipfrag +# message/tracking-status +# message/vnd.si.simp +# model/example +model/iges igs iges +model/mesh msh mesh silo +model/vnd.collada+xml dae +model/vnd.dwf dwf +# model/vnd.flatland.3dml +model/vnd.gdl gdl +# model/vnd.gs-gdl +# model/vnd.gs.gdl +model/vnd.gtw gtw +# model/vnd.moml+xml +model/vnd.mts mts +# model/vnd.parasolid.transmit.binary +# model/vnd.parasolid.transmit.text +model/vnd.vtu vtu +model/vrml wrl vrml +model/x3d+binary x3db x3dbz +model/x3d+vrml x3dv x3dvz +model/x3d+xml x3d x3dz +# multipart/alternative +# multipart/appledouble +# multipart/byteranges +# multipart/digest +# multipart/encrypted +# multipart/example +# multipart/form-data +# multipart/header-set +# multipart/mixed +# multipart/parallel +# multipart/related +# multipart/report +# multipart/signed +# multipart/voice-message +# text/1d-interleaved-parityfec +text/cache-manifest appcache +text/calendar ics ifb +text/css css +text/csv csv +# text/directory +# text/dns +# text/ecmascript +# text/enriched +# text/example +# text/fwdred +text/html html htm +# text/javascript +text/n3 n3 +# text/parityfec +text/plain txt text conf def list log in +# text/prs.fallenstein.rst +text/prs.lines.tag dsc +# text/vnd.radisys.msml-basic-layout +# text/red +# text/rfc822-headers +text/richtext rtx +# text/rtf +# text/rtp-enc-aescm128 +# text/rtx +text/sgml sgml sgm +# text/t140 +text/tab-separated-values tsv +text/troff t tr roff man me ms +text/turtle ttl +# text/ulpfec +text/uri-list uri uris urls +text/vcard vcard +# text/vnd.abc +text/vnd.curl curl +text/vnd.curl.dcurl dcurl +text/vnd.curl.scurl scurl +text/vnd.curl.mcurl mcurl +# text/vnd.dmclientscript +text/vnd.dvb.subtitle sub +# text/vnd.esmertec.theme-descriptor +text/vnd.fly fly +text/vnd.fmi.flexstor flx +text/vnd.graphviz gv +text/vnd.in3d.3dml 3dml +text/vnd.in3d.spot spot +# text/vnd.iptc.newsml +# text/vnd.iptc.nitf +# text/vnd.latex-z +# text/vnd.motorola.reflex +# text/vnd.ms-mediapackage +# text/vnd.net2phone.commcenter.command +# text/vnd.si.uricatalogue +text/vnd.sun.j2me.app-descriptor jad +# text/vnd.trolltech.linguist +# text/vnd.wap.si +# text/vnd.wap.sl +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/x-asm s asm +text/x-c c cc cxx cpp h hh dic +text/x-fortran f for f77 f90 +text/x-java-source java +text/x-opml opml +text/x-pascal p pas +text/x-nfo nfo +text/x-setext etx +text/x-sfv sfv +text/x-uuencode uu +text/x-vcalendar vcs +text/x-vcard vcf +# text/xml +# text/xml-external-parsed-entity +# video/1d-interleaved-parityfec +video/3gpp 3gp +# video/3gpp-tt +video/3gpp2 3g2 +# video/bmpeg +# video/bt656 +# video/celb +# video/dv +# video/example +video/h261 h261 +video/h263 h263 +# video/h263-1998 +# video/h263-2000 +video/h264 h264 +# video/h264-rcdo +# video/h264-svc +video/jpeg jpgv +# video/jpeg2000 +video/jpm jpm jpgm +video/mj2 mj2 mjp2 +# video/mp1s +# video/mp2p +# video/mp2t +video/mp4 mp4 mp4v mpg4 +# video/mp4v-es +video/mpeg mpeg mpg mpe m1v m2v +# video/mpeg4-generic +# video/mpv +# video/nv +video/ogg ogv +# video/parityfec +# video/pointer +video/quicktime qt mov +# video/raw +# video/rtp-enc-aescm128 +# video/rtx +# video/smpte292m +# video/ulpfec +# video/vc1 +# video/vnd.cctv +video/vnd.dece.hd uvh uvvh +video/vnd.dece.mobile uvm uvvm +# video/vnd.dece.mp4 +video/vnd.dece.pd uvp uvvp +video/vnd.dece.sd uvs uvvs +video/vnd.dece.video uvv uvvv +# video/vnd.directv.mpeg +# video/vnd.directv.mpeg-tts +# video/vnd.dlna.mpeg-tts +video/vnd.dvb.file dvb +video/vnd.fvt fvt +# video/vnd.hns.video +# video/vnd.iptvforum.1dparityfec-1010 +# video/vnd.iptvforum.1dparityfec-2005 +# video/vnd.iptvforum.2dparityfec-1010 +# video/vnd.iptvforum.2dparityfec-2005 +# video/vnd.iptvforum.ttsavc +# video/vnd.iptvforum.ttsmpeg2 +# video/vnd.motorola.video +# video/vnd.motorola.videop +video/vnd.mpegurl mxu m4u +video/vnd.ms-playready.media.pyv pyv +# video/vnd.nokia.interleaved-multimedia +# video/vnd.nokia.videovoip +# video/vnd.objectvideo +# video/vnd.sealed.mpeg1 +# video/vnd.sealed.mpeg4 +# video/vnd.sealed.swf +# video/vnd.sealedmedia.softseal.mov +video/vnd.uvvu.mp4 uvu uvvu +video/vnd.vivo viv +video/webm webm +video/x-f4v f4v +video/x-fli fli +video/x-flv flv +video/x-m4v m4v +video/x-matroska mkv mk3d mks +video/x-mng mng +video/x-ms-asf asf asx +video/x-ms-vob vob +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie +video/x-smv smv +x-conference/x-cooltalk ice diff --git a/node_modules/express/node_modules/send/node_modules/mime/types/node.types b/node_modules/express/node_modules/send/node_modules/mime/types/node.types new file mode 100644 index 0000000..55b2cf7 --- /dev/null +++ b/node_modules/express/node_modules/send/node_modules/mime/types/node.types @@ -0,0 +1,77 @@ +# What: WebVTT +# Why: To allow formats intended for marking up external text track resources. +# http://dev.w3.org/html5/webvtt/ +# Added by: niftylettuce +text/vtt vtt + +# What: Google Chrome Extension +# Why: To allow apps to (work) be served with the right content type header. +# http://codereview.chromium.org/2830017 +# Added by: niftylettuce +application/x-chrome-extension crx + +# What: HTC support +# Why: To properly render .htc files such as CSS3PIE +# Added by: niftylettuce +text/x-component htc + +# What: HTML5 application cache manifes ('.manifest' extension) +# Why: De-facto standard. Required by Mozilla browser when serving HTML5 apps +# per https://developer.mozilla.org/en/offline_resources_in_firefox +# Added by: louisremi +text/cache-manifest manifest + +# What: node binary buffer format +# Why: semi-standard extension w/in the node community +# Added by: tootallnate +application/octet-stream buffer + +# What: The "protected" MP-4 formats used by iTunes. +# Why: Required for streaming music to browsers (?) +# Added by: broofa +application/mp4 m4p +audio/mp4 m4a + +# What: Video format, Part of RFC1890 +# Why: See https://github.com/bentomas/node-mime/pull/6 +# Added by: mjrusso +video/MP2T ts + +# What: EventSource mime type +# Why: mime type of Server-Sent Events stream +# http://www.w3.org/TR/eventsource/#text-event-stream +# Added by: francois2metz +text/event-stream event-stream + +# What: Mozilla App manifest mime type +# Why: https://developer.mozilla.org/en/Apps/Manifest#Serving_manifests +# Added by: ednapiranha +application/x-web-app-manifest+json webapp + +# What: Lua file types +# Why: Googling around shows de-facto consensus on these +# Added by: creationix (Issue #45) +text/x-lua lua +application/x-lua-bytecode luac + +# What: Markdown files, as per http://daringfireball.net/projects/markdown/syntax +# Why: http://stackoverflow.com/questions/10701983/what-is-the-mime-type-for-markdown +# Added by: avoidwork +text/x-markdown markdown md mkd + +# What: ini files +# Why: because they're just text files +# Added by: Matthew Kastor +text/plain ini + +# What: DASH Adaptive Streaming manifest +# Why: https://developer.mozilla.org/en-US/docs/DASH_Adaptive_Streaming_for_HTML_5_Video +# Added by: eelcocramer +application/dash+xml mdp + +# What: OpenType font files - http://www.microsoft.com/typography/otspec/ +# Why: Browsers usually ignore the font MIME types and sniff the content, +# but Chrome, shows a warning if OpenType fonts aren't served with +# the `font/opentype` MIME type: http://i.imgur.com/8c5RN8M.png. +# Added by: alrra +font/opentype otf diff --git a/node_modules/express/node_modules/send/package.json b/node_modules/express/node_modules/send/package.json new file mode 100644 index 0000000..8a20f9d --- /dev/null +++ b/node_modules/express/node_modules/send/package.json @@ -0,0 +1,45 @@ +{ + "name": "send", + "version": "0.1.4", + "description": "Better streaming static file server with Range and conditional-GET support", + "keywords": [ + "static", + "file", + "server" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "dependencies": { + "debug": "*", + "mime": "~1.2.9", + "fresh": "0.2.0", + "range-parser": "0.0.4" + }, + "devDependencies": { + "mocha": "*", + "should": "*", + "supertest": "0.0.1", + "connect": "2.x" + }, + "scripts": { + "test": "make test" + }, + "repository": { + "type": "git", + "url": "git://github.com/visionmedia/send.git" + }, + "main": "index", + "readme": "# send\n\n Send is Connect's `static()` extracted for generalized use, a streaming static file\n server supporting partial responses (Ranges), conditional-GET negotiation, high test coverage, and granular events which may be leveraged to take appropriate actions in your application or framework.\n\n## Installation\n\n $ npm install send\n\n## Examples\n\n Small:\n\n```js\nvar http = require('http');\nvar send = require('send');\n\nvar app = http.createServer(function(req, res){\n send(req, req.url).pipe(res);\n}).listen(3000);\n```\n\n Serving from a root directory with custom error-handling:\n\n```js\nvar http = require('http');\nvar send = require('send');\nvar url = require('url');\n\nvar app = http.createServer(function(req, res){\n // your custom error-handling logic:\n function error(err) {\n res.statusCode = err.status || 500;\n res.end(err.message);\n }\n\n // your custom directory handling logic:\n function redirect() {\n res.statusCode = 301;\n res.setHeader('Location', req.url + '/');\n res.end('Redirecting to ' + req.url + '/');\n }\n\n // transfer arbitrary files from within\n // /www/example.com/public/*\n send(req, url.parse(req.url).pathname)\n .root('/www/example.com/public')\n .on('error', error)\n .on('directory', redirect)\n .pipe(res);\n}).listen(3000);\n```\n\n## API\n\n### Events\n\n - `error` an error occurred `(err)`\n - `directory` a directory was requested\n - `file` a file was requested `(path, stat)`\n - `stream` file streaming has started `(stream)`\n - `end` streaming has completed\n\n### .root(dir)\n\n Serve files relative to `path`. Aliased as `.from(dir)`.\n\n### .index(path)\n\n By default send supports \"index.html\" files, to disable this\n invoke `.index(false)` or to supply a new index pass a string.\n\n### .maxage(ms)\n\n Provide a max-age in milliseconds for http caching, defaults to 0.\n\n### .hidden(bool)\n\n Enable or disable transfer of hidden files, defaults to false.\n\n## Error-handling\n\n By default when no `error` listeners are present an automatic response will be made, otherwise you have full control over the response, aka you may show a 5xx page etc.\n\n## Caching\n\n It does _not_ perform internal caching, you should use a reverse proxy cache such\n as Varnish for this, or those fancy things called CDNs. If your application is small enough that it would benefit from single-node memory caching, it's small enough that it does not need caching at all ;).\n\n## Debugging\n\n To enable `debug()` instrumentation output export __DEBUG__:\n\n```\n$ DEBUG=send node app\n```\n\n## Running tests\n\n```\n$ npm install\n$ make test\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/send/issues" + }, + "_id": "send@0.1.4", + "dist": { + "shasum": "be70d8d1be01de61821af13780b50345a4f71abd" + }, + "_from": "send@0.1.4", + "_resolved": "https://registry.npmjs.org/send/-/send-0.1.4.tgz" +} diff --git a/node_modules/express/package.json b/node_modules/express/package.json new file mode 100644 index 0000000..42c9530 --- /dev/null +++ b/node_modules/express/package.json @@ -0,0 +1,88 @@ +{ + "name": "express", + "description": "Sinatra inspired web development framework", + "version": "3.4.4", + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "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": "2.11.0", + "commander": "1.3.2", + "range-parser": "0.0.4", + "mkdirp": "0.3.5", + "cookie": "0.1.0", + "buffer-crc32": "0.2.1", + "fresh": "0.2.0", + "methods": "0.1.0", + "send": "0.1.4", + "cookie-signature": "1.0.1", + "debug": "*" + }, + "devDependencies": { + "ejs": "*", + "mocha": "*", + "jade": "0.30.0", + "hjs": "*", + "stylus": "*", + "should": "2", + "connect-redis": "*", + "marked": "*", + "supertest": "0.8.1 - 1" + }, + "keywords": [ + "express", + "framework", + "sinatra", + "web", + "rest", + "restful", + "router", + "app", + "api" + ], + "repository": { + "type": "git", + "url": "git://github.com/visionmedia/express" + }, + "main": "index", + "bin": { + "express": "./bin/express" + }, + "scripts": { + "prepublish": "npm prune", + "test": "make test" + }, + "engines": { + "node": "*" + }, + "readme": "[![express logo](http://f.cl.ly/items/0V2S1n0K1i3y1c122g04/Screen%20Shot%202012-04-11%20at%209.59.42%20AM.png)](http://expressjs.com/)\n\n Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).\n\n [![Build Status](https://secure.travis-ci.org/visionmedia/express.png)](http://travis-ci.org/visionmedia/express) [![Gittip](http://img.shields.io/gittip/visionmedia.png)](https://www.gittip.com/visionmedia/)\n\n```js\nvar express = require('express');\nvar app = express();\n\napp.get('/', function(req, res){\n res.send('Hello World');\n});\n\napp.listen(3000);\n```\n\n## Installation\n\n $ npm install -g express\n\n## Quick Start\n\n The quickest way to get started with express is to utilize the executable `express(1)` to generate an application as shown below:\n\n Create the app:\n\n $ npm install -g express\n $ express /tmp/foo && cd /tmp/foo\n\n Install dependencies:\n\n $ npm install\n\n Start the server:\n\n $ node app\n\n## Features\n\n * Built on [Connect](http://github.com/senchalabs/connect)\n * Robust routing\n * HTTP helpers (redirection, caching, etc)\n * View system supporting 14+ template engines\n * Content negotiation\n * Focus on high performance\n * Environment based configuration\n * Executable for generating applications quickly\n * High test coverage\n\n## Philosophy\n\n The Express philosophy is to provide small, robust tooling for HTTP servers. Making\n it a great solution for single page applications, web sites, hybrids, or public\n HTTP APIs.\n\n Built on Connect you can use _only_ what you need, and nothing more, applications\n can be as big or as small as you like, even a single file. Express does\n not force you to use any specific ORM or template engine. With support for over\n 14 template engines via [Consolidate.js](http://github.com/visionmedia/consolidate.js)\n you can quickly craft your perfect framework.\n\n## More Information\n\n * [Website and Documentation](http://expressjs.com/) stored at [visionmedia/expressjs.com](https://github.com/visionmedia/expressjs.com)\n * Join #express on freenode\n * [Google Group](http://groups.google.com/group/express-js) for discussion\n * Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates\n * Visit the [Wiki](http://github.com/visionmedia/express/wiki)\n * [Русскоязычная документация](http://jsman.ru/express/)\n * Run express examples [online](https://runnable.com/express)\n\n## Viewing Examples\n\nClone the Express repo, then install the dev dependencies to install all the example / test suite deps:\n\n $ git clone git://github.com/visionmedia/express.git --depth 1\n $ cd express\n $ npm install\n\nthen run whichever tests you want:\n\n $ node examples/content-negotiation\n\nYou can also view live examples here\n\n\n\n## Running Tests\n\nTo run the test suite first invoke the following command within the repo, installing the development dependencies:\n\n $ npm install\n\nthen run the tests:\n\n $ make test\n\n## Contributors\n\n https://github.com/visionmedia/express/graphs/contributors\n\n## License\n\n(The MIT License)\n\nCopyright (c) 2009-2012 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/express/issues" + }, + "_id": "express@3.4.4", + "dist": { + "shasum": "0b63ae626c96b71b78d13dfce079c10351635a86" + }, + "_from": "express@3.4.x", + "_resolved": "https://registry.npmjs.org/express/-/express-3.4.4.tgz" +} diff --git a/node_modules/jade/.npmignore b/node_modules/jade/.npmignore new file mode 100644 index 0000000..3be3bd2 --- /dev/null +++ b/node_modules/jade/.npmignore @@ -0,0 +1,14 @@ +test +support +benchmarks +examples +lib-cov +coverage.html +.gitmodules +.travis.yml +History.md +Makefile +test/ +support/ +benchmarks/ +examples/ diff --git a/node_modules/jade/LICENSE b/node_modules/jade/LICENSE new file mode 100644 index 0000000..fbfe096 --- /dev/null +++ b/node_modules/jade/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2009-2010 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/node_modules/jade/Readme.md b/node_modules/jade/Readme.md new file mode 100644 index 0000000..dff2927 --- /dev/null +++ b/node_modules/jade/Readme.md @@ -0,0 +1,161 @@ +# [![Jade - template engine ](http://i.imgur.com/5zf2aVt.png)](http://jade-lang.com/) + +Full documentation is at [jade-lang.com](http://jade-lang.com/) + + Jade is a high performance template engine heavily influenced by [Haml](http://haml-lang.com) + and implemented with JavaScript for [node](http://nodejs.org). For discussion join the [Google Group](http://groups.google.com/group/jadejs). + + You can test drive Jade online [here](http://naltatis.github.com/jade-syntax-docs). + + [![Build Status](https://travis-ci.org/visionmedia/jade.png?branch=master)](https://travis-ci.org/visionmedia/jade) + [![Dependency Status](https://gemnasium.com/visionmedia/jade.png)](https://gemnasium.com/visionmedia/jade) + [![NPM version](https://badge.fury.io/js/jade.png)](http://badge.fury.io/js/jade) + +## Announcements + +**Deprecation of implicit script/style text-only:** + + Jade version 0.31.0 deprecated implicit text only support for scripts and styles. To fix this all you need to do is add a `.` character after the script or style tag. + + It is hoped that this change will make Jade easier for newcomers to learn without affecting the power of the language or leading to excessive verboseness. + + If you have a lot of Jade files that need fixing you can use [fix-jade](https://github.com/ForbesLindesay/fix-jade) to attempt to automate the process. + +**Command line option change:** + +since `v0.31.0`, `-o` is preferred for `--out` where we used `-O` before. + +## Installation + +via npm: + +```bash +$ npm install jade +``` + +## Syntax + +Jade is a clean, whitespace sensitive syntax for writing html. Here is a simple example: + +```jade +doctype 5 +html(lang="en") + head + title= pageTitle + script(type='text/javascript'). + if (foo) bar(1 + 5) + body + h1 Jade - node template engine + #container.col + if youAreUsingJade + p You are amazing + else + p Get on it! + p. + Jade is a terse and simple templating language with a + strong focus on performance and powerful features. +``` + +becomes + + +```html + + + + Jade + + + +

    Jade - node template engine

    +
    +

    You are amazing

    +

    Jade is a terse and simple templating language with a strong focus on performance and powerful features.

    +
    + + +``` + +The official [jade tutorial](http://jade-lang.com/tutorial/) is a great place to start. While that (and the syntax documentation) is being finished, you can view some of the old documentation [here](https://github.com/visionmedia/jade/blob/master/jade.md) and [here](https://github.com/visionmedia/jade/blob/master/jade-language.md) + +## API + +For full API, see [jade-lang.com/api](http://jade-lang.com/api/) + +```js +var jade = require('jade'); + +// compile +var fn = jade.compile('string of jade', options); +var html = fn(locals); + +// render +var html = jade.render('string of jade', merge(options, locals)); + +// renderFile +var html = jade.renderFile('filename.jade', merge(options, locals)); +``` + +### Options + + - `filename` Used in exceptions, and required when using includes + - `compileDebug` When `false` no debug instrumentation is compiled + - `pretty` Add pretty-indentation whitespace to output _(false by default)_ + +## Browser Support + + The latest version of jade can be download for the browser in standalone form from [here](https://github.com/visionmedia/jade/raw/master/jade.js). It only supports the very latest browsers though, and is a large file. It is recommended that you pre-compile your jade templates to JavaScript and then just use the [runtime.js](https://github.com/visionmedia/jade/raw/master/runtime.js) library on the client. + + To compile a template for use on the client using the command line, do: + +```console +$ jade --client --no-debug filename.jade +``` + +which will produce `filename.js` containing the compiled template. + +## Command Line + +After installing the latest version of [node](http://nodejs.org/), install with: + +```console +$ npm install jade -g +``` + +and run with + +```console +$ jade --help +``` + +## Additional Resources + +Tutorials: + + - cssdeck interactive [Jade syntax tutorial](http://cssdeck.com/labs/learning-the-jade-templating-engine-syntax) + - cssdeck interactive [Jade logic tutorial](http://cssdeck.com/labs/jade-templating-tutorial-codecast-part-2) + - in [Japanese](http://blog.craftgear.net/4f501e97c1347ec934000001/title/10%E5%88%86%E3%81%A7%E3%82%8F%E3%81%8B%E3%82%8Bjade%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%B3) + + +Implementations in other languages: + + - [php](http://github.com/everzet/jade.php) + - [scala](http://scalate.fusesource.org/versions/snapshot/documentation/scaml-reference.html) + - [ruby](https://github.com/slim-template/slim) + - [python](https://github.com/SyrusAkbary/pyjade) + - [java](https://github.com/neuland/jade4j) + +Other: + + - [Emacs Mode](https://github.com/brianc/jade-mode) + - [Vim Syntax](https://github.com/digitaltoad/vim-jade) + - [TextMate Bundle](http://github.com/miksago/jade-tmbundle) + - [Coda/SubEtha syntax Mode](https://github.com/aaronmccall/jade.mode) + - [Screencasts](http://tjholowaychuk.com/post/1004255394/jade-screencast-template-engine-for-nodejs) + - [html2jade](https://github.com/donpark/html2jade) converter + +## License + +MIT diff --git a/node_modules/jade/Readme_zh-cn.md b/node_modules/jade/Readme_zh-cn.md new file mode 100644 index 0000000..84b8b5c --- /dev/null +++ b/node_modules/jade/Readme_zh-cn.md @@ -0,0 +1,1278 @@ +# Jade - 模板引擎 + +Jade 是一个高性能的模板引擎,它深受 [Haml](http://haml-lang.com) 影响,它是用 JavaScript 实现的, 并且可以供 [Node](http://nodejs.org) 使用. + +翻译: [草依山](http://jser.me) + +## 声明 + +从 Jade `v0.31.0` 开始放弃了对于 `" +| !{html} +``` + +内联标签同样可以使用文本块来包含文本: + +```jade +label + | Username: + input(name='user[name]') +``` + +或者直接使用标签文本: + +```jade +label Username: + input(name='user[name]') +``` + +_只_ 包含文本的标签,比如 ` + + +

    My Site

    +

    Welcome to my super lame site.

    + + + +``` + +前面已经提到,`include` 可以包含比如 HTML 或者 CSS 这样的内容。给定一个扩展名后,Jade 不会把这个文件当作一个 Jade 源代码,并且会把它当作一个普通文本包含进来: + +``` +html + head + //- css and js have simple filters that wrap them in + '; + } else if (transformers[name].outputFormat === 'xml') { + res = res.replace(/'/g, '''); + } + } else { + throw new Error('unknown filter ":' + name + '"'); + } + return res; +} +filter.exists = function (name, str, options) { + return typeof filter[name] === 'function' || transformers[name]; +}; diff --git a/node_modules/jade/lib/index.js b/node_modules/jade/lib/index.js new file mode 100644 index 0000000..6a783c2 --- /dev/null +++ b/node_modules/jade/lib/index.js @@ -0,0 +1 @@ +jade.js \ No newline at end of file diff --git a/node_modules/jade/lib/inline-tags.js b/node_modules/jade/lib/inline-tags.js new file mode 100644 index 0000000..e7f28e7 --- /dev/null +++ b/node_modules/jade/lib/inline-tags.js @@ -0,0 +1,28 @@ + +/*! + * Jade - inline tags + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +module.exports = [ + 'a' + , 'abbr' + , 'acronym' + , 'b' + , 'br' + , 'code' + , 'em' + , 'font' + , 'i' + , 'img' + , 'ins' + , 'kbd' + , 'map' + , 'samp' + , 'small' + , 'span' + , 'strong' + , 'sub' + , 'sup' +]; \ No newline at end of file diff --git a/node_modules/jade/lib/jade.js b/node_modules/jade/lib/jade.js new file mode 100644 index 0000000..c239ee0 --- /dev/null +++ b/node_modules/jade/lib/jade.js @@ -0,0 +1,240 @@ +/*! + * Jade + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Parser = require('./parser') + , Lexer = require('./lexer') + , Compiler = require('./compiler') + , runtime = require('./runtime') + , addWith = require('with') + , fs = require('fs'); + +/** + * Expose self closing tags. + */ + +exports.selfClosing = require('./self-closing'); + +/** + * Default supported doctypes. + */ + +exports.doctypes = require('./doctypes'); + +/** + * Text filters. + */ + +exports.filters = require('./filters'); + +/** + * Utilities. + */ + +exports.utils = require('./utils'); + +/** + * Expose `Compiler`. + */ + +exports.Compiler = Compiler; + +/** + * Expose `Parser`. + */ + +exports.Parser = Parser; + +/** + * Expose `Lexer`. + */ + +exports.Lexer = Lexer; + +/** + * Nodes. + */ + +exports.nodes = require('./nodes'); + +/** + * Jade runtime helpers. + */ + +exports.runtime = runtime; + +/** + * Template function cache. + */ + +exports.cache = {}; + +/** + * Parse the given `str` of jade and return a function body. + * + * @param {String} str + * @param {Object} options + * @return {String} + * @api private + */ + +function parse(str, options){ + try { + // Parse + var parser = new (options.parser || Parser)(str, options.filename, options); + + // Compile + var compiler = new (options.compiler || Compiler)(parser.parse(), options) + , js = compiler.compile(); + + // Debug compiler + if (options.debug) { + console.error('\nCompiled Function:\n\n\033[90m%s\033[0m', js.replace(/^/gm, ' ')); + } + + return '' + + 'var buf = [];\n' + + (options.self + ? 'var self = locals || {};\n' + js + : addWith('locals || {}', js, ['jade', 'buf'])) + ';' + + 'return buf.join("");'; + } catch (err) { + parser = parser.context(); + runtime.rethrow(err, parser.filename, parser.lexer.lineno, str); + } +} + +/** + * Compile a `Function` representation of the given jade `str`. + * + * Options: + * + * - `compileDebug` when `false` debugging code is stripped from the compiled + template, when it is explicitly `true`, the source code is included in + the compiled template for better accuracy. + * - `filename` used to improve errors when `compileDebug` is not `false` + * + * @param {String} str + * @param {Options} options + * @return {Function} + * @api public + */ + +exports.compile = function(str, options){ + var options = options || {} + , filename = options.filename + ? JSON.stringify(options.filename) + : 'undefined' + , fn; + + str = String(str); + + if (options.compileDebug !== false) { + fn = [ + 'jade.debug = [{ lineno: 1, filename: ' + filename + ' }];' + , 'try {' + , parse(str, options) + , '} catch (err) {' + , ' jade.rethrow(err, jade.debug[0].filename, jade.debug[0].lineno' + (options.compileDebug === true ? ',' + JSON.stringify(str) : '') + ');' + , '}' + ].join('\n'); + } else { + fn = parse(str, options); + } + + if (options.client) return new Function('locals', fn) + fn = new Function('locals, jade', fn) + return function(locals){ return fn(locals, Object.create(runtime)) } +}; + +/** + * Render the given `str` of jade. + * + * Options: + * + * - `cache` enable template caching + * - `filename` filename required for `include` / `extends` and caching + * + * @param {String} str + * @param {Object|Function} options or fn + * @param {Function|undefined} fn + * @returns {String} + * @api public + */ + +exports.render = function(str, options, fn){ + // support callback API + if ('function' == typeof options) { + fn = options, options = undefined; + } + if (typeof fn === 'function') { + var res + try { + res = exports.render(str, options); + } catch (ex) { + return fn(ex); + } + return fn(null, res); + } + + options = options || {}; + + // cache requires .filename + if (options.cache && !options.filename) { + throw new Error('the "filename" option is required for caching'); + } + + var path = options.filename; + var tmpl = options.cache + ? exports.cache[path] || (exports.cache[path] = exports.compile(str, options)) + : exports.compile(str, options); + return tmpl(options); +}; + +/** + * Render a Jade file at the given `path`. + * + * @param {String} path + * @param {Object|Function} options or callback + * @param {Function|undefined} fn + * @returns {String} + * @api public + */ + +exports.renderFile = function(path, options, fn){ + // support callback API + if ('function' == typeof options) { + fn = options, options = undefined; + } + if (typeof fn === 'function') { + var res + try { + res = exports.renderFile(path, options); + } catch (ex) { + return fn(ex); + } + return fn(null, res); + } + + options = options || {}; + + var key = path + ':string'; + + options.filename = path; + var str = options.cache + ? exports.cache[key] || (exports.cache[key] = fs.readFileSync(path, 'utf8')) + : fs.readFileSync(path, 'utf8'); + return exports.render(str, options); +}; + +/** + * Express support. + */ + +exports.__express = exports.renderFile; diff --git a/node_modules/jade/lib/lexer.js b/node_modules/jade/lib/lexer.js new file mode 100644 index 0000000..5ec1517 --- /dev/null +++ b/node_modules/jade/lib/lexer.js @@ -0,0 +1,794 @@ +/*! + * Jade - Lexer + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +var utils = require('./utils'); +var characterParser = require('character-parser'); + + +/** + * Initialize `Lexer` with the given `str`. + * + * Options: + * + * - `colons` allow colons for attr delimiters + * + * @param {String} str + * @param {Object} options + * @api private + */ + +var Lexer = module.exports = function Lexer(str, options) { + options = options || {}; + this.input = str.replace(/\r\n|\r/g, '\n'); + this.colons = options.colons; + this.deferredTokens = []; + this.lastIndents = 0; + this.lineno = 1; + this.stash = []; + this.indentStack = []; + this.indentRe = null; + this.pipeless = false; +}; + + +function assertExpression(exp) { + //this verifies that a JavaScript expression is valid + Function('', 'return (' + exp + ')'); +} +function assertNestingCorrect(exp) { + //this verifies that code is properly nested, but allows + //invalid JavaScript such as the contents of `attributes` + var res = characterParser(exp) + if (res.isNesting()) { + throw new Error('Nesting must match on expression `' + exp + '`') + } +} + +/** + * Lexer prototype. + */ + +Lexer.prototype = { + + /** + * Construct a token with the given `type` and `val`. + * + * @param {String} type + * @param {String} val + * @return {Object} + * @api private + */ + + tok: function(type, val){ + return { + type: type + , line: this.lineno + , val: val + } + }, + + /** + * Consume the given `len` of input. + * + * @param {Number} len + * @api private + */ + + consume: function(len){ + this.input = this.input.substr(len); + }, + + /** + * Scan for `type` with the given `regexp`. + * + * @param {String} type + * @param {RegExp} regexp + * @return {Object} + * @api private + */ + + scan: function(regexp, type){ + var captures; + if (captures = regexp.exec(this.input)) { + this.consume(captures[0].length); + return this.tok(type, captures[1]); + } + }, + + /** + * Defer the given `tok`. + * + * @param {Object} tok + * @api private + */ + + defer: function(tok){ + this.deferredTokens.push(tok); + }, + + /** + * Lookahead `n` tokens. + * + * @param {Number} n + * @return {Object} + * @api private + */ + + lookahead: function(n){ + var fetch = n - this.stash.length; + while (fetch-- > 0) this.stash.push(this.next()); + return this.stash[--n]; + }, + + /** + * Return the indexOf `(` or `{` or `[` / `)` or `}` or `]` delimiters. + * + * @return {Number} + * @api private + */ + + bracketExpression: function(skip){ + skip = skip || 0; + var start = this.input[skip]; + if (start != '(' && start != '{' && start != '[') throw new Error('unrecognized start character'); + var end = ({'(': ')', '{': '}', '[': ']'})[start]; + var range = characterParser.parseMax(this.input, {start: skip + 1}); + if (this.input[range.end] !== end) throw new Error('start character ' + start + ' does not match end character ' + this.input[range.end]); + return range; + }, + + /** + * Stashed token. + */ + + stashed: function() { + return this.stash.length + && this.stash.shift(); + }, + + /** + * Deferred token. + */ + + deferred: function() { + return this.deferredTokens.length + && this.deferredTokens.shift(); + }, + + /** + * end-of-source. + */ + + eos: function() { + if (this.input.length) return; + if (this.indentStack.length) { + this.indentStack.shift(); + return this.tok('outdent'); + } else { + return this.tok('eos'); + } + }, + + /** + * Blank line. + */ + + blank: function() { + var captures; + if (captures = /^\n *\n/.exec(this.input)) { + this.consume(captures[0].length - 1); + ++this.lineno; + if (this.pipeless) return this.tok('text', ''); + return this.next(); + } + }, + + /** + * Comment. + */ + + comment: function() { + var captures; + if (captures = /^ *\/\/(-)?([^\n]*)/.exec(this.input)) { + this.consume(captures[0].length); + var tok = this.tok('comment', captures[2]); + tok.buffer = '-' != captures[1]; + return tok; + } + }, + + /** + * Interpolated tag. + */ + + interpolation: function() { + if (/^#\{/.test(this.input)) { + var match; + try { + match = this.bracketExpression(1); + } catch (ex) { + return;//not an interpolation expression, just an unmatched open interpolation + } + + this.consume(match.end + 1); + return this.tok('interpolation', match.src); + } + }, + + /** + * Tag. + */ + + tag: function() { + var captures; + if (captures = /^(\w[-:\w]*)(\/?)/.exec(this.input)) { + this.consume(captures[0].length); + var tok, name = captures[1]; + if (':' == name[name.length - 1]) { + name = name.slice(0, -1); + tok = this.tok('tag', name); + this.defer(this.tok(':')); + while (' ' == this.input[0]) this.input = this.input.substr(1); + } else { + tok = this.tok('tag', name); + } + tok.selfClosing = !! captures[2]; + return tok; + } + }, + + /** + * Filter. + */ + + filter: function() { + return this.scan(/^:(\w+)/, 'filter'); + }, + + /** + * Doctype. + */ + + doctype: function() { + return this.scan(/^(?:!!!|doctype) *([^\n]+)?/, 'doctype'); + }, + + /** + * Id. + */ + + id: function() { + return this.scan(/^#([\w-]+)/, 'id'); + }, + + /** + * Class. + */ + + className: function() { + return this.scan(/^\.([\w-]+)/, 'class'); + }, + + /** + * Text. + */ + + text: function() { + return this.scan(/^(?:\| ?| ?)?([^\n]+)/, 'text'); + }, + + /** + * Extends. + */ + + "extends": function() { + return this.scan(/^extends? +([^\n]+)/, 'extends'); + }, + + /** + * Block prepend. + */ + + prepend: function() { + var captures; + if (captures = /^prepend +([^\n]+)/.exec(this.input)) { + this.consume(captures[0].length); + var mode = 'prepend' + , name = captures[1] + , tok = this.tok('block', name); + tok.mode = mode; + return tok; + } + }, + + /** + * Block append. + */ + + append: function() { + var captures; + if (captures = /^append +([^\n]+)/.exec(this.input)) { + this.consume(captures[0].length); + var mode = 'append' + , name = captures[1] + , tok = this.tok('block', name); + tok.mode = mode; + return tok; + } + }, + + /** + * Block. + */ + + block: function() { + var captures; + if (captures = /^block\b *(?:(prepend|append) +)?([^\n]*)/.exec(this.input)) { + this.consume(captures[0].length); + var mode = captures[1] || 'replace' + , name = captures[2] + , tok = this.tok('block', name); + + tok.mode = mode; + return tok; + } + }, + + /** + * Yield. + */ + + yield: function() { + return this.scan(/^yield */, 'yield'); + }, + + /** + * Include. + */ + + include: function() { + return this.scan(/^include +([^\n]+)/, 'include'); + }, + + /** + * Case. + */ + + "case": function() { + return this.scan(/^case +([^\n]+)/, 'case'); + }, + + /** + * When. + */ + + when: function() { + return this.scan(/^when +([^:\n]+)/, 'when'); + }, + + /** + * Default. + */ + + "default": function() { + return this.scan(/^default */, 'default'); + }, + + /** + * Assignment. + */ + + assignment: function() { + var captures; + if (captures = /^(\w+) += *([^;\n]+)( *;? *)/.exec(this.input)) { + this.consume(captures[0].length); + var name = captures[1] + , val = captures[2]; + return this.tok('code', 'var ' + name + ' = (' + val + ');'); + } + }, + + /** + * Call mixin. + */ + + call: function(){ + var captures; + if (captures = /^\+([-\w]+)/.exec(this.input)) { + this.consume(captures[0].length); + var tok = this.tok('call', captures[1]); + + // Check for args (not attributes) + if (captures = /^ *\(/.exec(this.input)) { + try { + var range = this.bracketExpression(captures[0].length - 1); + if (!/^ *[-\w]+ *=/.test(range.src)) { // not attributes + this.consume(range.end + 1); + tok.args = range.src; + } + } catch (ex) { + //not a bracket expcetion, just unmatched open parens + } + } + + return tok; + } + }, + + /** + * Mixin. + */ + + mixin: function(){ + var captures; + if (captures = /^mixin +([-\w]+)(?: *\((.*)\))?/.exec(this.input)) { + this.consume(captures[0].length); + var tok = this.tok('mixin', captures[1]); + tok.args = captures[2]; + return tok; + } + }, + + /** + * Conditional. + */ + + conditional: function() { + var captures; + if (captures = /^(if|unless|else if|else)\b([^\n]*)/.exec(this.input)) { + this.consume(captures[0].length); + var type = captures[1] + , js = captures[2]; + + switch (type) { + case 'if': + assertExpression(js) + js = 'if (' + js + ')'; + break; + case 'unless': + assertExpression(js) + js = 'if (!(' + js + '))'; + break; + case 'else if': + assertExpression(js) + js = 'else if (' + js + ')'; + break; + case 'else': + if (js && js.trim()) { + throw new Error('`else` cannot have a condition, perhaps you meant `else if`'); + } + js = 'else'; + break; + } + + return this.tok('code', js); + } + }, + + /** + * While. + */ + + "while": function() { + var captures; + if (captures = /^while +([^\n]+)/.exec(this.input)) { + this.consume(captures[0].length); + assertExpression(captures[1]) + return this.tok('code', 'while (' + captures[1] + ')'); + } + }, + + /** + * Each. + */ + + each: function() { + var captures; + if (captures = /^(?:- *)?(?:each|for) +([a-zA-Z_$][\w$]*)(?: *, *([a-zA-Z_$][\w$]*))? * in *([^\n]+)/.exec(this.input)) { + this.consume(captures[0].length); + var tok = this.tok('each', captures[1]); + tok.key = captures[2] || '$index'; + assertExpression(captures[3]) + tok.code = captures[3]; + return tok; + } + }, + + /** + * Code. + */ + + code: function() { + var captures; + if (captures = /^(!?=|-)[ \t]*([^\n]+)/.exec(this.input)) { + this.consume(captures[0].length); + var flags = captures[1]; + captures[1] = captures[2]; + var tok = this.tok('code', captures[1]); + tok.escape = flags.charAt(0) === '='; + tok.buffer = flags.charAt(0) === '=' || flags.charAt(1) === '='; + if (tok.buffer) assertExpression(captures[1]) + return tok; + } + }, + + /** + * Attributes. + */ + + attrs: function() { + if ('(' == this.input.charAt(0)) { + var index = this.bracketExpression().end + , str = this.input.substr(1, index-1) + , tok = this.tok('attrs') + , equals = this.colons ? ':' : '='; + + if (equals === ':') { + console.warn('`:` in jade is deprecated, please use `=`'); + } + + assertNestingCorrect(str); + + var quote = ''; + function interpolate(attr) { + return attr.replace(/(\\)?#\{(.+)/g, function(_, escape, expr){ + if (escape) return _; + try { + var range = characterParser.parseMax(expr); + if (expr[range.end] !== '}') return _.substr(0, 2) + interpolate(_.substr(2)); + assertExpression(range.src) + return quote + " + (" + range.src + ") + " + quote + interpolate(expr.substr(range.end + 1)); + } catch (ex) { + return _.substr(0, 2) + interpolate(_.substr(2)); + } + }); + } + + this.consume(index + 1); + tok.attrs = {}; + tok.escaped = {}; + + var escapedAttr = true + var key = ''; + var val = ''; + var interpolatable = ''; + var state = characterParser.defaultState(); + var loc = 'key'; + function isEndOfAttribute(i) { + if (key.trim() === '') return false; + if (i === str.length) return true; + if (loc === 'key') { + if (str[i] === ' ' || str[i] === '\n') { + for (var x = i; x < str.length; x++) { + if (str[x] != ' ' && str[x] != '\n') { + if (str[x] === '=' || str[x] === '!' || str[x] === ',') return false; + else return true; + } + } + } + return str[i] === ',' + } else if (loc === 'value' && !state.isNesting()) { + try { + Function('', 'return (' + val + ');'); + if (str[i] === ' ' || str[i] === '\n') { + for (var x = i; x < str.length; x++) { + if (str[x] != ' ' && str[x] != '\n') { + if (characterParser.isPunctuator(str[x]) && str[x] != '"' && str[x] != "'") return false; + else return true; + } + } + } + return str[i] === ','; + } catch (ex) { + return false; + } + } + } + for (var i = 0; i <= str.length; i++) { + if (isEndOfAttribute(i)) { + val = val.trim(); + if (val) assertExpression(val) + key = key.trim(); + key = key.replace(/^['"]|['"]$/g, ''); + tok.escaped[key] = escapedAttr; + tok.attrs[key] = '' == val ? true : val; + key = val = ''; + loc = 'key'; + escapedAttr = false; + } else { + switch (loc) { + case 'key-char': + if (str[i] === quote) { + loc = 'key'; + if (i + 1 < str.length && [' ', ',', '!', equals, '\n'].indexOf(str[i + 1]) === -1) + throw new Error('Unexpected character ' + str[i + 1] + ' expected ` `, `\\n`, `,`, `!` or `=`'); + } else if (loc === 'key-char') { + key += str[i]; + } + break; + case 'key': + if (key === '' && (str[i] === '"' || str[i] === "'")) { + loc = 'key-char'; + quote = str[i]; + } else if (str[i] === '!' || str[i] === equals) { + escapedAttr = str[i] !== '!'; + if (str[i] === '!') i++; + if (str[i] !== equals) throw new Error('Unexpected character ' + str[i] + ' expected `=`'); + loc = 'value'; + state = characterParser.defaultState(); + } else { + key += str[i] + } + break; + case 'value': + state = characterParser.parseChar(str[i], state); + if (state.isString()) { + loc = 'string'; + quote = str[i]; + interpolatable = str[i]; + } else { + val += str[i]; + } + break; + case 'string': + state = characterParser.parseChar(str[i], state); + interpolatable += str[i]; + if (!state.isString()) { + loc = 'value'; + val += interpolate(interpolatable); + } + break; + } + } + } + + if ('/' == this.input.charAt(0)) { + this.consume(1); + tok.selfClosing = true; + } + + return tok; + } + }, + + /** + * Indent | Outdent | Newline. + */ + + indent: function() { + var captures, re; + + // established regexp + if (this.indentRe) { + captures = this.indentRe.exec(this.input); + // determine regexp + } else { + // tabs + re = /^\n(\t*) */; + captures = re.exec(this.input); + + // spaces + if (captures && !captures[1].length) { + re = /^\n( *)/; + captures = re.exec(this.input); + } + + // established + if (captures && captures[1].length) this.indentRe = re; + } + + if (captures) { + var tok + , indents = captures[1].length; + + ++this.lineno; + this.consume(indents + 1); + + if (' ' == this.input[0] || '\t' == this.input[0]) { + throw new Error('Invalid indentation, you can use tabs or spaces but not both'); + } + + // blank line + if ('\n' == this.input[0]) return this.tok('newline'); + + // outdent + if (this.indentStack.length && indents < this.indentStack[0]) { + while (this.indentStack.length && this.indentStack[0] > indents) { + this.stash.push(this.tok('outdent')); + this.indentStack.shift(); + } + tok = this.stash.pop(); + // indent + } else if (indents && indents != this.indentStack[0]) { + this.indentStack.unshift(indents); + tok = this.tok('indent', indents); + // newline + } else { + tok = this.tok('newline'); + } + + return tok; + } + }, + + /** + * Pipe-less text consumed only when + * pipeless is true; + */ + + pipelessText: function() { + if (this.pipeless) { + if ('\n' == this.input[0]) return; + var i = this.input.indexOf('\n'); + if (-1 == i) i = this.input.length; + var str = this.input.substr(0, i); + this.consume(str.length); + return this.tok('text', str); + } + }, + + /** + * ':' + */ + + colon: function() { + return this.scan(/^: */, ':'); + }, + + /** + * Return the next token object, or those + * previously stashed by lookahead. + * + * @return {Object} + * @api private + */ + + advance: function(){ + return this.stashed() + || this.next(); + }, + + /** + * Return the next token object. + * + * @return {Object} + * @api private + */ + + next: function() { + return this.deferred() + || this.blank() + || this.eos() + || this.pipelessText() + || this.yield() + || this.doctype() + || this.interpolation() + || this["case"]() + || this.when() + || this["default"]() + || this["extends"]() + || this.append() + || this.prepend() + || this.block() + || this.include() + || this.mixin() + || this.call() + || this.conditional() + || this.each() + || this["while"]() + || this.assignment() + || this.tag() + || this.filter() + || this.code() + || this.id() + || this.className() + || this.attrs() + || this.indent() + || this.comment() + || this.colon() + || this.text(); + } +}; diff --git a/node_modules/jade/lib/nodes/attrs.js b/node_modules/jade/lib/nodes/attrs.js new file mode 100644 index 0000000..e7a6958 --- /dev/null +++ b/node_modules/jade/lib/nodes/attrs.js @@ -0,0 +1,79 @@ + +/*! + * Jade - nodes - Attrs + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'), + Block = require('./block'); + +/** + * Initialize a `Attrs` node. + * + * @api public + */ + +var Attrs = module.exports = function Attrs() { + this.attrs = []; +}; + +/** + * Inherit from `Node`. + */ + +Attrs.prototype = Object.create(Node.prototype); +Attrs.prototype.constructor = Attrs; +Attrs.prototype.constructor.name = 'Attrs'; // prevent the minifiers removing this + +/** + * Set attribute `name` to `val`, keep in mind these become + * part of a raw js object literal, so to quote a value you must + * '"quote me"', otherwise or example 'user.name' is literal JavaScript. + * + * @param {String} name + * @param {String} val + * @param {Boolean} escaped + * @return {Tag} for chaining + * @api public + */ + +Attrs.prototype.setAttribute = function(name, val, escaped){ + this.attrs.push({ name: name, val: val, escaped: escaped }); + return this; +}; + +/** + * Remove attribute `name` when present. + * + * @param {String} name + * @api public + */ + +Attrs.prototype.removeAttribute = function(name){ + for (var i = 0, len = this.attrs.length; i < len; ++i) { + if (this.attrs[i] && this.attrs[i].name == name) { + delete this.attrs[i]; + } + } +}; + +/** + * Get attribute value by `name`. + * + * @param {String} name + * @return {String} + * @api public + */ + +Attrs.prototype.getAttribute = function(name){ + for (var i = 0, len = this.attrs.length; i < len; ++i) { + if (this.attrs[i] && this.attrs[i].name == name) { + return this.attrs[i].val; + } + } +}; diff --git a/node_modules/jade/lib/nodes/block-comment.js b/node_modules/jade/lib/nodes/block-comment.js new file mode 100644 index 0000000..a124951 --- /dev/null +++ b/node_modules/jade/lib/nodes/block-comment.js @@ -0,0 +1,35 @@ + +/*! + * Jade - nodes - BlockComment + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a `BlockComment` with the given `block`. + * + * @param {String} val + * @param {Block} block + * @param {Boolean} buffer + * @api public + */ + +var BlockComment = module.exports = function BlockComment(val, block, buffer) { + this.block = block; + this.val = val; + this.buffer = buffer; +}; + +/** + * Inherit from `Node`. + */ + +BlockComment.prototype = Object.create(Node.prototype); +BlockComment.prototype.constructor = BlockComment; +BlockComment.prototype.constructor.name = 'BlockComment'; // prevent the minifiers removing this \ No newline at end of file diff --git a/node_modules/jade/lib/nodes/block.js b/node_modules/jade/lib/nodes/block.js new file mode 100644 index 0000000..a71e91b --- /dev/null +++ b/node_modules/jade/lib/nodes/block.js @@ -0,0 +1,125 @@ + +/*! + * Jade - nodes - Block + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Block` with an optional `node`. + * + * @param {Node} node + * @api public + */ + +var Block = module.exports = function Block(node){ + this.nodes = []; + if (node) this.push(node); +}; + +/** + * Inherit from `Node`. + */ + + +Block.prototype = Object.create(Node.prototype); +Block.prototype.constructor = Block; +Block.prototype.constructor.name = 'Block'; // prevent the minifiers removing this + +/** + * Block flag. + */ + +Block.prototype.isBlock = true; + +/** + * Replace the nodes in `other` with the nodes + * in `this` block. + * + * @param {Block} other + * @api private + */ + +Block.prototype.replace = function(other){ + other.nodes = this.nodes; +}; + +/** + * Pust the given `node`. + * + * @param {Node} node + * @return {Number} + * @api public + */ + +Block.prototype.push = function(node){ + return this.nodes.push(node); +}; + +/** + * Check if this block is empty. + * + * @return {Boolean} + * @api public + */ + +Block.prototype.isEmpty = function(){ + return 0 == this.nodes.length; +}; + +/** + * Unshift the given `node`. + * + * @param {Node} node + * @return {Number} + * @api public + */ + +Block.prototype.unshift = function(node){ + return this.nodes.unshift(node); +}; + +/** + * Return the "last" block, or the first `yield` node. + * + * @return {Block} + * @api private + */ + +Block.prototype.includeBlock = function(){ + var ret = this + , node; + + for (var i = 0, len = this.nodes.length; i < len; ++i) { + node = this.nodes[i]; + if (node.yield) return node; + else if (node.textOnly) continue; + else if (node.includeBlock) ret = node.includeBlock(); + else if (node.block && !node.block.isEmpty()) ret = node.block.includeBlock(); + if (ret.yield) return ret; + } + + return ret; +}; + +/** + * Return a clone of this block. + * + * @return {Block} + * @api private + */ + +Block.prototype.clone = function(){ + var clone = new Block; + for (var i = 0, len = this.nodes.length; i < len; ++i) { + clone.push(this.nodes[i].clone()); + } + return clone; +}; + diff --git a/node_modules/jade/lib/nodes/case.js b/node_modules/jade/lib/nodes/case.js new file mode 100644 index 0000000..818bcc2 --- /dev/null +++ b/node_modules/jade/lib/nodes/case.js @@ -0,0 +1,46 @@ + +/*! + * Jade - nodes - Case + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Case` with `expr`. + * + * @param {String} expr + * @api public + */ + +var Case = exports = module.exports = function Case(expr, block){ + this.expr = expr; + this.block = block; +}; + +/** + * Inherit from `Node`. + */ + +Case.prototype = Object.create(Node.prototype); +Case.prototype.constructor = Case; +Case.prototype.constructor.name = 'Case'; // prevent the minifiers removing this + +var When = exports.When = function When(expr, block){ + this.expr = expr; + this.block = block; + this.debug = false; +}; + +/** + * Inherit from `Node`. + */ + +When.prototype = Object.create(Node.prototype); +When.prototype.constructor = When; +When.prototype.constructor.name = 'When'; // prevent the minifiers removing this diff --git a/node_modules/jade/lib/nodes/code.js b/node_modules/jade/lib/nodes/code.js new file mode 100644 index 0000000..855710b --- /dev/null +++ b/node_modules/jade/lib/nodes/code.js @@ -0,0 +1,37 @@ + +/*! + * Jade - nodes - Code + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a `Code` node with the given code `val`. + * Code may also be optionally buffered and escaped. + * + * @param {String} val + * @param {Boolean} buffer + * @param {Boolean} escape + * @api public + */ + +var Code = module.exports = function Code(val, buffer, escape) { + this.val = val; + this.buffer = buffer; + this.escape = escape; + if (val.match(/^ *else/)) this.debug = false; +}; + +/** + * Inherit from `Node`. + */ + +Code.prototype = Object.create(Node.prototype); +Code.prototype.constructor = Code; +Code.prototype.constructor.name = 'Code'; // prevent the minifiers removing this \ No newline at end of file diff --git a/node_modules/jade/lib/nodes/comment.js b/node_modules/jade/lib/nodes/comment.js new file mode 100644 index 0000000..47cd6d4 --- /dev/null +++ b/node_modules/jade/lib/nodes/comment.js @@ -0,0 +1,34 @@ + +/*! + * Jade - nodes - Comment + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a `Comment` with the given `val`, optionally `buffer`, + * otherwise the comment may render in the output. + * + * @param {String} val + * @param {Boolean} buffer + * @api public + */ + +var Comment = module.exports = function Comment(val, buffer) { + this.val = val; + this.buffer = buffer; +}; + +/** + * Inherit from `Node`. + */ + +Comment.prototype = Object.create(Node.prototype); +Comment.prototype.constructor = Comment; +Comment.prototype.constructor.name = 'Comment'; // prevent the minifiers removing this \ No newline at end of file diff --git a/node_modules/jade/lib/nodes/doctype.js b/node_modules/jade/lib/nodes/doctype.js new file mode 100644 index 0000000..36b221f --- /dev/null +++ b/node_modules/jade/lib/nodes/doctype.js @@ -0,0 +1,31 @@ + +/*! + * Jade - nodes - Doctype + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a `Doctype` with the given `val`. + * + * @param {String} val + * @api public + */ + +var Doctype = module.exports = function Doctype(val) { + this.val = val; +}; + +/** + * Inherit from `Node`. + */ + +Doctype.prototype = Object.create(Node.prototype); +Doctype.prototype.constructor = Doctype; +Doctype.prototype.constructor.name = 'Doctype'; // prevent the minifiers removing this \ No newline at end of file diff --git a/node_modules/jade/lib/nodes/each.js b/node_modules/jade/lib/nodes/each.js new file mode 100644 index 0000000..28b65fa --- /dev/null +++ b/node_modules/jade/lib/nodes/each.js @@ -0,0 +1,37 @@ + +/*! + * Jade - nodes - Each + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize an `Each` node, representing iteration + * + * @param {String} obj + * @param {String} val + * @param {String} key + * @param {Block} block + * @api public + */ + +var Each = module.exports = function Each(obj, val, key, block) { + this.obj = obj; + this.val = val; + this.key = key; + this.block = block; +}; + +/** + * Inherit from `Node`. + */ + +Each.prototype = Object.create(Node.prototype); +Each.prototype.constructor = Each; +Each.prototype.constructor.name = 'Each'; // prevent the minifiers removing this \ No newline at end of file diff --git a/node_modules/jade/lib/nodes/filter.js b/node_modules/jade/lib/nodes/filter.js new file mode 100644 index 0000000..6bcfa98 --- /dev/null +++ b/node_modules/jade/lib/nodes/filter.js @@ -0,0 +1,36 @@ + +/*! + * Jade - nodes - Filter + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , Block = require('./block'); + +/** + * Initialize a `Filter` node with the given + * filter `name` and `block`. + * + * @param {String} name + * @param {Block|Node} block + * @api public + */ + +var Filter = module.exports = function Filter(name, block, attrs) { + this.name = name; + this.block = block; + this.attrs = attrs; +}; + +/** + * Inherit from `Node`. + */ + +Filter.prototype = Object.create(Node.prototype); +Filter.prototype.constructor = Filter; +Filter.prototype.constructor.name = 'Filter'; // prevent the minifiers removing this \ No newline at end of file diff --git a/node_modules/jade/lib/nodes/index.js b/node_modules/jade/lib/nodes/index.js new file mode 100644 index 0000000..c7782a9 --- /dev/null +++ b/node_modules/jade/lib/nodes/index.js @@ -0,0 +1,20 @@ + +/*! + * Jade - nodes + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +exports.Node = require('./node'); +exports.Tag = require('./tag'); +exports.Code = require('./code'); +exports.Each = require('./each'); +exports.Case = require('./case'); +exports.Text = require('./text'); +exports.Block = require('./block'); +exports.Mixin = require('./mixin'); +exports.Filter = require('./filter'); +exports.Comment = require('./comment'); +exports.Literal = require('./literal'); +exports.BlockComment = require('./block-comment'); +exports.Doctype = require('./doctype'); diff --git a/node_modules/jade/lib/nodes/literal.js b/node_modules/jade/lib/nodes/literal.js new file mode 100644 index 0000000..16929eb --- /dev/null +++ b/node_modules/jade/lib/nodes/literal.js @@ -0,0 +1,31 @@ + +/*! + * Jade - nodes - Literal + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a `Literal` node with the given `str. + * + * @param {String} str + * @api public + */ + +var Literal = module.exports = function Literal(str) { + this.str = str; +}; + +/** + * Inherit from `Node`. + */ + +Literal.prototype = Object.create(Node.prototype); +Literal.prototype.constructor = Literal; +Literal.prototype.constructor.name = 'Literal'; // prevent the minifiers removing this diff --git a/node_modules/jade/lib/nodes/mixin.js b/node_modules/jade/lib/nodes/mixin.js new file mode 100644 index 0000000..2a1af1d --- /dev/null +++ b/node_modules/jade/lib/nodes/mixin.js @@ -0,0 +1,37 @@ + +/*! + * Jade - nodes - Mixin + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Attrs = require('./attrs'); + +/** + * Initialize a new `Mixin` with `name` and `block`. + * + * @param {String} name + * @param {String} args + * @param {Block} block + * @api public + */ + +var Mixin = module.exports = function Mixin(name, args, block, call){ + this.name = name; + this.args = args; + this.block = block; + this.attrs = []; + this.call = call; +}; + +/** + * Inherit from `Attrs`. + */ + +Mixin.prototype = Object.create(Attrs.prototype); +Mixin.prototype.constructor = Mixin; +Mixin.prototype.constructor.name = 'Mixin'; // prevent the minifiers removing this diff --git a/node_modules/jade/lib/nodes/node.js b/node_modules/jade/lib/nodes/node.js new file mode 100644 index 0000000..aead311 --- /dev/null +++ b/node_modules/jade/lib/nodes/node.js @@ -0,0 +1,25 @@ + +/*! + * Jade - nodes - Node + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Initialize a `Node`. + * + * @api public + */ + +var Node = module.exports = function Node(){}; + +/** + * Clone this node (return itself) + * + * @return {Node} + * @api private + */ + +Node.prototype.clone = function(){ + return this; +}; diff --git a/node_modules/jade/lib/nodes/tag.js b/node_modules/jade/lib/nodes/tag.js new file mode 100644 index 0000000..22ef41b --- /dev/null +++ b/node_modules/jade/lib/nodes/tag.js @@ -0,0 +1,97 @@ + +/*! + * Jade - nodes - Tag + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Attrs = require('./attrs'), + Block = require('./block'), + inlineTags = require('../inline-tags'); + +/** + * Initialize a `Tag` node with the given tag `name` and optional `block`. + * + * @param {String} name + * @param {Block} block + * @api public + */ + +var Tag = module.exports = function Tag(name, block) { + this.name = name; + this.attrs = []; + this.block = block || new Block; +}; + +/** + * Inherit from `Attrs`. + */ + +Tag.prototype = Object.create(Attrs.prototype); +Tag.prototype.constructor = Tag; +Tag.prototype.constructor.name = 'Tag'; // prevent the minifiers removing this + +/** + * Clone this tag. + * + * @return {Tag} + * @api private + */ + +Tag.prototype.clone = function(){ + var clone = new Tag(this.name, this.block.clone()); + clone.line = this.line; + clone.attrs = this.attrs; + clone.textOnly = this.textOnly; + return clone; +}; + +/** + * Check if this tag is an inline tag. + * + * @return {Boolean} + * @api private + */ + +Tag.prototype.isInline = function(){ + return ~inlineTags.indexOf(this.name); +}; + +/** + * Check if this tag's contents can be inlined. Used for pretty printing. + * + * @return {Boolean} + * @api private + */ + +Tag.prototype.canInline = function(){ + var nodes = this.block.nodes; + + function isInline(node){ + // Recurse if the node is a block + if (node.isBlock) return node.nodes.every(isInline); + return node.isText || (node.isInline && node.isInline()); + } + + // Empty tag + if (!nodes.length) return true; + + // Text-only or inline-only tag + if (1 == nodes.length) return isInline(nodes[0]); + + // Multi-line inline-only tag + if (this.block.nodes.every(isInline)) { + for (var i = 1, len = nodes.length; i < len; ++i) { + if (nodes[i-1].isText && nodes[i].isText) + return false; + } + return true; + } + + // Mixed tag + return false; +}; \ No newline at end of file diff --git a/node_modules/jade/lib/nodes/text.js b/node_modules/jade/lib/nodes/text.js new file mode 100644 index 0000000..94cddc4 --- /dev/null +++ b/node_modules/jade/lib/nodes/text.js @@ -0,0 +1,38 @@ + +/*! + * Jade - nodes - Text + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a `Text` node with optional `line`. + * + * @param {String} line + * @api public + */ + +var Text = module.exports = function Text(line) { + this.val = ''; + if ('string' == typeof line) this.val = line; +}; + +/** + * Inherit from `Node`. + */ + +Text.prototype = Object.create(Node.prototype); +Text.prototype.constructor = Text; +Text.prototype.constructor.name = 'Text'; // prevent the minifiers removing this + +/** + * Flag as text. + */ + +Text.prototype.isText = true; \ No newline at end of file diff --git a/node_modules/jade/lib/parser.js b/node_modules/jade/lib/parser.js new file mode 100644 index 0000000..ec19ea2 --- /dev/null +++ b/node_modules/jade/lib/parser.js @@ -0,0 +1,735 @@ +/*! + * Jade - Parser + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Lexer = require('./lexer') + , nodes = require('./nodes') + , utils = require('./utils') + , filters = require('./filters') + , path = require('path') + , extname = path.extname; + +/** + * Initialize `Parser` with the given input `str` and `filename`. + * + * @param {String} str + * @param {String} filename + * @param {Object} options + * @api public + */ + +var Parser = exports = module.exports = function Parser(str, filename, options){ + //Strip any UTF-8 BOM off of the start of `str`, if it exists. + this.input = str.replace(/^\uFEFF/, ''); + this.lexer = new Lexer(this.input, options); + this.filename = filename; + this.blocks = {}; + this.mixins = {}; + this.options = options; + this.contexts = [this]; +}; + +/** + * Tags that may not contain tags. + */ + +var textOnly = exports.textOnly = ['script', 'style']; + +/** + * Parser prototype. + */ + +Parser.prototype = { + + /** + * Push `parser` onto the context stack, + * or pop and return a `Parser`. + */ + + context: function(parser){ + if (parser) { + this.contexts.push(parser); + } else { + return this.contexts.pop(); + } + }, + + /** + * Return the next token object. + * + * @return {Object} + * @api private + */ + + advance: function(){ + return this.lexer.advance(); + }, + + /** + * Skip `n` tokens. + * + * @param {Number} n + * @api private + */ + + skip: function(n){ + while (n--) this.advance(); + }, + + /** + * Single token lookahead. + * + * @return {Object} + * @api private + */ + + peek: function() { + return this.lookahead(1); + }, + + /** + * Return lexer lineno. + * + * @return {Number} + * @api private + */ + + line: function() { + return this.lexer.lineno; + }, + + /** + * `n` token lookahead. + * + * @param {Number} n + * @return {Object} + * @api private + */ + + lookahead: function(n){ + return this.lexer.lookahead(n); + }, + + /** + * Parse input returning a string of js for evaluation. + * + * @return {String} + * @api public + */ + + parse: function(){ + var block = new nodes.Block, parser; + block.line = this.line(); + + while ('eos' != this.peek().type) { + if ('newline' == this.peek().type) { + this.advance(); + } else { + block.push(this.parseExpr()); + } + } + + if (parser = this.extending) { + this.context(parser); + var ast = parser.parse(); + this.context(); + + // hoist mixins + for (var name in this.mixins) + ast.unshift(this.mixins[name]); + return ast; + } + + return block; + }, + + /** + * Expect the given type, or throw an exception. + * + * @param {String} type + * @api private + */ + + expect: function(type){ + if (this.peek().type === type) { + return this.advance(); + } else { + throw new Error('expected "' + type + '", but got "' + this.peek().type + '"'); + } + }, + + /** + * Accept the given `type`. + * + * @param {String} type + * @api private + */ + + accept: function(type){ + if (this.peek().type === type) { + return this.advance(); + } + }, + + /** + * tag + * | doctype + * | mixin + * | include + * | filter + * | comment + * | text + * | each + * | code + * | yield + * | id + * | class + * | interpolation + */ + + parseExpr: function(){ + switch (this.peek().type) { + case 'tag': + return this.parseTag(); + case 'mixin': + return this.parseMixin(); + case 'block': + return this.parseBlock(); + case 'case': + return this.parseCase(); + case 'when': + return this.parseWhen(); + case 'default': + return this.parseDefault(); + case 'extends': + return this.parseExtends(); + case 'include': + return this.parseInclude(); + case 'doctype': + return this.parseDoctype(); + case 'filter': + return this.parseFilter(); + case 'comment': + return this.parseComment(); + case 'text': + return this.parseText(); + case 'each': + return this.parseEach(); + case 'code': + return this.parseCode(); + case 'call': + return this.parseCall(); + case 'interpolation': + return this.parseInterpolation(); + case 'yield': + this.advance(); + var block = new nodes.Block; + block.yield = true; + return block; + case 'id': + case 'class': + var tok = this.advance(); + this.lexer.defer(this.lexer.tok('tag', 'div')); + this.lexer.defer(tok); + return this.parseExpr(); + default: + throw new Error('unexpected token "' + this.peek().type + '"'); + } + }, + + /** + * Text + */ + + parseText: function(){ + var tok = this.expect('text'); + var node = new nodes.Text(tok.val); + node.line = this.line(); + return node; + }, + + /** + * ':' expr + * | block + */ + + parseBlockExpansion: function(){ + if (':' == this.peek().type) { + this.advance(); + return new nodes.Block(this.parseExpr()); + } else { + return this.block(); + } + }, + + /** + * case + */ + + parseCase: function(){ + var val = this.expect('case').val; + var node = new nodes.Case(val); + node.line = this.line(); + node.block = this.block(); + return node; + }, + + /** + * when + */ + + parseWhen: function(){ + var val = this.expect('when').val + return new nodes.Case.When(val, this.parseBlockExpansion()); + }, + + /** + * default + */ + + parseDefault: function(){ + this.expect('default'); + return new nodes.Case.When('default', this.parseBlockExpansion()); + }, + + /** + * code + */ + + parseCode: function(){ + var tok = this.expect('code'); + var node = new nodes.Code(tok.val, tok.buffer, tok.escape); + var block; + var i = 1; + node.line = this.line(); + while (this.lookahead(i) && 'newline' == this.lookahead(i).type) ++i; + block = 'indent' == this.lookahead(i).type; + if (block) { + this.skip(i-1); + node.block = this.block(); + } + return node; + }, + + /** + * comment + */ + + parseComment: function(){ + var tok = this.expect('comment'); + var node; + + if ('indent' == this.peek().type) { + node = new nodes.BlockComment(tok.val, this.block(), tok.buffer); + } else { + node = new nodes.Comment(tok.val, tok.buffer); + } + + node.line = this.line(); + return node; + }, + + /** + * doctype + */ + + parseDoctype: function(){ + var tok = this.expect('doctype'); + var node = new nodes.Doctype(tok.val); + node.line = this.line(); + return node; + }, + + /** + * filter attrs? text-block + */ + + parseFilter: function(){ + var tok = this.expect('filter'); + var attrs = this.accept('attrs'); + var block; + + if ('indent' == this.peek().type) { + this.lexer.pipeless = true; + block = this.parseTextBlock(); + this.lexer.pipeless = false; + } else block = new nodes.Block; + + var node = new nodes.Filter(tok.val, block, attrs && attrs.attrs); + node.line = this.line(); + return node; + }, + + /** + * each block + */ + + parseEach: function(){ + var tok = this.expect('each'); + var node = new nodes.Each(tok.code, tok.val, tok.key); + node.line = this.line(); + node.block = this.block(); + if (this.peek().type == 'code' && this.peek().val == 'else') { + this.advance(); + node.alternative = this.block(); + } + return node; + }, + + /** + * Resolves a path relative to the template for use in + * includes and extends + * + * @param {String} path + * @param {String} purpose Used in error messages. + * @return {String} + * @api private + */ + + resolvePath: function (path, purpose) { + var p = require('path'); + var dirname = p.dirname; + var basename = p.basename; + var join = p.join; + + if (path[0] !== '/' && !this.filename) + throw new Error('the "filename" option is required to use "' + purpose + '" with "relative" paths'); + + if (path[0] === '/' && !this.options.basedir) + throw new Error('the "basedir" option is required to use "' + purpose + '" with "absolute" paths'); + + path = join(path[0] === '/' ? this.options.basedir : dirname(this.filename), path); + + if (basename(path).indexOf('.') === -1) path += '.jade'; + + return path; + }, + + /** + * 'extends' name + */ + + parseExtends: function(){ + var fs = require('fs'); + + var path = this.resolvePath(this.expect('extends').val.trim(), 'extends'); + if ('.jade' != path.substr(-5)) path += '.jade'; + + var str = fs.readFileSync(path, 'utf8'); + var parser = new Parser(str, path, this.options); + + parser.blocks = this.blocks; + parser.contexts = this.contexts; + this.extending = parser; + + // TODO: null node + return new nodes.Literal(''); + }, + + /** + * 'block' name block + */ + + parseBlock: function(){ + var block = this.expect('block'); + var mode = block.mode; + var name = block.val.trim(); + + block = 'indent' == this.peek().type + ? this.block() + : new nodes.Block(new nodes.Literal('')); + + var prev = this.blocks[name] || {prepended: [], appended: []} + if (prev.mode === 'replace') return this.blocks[name] = prev; + + var allNodes = prev.prepended.concat(block.nodes).concat(prev.appended); + + switch (mode) { + case 'append': + prev.appended = prev.parser === this ? + prev.appended.concat(block.nodes) : + block.nodes.concat(prev.appended); + break; + case 'prepend': + prev.prepended = prev.parser === this ? + block.nodes.concat(prev.prepended) : + prev.prepended.concat(block.nodes); + break; + } + block.nodes = allNodes; + block.appended = prev.appended; + block.prepended = prev.prepended; + block.mode = mode; + block.parser = this; + + return this.blocks[name] = block; + }, + + /** + * include block? + */ + + parseInclude: function(){ + var fs = require('fs'); + + var path = this.resolvePath(this.expect('include').val.trim(), 'include'); + + // non-jade + if ('.jade' != path.substr(-5)) { + var str = fs.readFileSync(path, 'utf8').replace(/\r/g, ''); + var ext = extname(path).slice(1); + if (filters.exists(ext)) str = filters(ext, str, { filename: path }); + return new nodes.Literal(str); + } + + var str = fs.readFileSync(path, 'utf8'); + var parser = new Parser(str, path, this.options); + parser.blocks = utils.merge({}, this.blocks); + + parser.mixins = this.mixins; + + this.context(parser); + var ast = parser.parse(); + this.context(); + ast.filename = path; + + if ('indent' == this.peek().type) { + ast.includeBlock().push(this.block()); + } + + return ast; + }, + + /** + * call ident block + */ + + parseCall: function(){ + var tok = this.expect('call'); + var name = tok.val; + var args = tok.args; + var mixin = new nodes.Mixin(name, args, new nodes.Block, true); + + this.tag(mixin); + if (mixin.code) { + mixin.block.push(mixin.code); + mixin.code = null; + } + if (mixin.block.isEmpty()) mixin.block = null; + return mixin; + }, + + /** + * mixin block + */ + + parseMixin: function(){ + var tok = this.expect('mixin'); + var name = tok.val; + var args = tok.args; + var mixin; + + // definition + if ('indent' == this.peek().type) { + mixin = new nodes.Mixin(name, args, this.block(), false); + this.mixins[name] = mixin; + return mixin; + // call + } else { + return new nodes.Mixin(name, args, null, true); + } + }, + + /** + * indent (text | newline)* outdent + */ + + parseTextBlock: function(){ + var block = new nodes.Block; + block.line = this.line(); + var spaces = this.expect('indent').val; + if (null == this._spaces) this._spaces = spaces; + var indent = Array(spaces - this._spaces + 1).join(' '); + while ('outdent' != this.peek().type) { + switch (this.peek().type) { + case 'newline': + this.advance(); + break; + case 'indent': + this.parseTextBlock().nodes.forEach(function(node){ + block.push(node); + }); + break; + default: + var text = new nodes.Text(indent + this.advance().val); + text.line = this.line(); + block.push(text); + } + } + + if (spaces == this._spaces) this._spaces = null; + this.expect('outdent'); + return block; + }, + + /** + * indent expr* outdent + */ + + block: function(){ + var block = new nodes.Block; + block.line = this.line(); + this.expect('indent'); + while ('outdent' != this.peek().type) { + if ('newline' == this.peek().type) { + this.advance(); + } else { + block.push(this.parseExpr()); + } + } + this.expect('outdent'); + return block; + }, + + /** + * interpolation (attrs | class | id)* (text | code | ':')? newline* block? + */ + + parseInterpolation: function(){ + var tok = this.advance(); + var tag = new nodes.Tag(tok.val); + tag.buffer = true; + return this.tag(tag); + }, + + /** + * tag (attrs | class | id)* (text | code | ':')? newline* block? + */ + + parseTag: function(){ + // ast-filter look-ahead + var i = 2; + if ('attrs' == this.lookahead(i).type) ++i; + + var tok = this.advance(); + var tag = new nodes.Tag(tok.val); + + tag.selfClosing = tok.selfClosing; + + return this.tag(tag); + }, + + /** + * Parse tag. + */ + + tag: function(tag){ + var dot; + + tag.line = this.line(); + + var seenAttrs = false; + // (attrs | class | id)* + out: + while (true) { + switch (this.peek().type) { + case 'id': + case 'class': + var tok = this.advance(); + tag.setAttribute(tok.type, "'" + tok.val + "'"); + continue; + case 'attrs': + if (seenAttrs) { + console.warn('You should not have jade tags with multiple attributes.'); + } + seenAttrs = true; + var tok = this.advance() + , obj = tok.attrs + , escaped = tok.escaped + , names = Object.keys(obj); + + if (tok.selfClosing) tag.selfClosing = true; + + for (var i = 0, len = names.length; i < len; ++i) { + var name = names[i] + , val = obj[name]; + tag.setAttribute(name, val, escaped[name]); + } + continue; + default: + break out; + } + } + + // check immediate '.' + if ('.' == this.peek().val) { + dot = tag.textOnly = true; + this.advance(); + } + + // (text | code | ':')? + switch (this.peek().type) { + case 'text': + tag.block.push(this.parseText()); + break; + case 'code': + tag.code = this.parseCode(); + break; + case ':': + this.advance(); + tag.block = new nodes.Block; + tag.block.push(this.parseExpr()); + break; + case 'newline': + case 'indent': + case 'outdent': + case 'eos': + break; + default: + throw new Error('Unexpected token `' + this.peek().type + '` expected `text`, `code`, `:`, `newline` or `eos`') + } + + // newline* + while ('newline' == this.peek().type) this.advance(); + + tag.textOnly = tag.textOnly || ~textOnly.indexOf(tag.name); + + // script special-case + if ('script' == tag.name) { + var type = tag.getAttribute('type'); + if (!dot && type && 'text/javascript' != type.replace(/^['"]|['"]$/g, '')) { + tag.textOnly = false; + } + } + + // block? + if ('indent' == this.peek().type) { + if (tag.textOnly) { + if (!dot) { + console.warn(this.filename + ', line ' + this.peek().line + ':') + console.warn('Implicit textOnly for `script` and `style` is deprecated. Use `script.` or `style.` instead.'); + } + this.lexer.pipeless = true; + tag.block = this.parseTextBlock(); + this.lexer.pipeless = false; + } else { + var block = this.block(); + if (tag.block) { + for (var i = 0, len = block.nodes.length; i < len; ++i) { + tag.block.push(block.nodes[i]); + } + } else { + tag.block = block; + } + } + } + + return tag; + } +}; diff --git a/node_modules/jade/lib/runtime.js b/node_modules/jade/lib/runtime.js new file mode 100644 index 0000000..804f616 --- /dev/null +++ b/node_modules/jade/lib/runtime.js @@ -0,0 +1,199 @@ + +/*! + * Jade - runtime + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Lame Array.isArray() polyfill for now. + */ + +if (!Array.isArray) { + Array.isArray = function(arr){ + return '[object Array]' == Object.prototype.toString.call(arr); + }; +} + +/** + * Lame Object.keys() polyfill for now. + */ + +if (!Object.keys) { + Object.keys = function(obj){ + var arr = []; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + arr.push(key); + } + } + return arr; + } +} + +/** + * Merge two attribute objects giving precedence + * to values in object `b`. Classes are special-cased + * allowing for arrays and merging/joining appropriately + * resulting in a string. + * + * @param {Object} a + * @param {Object} b + * @return {Object} a + * @api private + */ + +exports.merge = function merge(a, b) { + var ac = a['class']; + var bc = b['class']; + + if (ac || bc) { + ac = ac || []; + bc = bc || []; + if (!Array.isArray(ac)) ac = [ac]; + if (!Array.isArray(bc)) bc = [bc]; + a['class'] = ac.concat(bc).filter(nulls); + } + + for (var key in b) { + if (key != 'class') { + a[key] = b[key]; + } + } + + return a; +}; + +/** + * Filter null `val`s. + * + * @param {*} val + * @return {Boolean} + * @api private + */ + +function nulls(val) { + return val != null && val !== ''; +} + +/** + * join array as classes. + * + * @param {*} val + * @return {String} + * @api private + */ + +function joinClasses(val) { + return Array.isArray(val) ? val.map(joinClasses).filter(nulls).join(' ') : val; +} + +/** + * Render the given attributes object. + * + * @param {Object} obj + * @param {Object} escaped + * @return {String} + * @api private + */ + +exports.attrs = function attrs(obj, escaped){ + var buf = [] + , terse = obj.terse; + + delete obj.terse; + var keys = Object.keys(obj) + , len = keys.length; + + if (len) { + buf.push(''); + for (var i = 0; i < len; ++i) { + var key = keys[i] + , val = obj[key]; + + if ('boolean' == typeof val || null == val) { + if (val) { + terse + ? buf.push(key) + : buf.push(key + '="' + key + '"'); + } + } else if (0 == key.indexOf('data') && 'string' != typeof val) { + buf.push(key + "='" + JSON.stringify(val) + "'"); + } else if ('class' == key) { + if (escaped && escaped[key]){ + if (val = exports.escape(joinClasses(val))) { + buf.push(key + '="' + val + '"'); + } + } else { + if (val = joinClasses(val)) { + buf.push(key + '="' + val + '"'); + } + } + } else if (escaped && escaped[key]) { + buf.push(key + '="' + exports.escape(val) + '"'); + } else { + buf.push(key + '="' + val + '"'); + } + } + } + + return buf.join(' '); +}; + +/** + * Escape the given string of `html`. + * + * @param {String} html + * @return {String} + * @api private + */ + +exports.escape = function escape(html){ + return String(html) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +}; + +/** + * Re-throw the given `err` in context to the + * the jade in `filename` at the given `lineno`. + * + * @param {Error} err + * @param {String} filename + * @param {String} lineno + * @api private + */ + +exports.rethrow = function rethrow(err, filename, lineno, str){ + if (!(err instanceof Error)) throw err; + if ((typeof window != 'undefined' || !filename) && !str) { + err.message += ' on line ' + lineno; + throw err; + } + try { + str = str || require('fs').readFileSync(filename, 'utf8') + } catch (ex) { + rethrow(err, null, lineno) + } + var context = 3 + , lines = str.split('\n') + , start = Math.max(lineno - context, 0) + , end = Math.min(lines.length, lineno + context); + + // Error context + var context = lines.slice(start, end).map(function(line, i){ + var curr = i + start + 1; + return (curr == lineno ? ' > ' : ' ') + + curr + + '| ' + + line; + }).join('\n'); + + // Alter exception message + err.path = filename; + err.message = (filename || 'Jade') + ':' + lineno + + '\n' + context + '\n\n' + err.message; + throw err; +}; diff --git a/node_modules/jade/lib/self-closing.js b/node_modules/jade/lib/self-closing.js new file mode 100644 index 0000000..2e92288 --- /dev/null +++ b/node_modules/jade/lib/self-closing.js @@ -0,0 +1,19 @@ + +/*! + * Jade - self closing tags + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +module.exports = [ + 'meta' + , 'img' + , 'link' + , 'input' + , 'source' + , 'area' + , 'base' + , 'col' + , 'br' + , 'hr' +]; \ No newline at end of file diff --git a/node_modules/jade/lib/utils.js b/node_modules/jade/lib/utils.js new file mode 100644 index 0000000..b7f6bf1 --- /dev/null +++ b/node_modules/jade/lib/utils.js @@ -0,0 +1,21 @@ + +/*! + * Jade - utils + * Copyright(c) 2010 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Merge `b` into `a`. + * + * @param {Object} a + * @param {Object} b + * @return {Object} + * @api public + */ + +exports.merge = function(a, b) { + for (var key in b) a[key] = b[key]; + return a; +}; + diff --git a/node_modules/jade/node_modules/character-parser/.npmignore b/node_modules/jade/node_modules/character-parser/.npmignore new file mode 100644 index 0000000..2a72174 --- /dev/null +++ b/node_modules/jade/node_modules/character-parser/.npmignore @@ -0,0 +1,2 @@ +test/ +.travis.yml \ No newline at end of file diff --git a/node_modules/jade/node_modules/character-parser/LICENSE b/node_modules/jade/node_modules/character-parser/LICENSE new file mode 100644 index 0000000..2ecc0d1 --- /dev/null +++ b/node_modules/jade/node_modules/character-parser/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013 Forbes Lindesay + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/jade/node_modules/character-parser/README.md b/node_modules/jade/node_modules/character-parser/README.md new file mode 100644 index 0000000..22fab2d --- /dev/null +++ b/node_modules/jade/node_modules/character-parser/README.md @@ -0,0 +1,142 @@ +# character-parser + +Parse JavaScript one character at a time to look for snippets in Templates. This is not a validator, it's just designed to allow you to have sections of JavaScript delimited by brackets robustly. + +[![Build Status](https://travis-ci.org/ForbesLindesay/character-parser.png?branch=master)](https://travis-ci.org/ForbesLindesay/character-parser) + +## Installation + + npm install character-parser + +## Usage + +Work out how much depth changes: + +```js +var state = parse('foo(arg1, arg2, {\n foo: [a, b\n'); +assert(state.roundDepth === 1); +assert(state.curlyDepth === 1); +assert(state.squareDepth === 1); +parse(' c, d]\n })', state); +assert(state.squareDepth === 0); +assert(state.curlyDepth === 0); +assert(state.roundDepth === 0); +``` + +### Bracketed Expressions + +Find all the contents of a bracketed expression: + +```js +var section = parser.parseMax('foo="(", bar="}") bing bong'); +assert(section.start === 0); +assert(section.end === 16);//exclusive end of string +assert(section.src = 'foo="(", bar="}"'); + + +var section = parser.parseMax('{foo="(", bar="}"} bing bong', {start: 1}); +assert(section.start === 1); +assert(section.end === 17);//exclusive end of string +assert(section.src = 'foo="(", bar="}"'); +``` + +The bracketed expression parsing simply parses up to but excluding the first unmatched closed bracket (`)`, `}`, `]`). It is clever enough to ignore brackets in comments or strings. + + +### Custom Delimited Expressions + +Find code up to a custom delimiter: + +```js +var section = parser.parseUntil('foo.bar("%>").baz%> bing bong', '%>'); +assert(section.start === 0); +assert(section.end === 17);//exclusive end of string +assert(section.src = 'foo.bar("%>").baz'); + +var section = parser.parseUntil('<%foo.bar("%>").baz%> bing bong', '%>', {start: 2}); +assert(section.start === 2); +assert(section.end === 19);//exclusive end of string +assert(section.src = 'foo.bar("%>").baz'); +``` + +Delimiters are ignored if they are inside strings or comments. + +## API + +### parse(str, state = defaultState(), options = {start: 0, end: src.length}) + +Parse a string starting at the index start, and return the state after parsing that string. + +If you want to parse one string in multiple sections you should keep passing the resulting state to the next parse operation. + +Returns a `State` object. + +### parseMax(src, options = {start: 0}) + +Parses the source until the first unmatched close bracket (any of `)`, `}`, `]`). It returns an object with the structure: + +```js +{ + start: 0,//index of first character of string + end: 13,//index of first character after the end of string + src: 'source string' +} +``` + +### parseUntil(src, delimiter, options = {start: 0, includeLineComment: false}) + +Parses the source until the first occurence of `delimiter` which is not in a string or a comment. If `includeLineComment` is `true`, it will still count if the delimiter occurs in a line comment, but not in a block comment. It returns an object with the structure: + +```js +{ + start: 0,//index of first character of string + end: 13,//index of first character after the end of string + src: 'source string' +} +``` + +### parseChar(character, state = defaultState()) + +Parses the single character and returns the state. See `parse` for the structure of the returned state object. N.B. character must be a single character not a multi character string. + +### defaultState() + +Get a default starting state. + +### isPunctuator(character) + +Returns `true` if `character` represents punctuation in JavaScript. + +### isKeyword(name) + +Returns `true` if `name` is a keyword in JavaScript. + +## State + +A state is an object with the following structure + +```js +{ + lineComment: false, //true if inside a line comment + blockComment: false, //true if inside a block comment + + singleQuote: false, //true if inside a single quoted string + doubleQuote: false, //true if inside a double quoted string + regexp: false, //true if inside a regular expression + escaped: false, //true if in a string and the last character was an escape character + + roundDepth: 0, //number of un-closed open `(` brackets + curlyDepth: 0, //number of un-closed open `{` brackets + squareDepth: 0 //number of un-closed open `[` brackets +} +``` + +It also has the following useful methods: + +- `.isString()` returns `true` if the current location is inside a string. +- `.isComment()` returns `true` if the current location is inside a comment. +- `isNesting()` returns `true` if the current location is anything but at the top level, i.e. with no nesting. + +## License + +MIT \ No newline at end of file diff --git a/node_modules/jade/node_modules/character-parser/index.js b/node_modules/jade/node_modules/character-parser/index.js new file mode 100644 index 0000000..4707f0a --- /dev/null +++ b/node_modules/jade/node_modules/character-parser/index.js @@ -0,0 +1,217 @@ +exports = (module.exports = parse); +exports.parse = parse; +function parse(src, state, options) { + options = options || {}; + state = state || exports.defaultState(); + var start = options.start || 0; + var end = options.end || src.length; + var index = start; + while (index < end) { + if (state.roundDepth < 0 || state.curlyDepth < 0 || state.squareDepth < 0) { + throw new SyntaxError('Mismatched Bracket: ' + src[index - 1]); + } + exports.parseChar(src[index++], state); + } + return state; +} + +exports.parseMax = parseMax; +function parseMax(src, options) { + options = options || {}; + var start = options.start || 0; + var index = start; + var state = exports.defaultState(); + while (state.roundDepth >= 0 && state.curlyDepth >= 0 && state.squareDepth >= 0) { + if (index >= src.length) { + throw new Error('The end of the string was reached with no closing bracket found.'); + } + exports.parseChar(src[index++], state); + } + var end = index - 1; + return { + start: start, + end: end, + src: src.substring(start, end) + }; +} + +exports.parseUntil = parseUntil; +function parseUntil(src, delimiter, options) { + options = options || {}; + var includeLineComment = options.includeLineComment || false; + var start = options.start || 0; + var index = start; + var state = exports.defaultState(); + while (state.isString() || state.regexp || state.blockComment || + (!includeLineComment && state.lineComment) || !startsWith(src, delimiter, index)) { + exports.parseChar(src[index++], state); + } + var end = index; + return { + start: start, + end: end, + src: src.substring(start, end) + }; +} + + +exports.parseChar = parseChar; +function parseChar(character, state) { + if (character.length !== 1) throw new Error('Character must be a string of length 1'); + state = state || exports.defaultState(); + var wasComment = state.blockComment || state.lineComment; + var lastChar = state.history ? state.history[0] : ''; + if (state.lineComment) { + if (character === '\n') { + state.lineComment = false; + } + } else if (state.blockComment) { + if (state.lastChar === '*' && character === '/') { + state.blockComment = false; + } + } else if (state.singleQuote) { + if (character === '\'' && !state.escaped) { + state.singleQuote = false; + } else if (character === '\\' && !state.escaped) { + state.escaped = true; + } else { + state.escaped = false; + } + } else if (state.doubleQuote) { + if (character === '"' && !state.escaped) { + state.doubleQuote = false; + } else if (character === '\\' && !state.escaped) { + state.escaped = true; + } else { + state.escaped = false; + } + } else if (state.regexp) { + if (character === '/' && !state.escaped) { + state.regexp = false; + } else if (character === '\\' && !state.escaped) { + state.escaped = true; + } else { + state.escaped = false; + } + } else if (lastChar === '/' && character === '/') { + state.history = state.history.substr(1); + state.lineComment = true; + } else if (lastChar === '/' && character === '*') { + state.history = state.history.substr(1); + state.blockComment = true; + } else if (character === '/' && isRegexp(state.history)) { + state.regexp = true; + } else if (character === '\'') { + state.singleQuote = true; + } else if (character === '"') { + state.doubleQuote = true; + } else if (character === '(') { + state.roundDepth++; + } else if (character === ')') { + state.roundDepth--; + } else if (character === '{') { + state.curlyDepth++; + } else if (character === '}') { + state.curlyDepth--; + } else if (character === '[') { + state.squareDepth++; + } else if (character === ']') { + state.squareDepth--; + } + if (!state.blockComment && !state.lineComment && !wasComment) state.history = character + state.history; + return state; +} + +exports.defaultState = function () { return new State() }; +function State() { + this.lineComment = false; + this.blockComment = false; + + this.singleQuote = false; + this.doubleQuote = false; + this.regexp = false; + this.escaped = false; + + this.roundDepth = 0; + this.curlyDepth = 0; + this.squareDepth = 0; + + this.history = '' +} +State.prototype.isString = function () { + return this.singleQuote || this.doubleQuote; +} +State.prototype.isComment = function () { + return this.lineComment || this.blockComment; +} +State.prototype.isNesting = function () { + return this.isString() || this.isComment() || this.regexp || this.roundDepth > 0 || this.curlyDepth > 0 || this.squareDepth > 0 +} + +function startsWith(str, start, i) { + return str.substr(i || 0, start.length) === start; +} + +exports.isPunctuator = isPunctuator +function isPunctuator(c) { + var code = c.charCodeAt(0) + + switch (code) { + case 46: // . dot + case 40: // ( open bracket + case 41: // ) close bracket + case 59: // ; semicolon + case 44: // , comma + case 123: // { open curly brace + case 125: // } close curly brace + case 91: // [ + case 93: // ] + case 58: // : + case 63: // ? + case 126: // ~ + case 37: // % + case 38: // & + case 42: // *: + case 43: // + + case 45: // - + case 47: // / + case 60: // < + case 62: // > + case 94: // ^ + case 124: // | + case 33: // ! + case 61: // = + return true; + default: + return false; + } +} +exports.isKeyword = isKeyword +function isKeyword(id) { + return (id === 'if') || (id === 'in') || (id === 'do') || (id === 'var') || (id === 'for') || (id === 'new') || + (id === 'try') || (id === 'let') || (id === 'this') || (id === 'else') || (id === 'case') || + (id === 'void') || (id === 'with') || (id === 'enum') || (id === 'while') || (id === 'break') || (id === 'catch') || + (id === 'throw') || (id === 'const') || (id === 'yield') || (id === 'class') || (id === 'super') || + (id === 'return') || (id === 'typeof') || (id === 'delete') || (id === 'switch') || (id === 'export') || + (id === 'import') || (id === 'default') || (id === 'finally') || (id === 'extends') || (id === 'function') || + (id === 'continue') || (id === 'debugger') || (id === 'package') || (id === 'private') || (id === 'interface') || + (id === 'instanceof') || (id === 'implements') || (id === 'protected') || (id === 'public') || (id === 'static') || + (id === 'yield') || (id === 'let'); +} + +function isRegexp(history) { + //could be start of regexp or divide sign + + history = history.replace(/^\s*/, ''); + + //unless its an `if`, `while`, `for` or `with` it's a divide, so we assume it's a divide + if (history[0] === ')') return false; + //unless it's a function expression, it's a regexp, so we assume it's a regexp + if (history[0] === '}') return true; + //any punctuation means it's a regexp + if (isPunctuator(history[0])) return true; + //if the last thing was a keyword then it must be a regexp (e.g. `typeof /foo/`) + if (/^\w+\b/.test(history) && isKeyword(/^\w+\b/.exec(history)[0].split('').reverse().join(''))) return true; + + return false; +} diff --git a/node_modules/jade/node_modules/character-parser/package.json b/node_modules/jade/node_modules/character-parser/package.json new file mode 100644 index 0000000..f98e054 --- /dev/null +++ b/node_modules/jade/node_modules/character-parser/package.json @@ -0,0 +1,42 @@ +{ + "name": "character-parser", + "version": "1.2.0", + "description": "Parse JavaScript one character at a time to look for snippets in Templates. This is not a validator, it's just designed to allow you to have sections of JavaScript delimited by brackets robustly.", + "main": "index.js", + "scripts": { + "test": "mocha -R spec" + }, + "repository": { + "type": "git", + "url": "https://github.com/ForbesLindesay/character-parser.git" + }, + "keywords": [ + "parser", + "JavaScript", + "bracket", + "nesting", + "comment", + "string", + "escape", + "escaping" + ], + "author": { + "name": "ForbesLindesay" + }, + "license": "MIT", + "devDependencies": { + "better-assert": "~1.0.0", + "mocha": "~1.9.0" + }, + "readme": "# character-parser\r\n\r\nParse JavaScript one character at a time to look for snippets in Templates. This is not a validator, it's just designed to allow you to have sections of JavaScript delimited by brackets robustly.\r\n\r\n[![Build Status](https://travis-ci.org/ForbesLindesay/character-parser.png?branch=master)](https://travis-ci.org/ForbesLindesay/character-parser)\r\n\r\n## Installation\r\n\r\n npm install character-parser\r\n\r\n## Usage\r\n\r\nWork out how much depth changes:\r\n\r\n```js\r\nvar state = parse('foo(arg1, arg2, {\\n foo: [a, b\\n');\r\nassert(state.roundDepth === 1);\r\nassert(state.curlyDepth === 1);\r\nassert(state.squareDepth === 1);\r\nparse(' c, d]\\n })', state);\r\nassert(state.squareDepth === 0);\r\nassert(state.curlyDepth === 0);\r\nassert(state.roundDepth === 0);\r\n```\r\n\r\n### Bracketed Expressions\r\n\r\nFind all the contents of a bracketed expression:\r\n\r\n```js\r\nvar section = parser.parseMax('foo=\"(\", bar=\"}\") bing bong');\r\nassert(section.start === 0);\r\nassert(section.end === 16);//exclusive end of string\r\nassert(section.src = 'foo=\"(\", bar=\"}\"');\r\n\r\n\r\nvar section = parser.parseMax('{foo=\"(\", bar=\"}\"} bing bong', {start: 1});\r\nassert(section.start === 1);\r\nassert(section.end === 17);//exclusive end of string\r\nassert(section.src = 'foo=\"(\", bar=\"}\"');\r\n```\r\n\r\nThe bracketed expression parsing simply parses up to but excluding the first unmatched closed bracket (`)`, `}`, `]`). It is clever enough to ignore brackets in comments or strings.\r\n\r\n\r\n### Custom Delimited Expressions\r\n\r\nFind code up to a custom delimiter:\r\n\r\n```js\r\nvar section = parser.parseUntil('foo.bar(\"%>\").baz%> bing bong', '%>');\r\nassert(section.start === 0);\r\nassert(section.end === 17);//exclusive end of string\r\nassert(section.src = 'foo.bar(\"%>\").baz');\r\n\r\nvar section = parser.parseUntil('<%foo.bar(\"%>\").baz%> bing bong', '%>', {start: 2});\r\nassert(section.start === 2);\r\nassert(section.end === 19);//exclusive end of string\r\nassert(section.src = 'foo.bar(\"%>\").baz');\r\n```\r\n\r\nDelimiters are ignored if they are inside strings or comments.\r\n\r\n## API\r\n\r\n### parse(str, state = defaultState(), options = {start: 0, end: src.length})\r\n\r\nParse a string starting at the index start, and return the state after parsing that string.\r\n\r\nIf you want to parse one string in multiple sections you should keep passing the resulting state to the next parse operation.\r\n\r\nReturns a `State` object.\r\n\r\n### parseMax(src, options = {start: 0})\r\n\r\nParses the source until the first unmatched close bracket (any of `)`, `}`, `]`). It returns an object with the structure:\r\n\r\n```js\r\n{\r\n start: 0,//index of first character of string\r\n end: 13,//index of first character after the end of string\r\n src: 'source string'\r\n}\r\n```\r\n\r\n### parseUntil(src, delimiter, options = {start: 0, includeLineComment: false})\r\n\r\nParses the source until the first occurence of `delimiter` which is not in a string or a comment. If `includeLineComment` is `true`, it will still count if the delimiter occurs in a line comment, but not in a block comment. It returns an object with the structure:\r\n\r\n```js\r\n{\r\n start: 0,//index of first character of string\r\n end: 13,//index of first character after the end of string\r\n src: 'source string'\r\n}\r\n```\r\n\r\n### parseChar(character, state = defaultState())\r\n\r\nParses the single character and returns the state. See `parse` for the structure of the returned state object. N.B. character must be a single character not a multi character string.\r\n\r\n### defaultState()\r\n\r\nGet a default starting state.\r\n\r\n### isPunctuator(character)\r\n\r\nReturns `true` if `character` represents punctuation in JavaScript.\r\n\r\n### isKeyword(name)\r\n\r\nReturns `true` if `name` is a keyword in JavaScript.\r\n\r\n## State\r\n\r\nA state is an object with the following structure\r\n\r\n```js\r\n{\r\n lineComment: false, //true if inside a line comment\r\n blockComment: false, //true if inside a block comment\r\n\r\n singleQuote: false, //true if inside a single quoted string\r\n doubleQuote: false, //true if inside a double quoted string\r\n regexp: false, //true if inside a regular expression\r\n escaped: false, //true if in a string and the last character was an escape character\r\n\r\n roundDepth: 0, //number of un-closed open `(` brackets\r\n curlyDepth: 0, //number of un-closed open `{` brackets\r\n squareDepth: 0 //number of un-closed open `[` brackets\r\n}\r\n```\r\n\r\nIt also has the following useful methods:\r\n\r\n- `.isString()` returns `true` if the current location is inside a string.\r\n- `.isComment()` returns `true` if the current location is inside a comment.\r\n- `isNesting()` returns `true` if the current location is anything but at the top level, i.e. with no nesting.\r\n\r\n## License\r\n\r\nMIT", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/ForbesLindesay/character-parser/issues" + }, + "_id": "character-parser@1.2.0", + "dist": { + "shasum": "d6d5df03247e863b3945a2aefee08eb882f2ad2f" + }, + "_from": "character-parser@1.2.0", + "_resolved": "https://registry.npmjs.org/character-parser/-/character-parser-1.2.0.tgz" +} diff --git a/node_modules/jade/node_modules/commander/History.md b/node_modules/jade/node_modules/commander/History.md new file mode 100644 index 0000000..2e66582 --- /dev/null +++ b/node_modules/jade/node_modules/commander/History.md @@ -0,0 +1,179 @@ + +2.0.0 / 2013-07-18 +================== + + * remove input methods (.prompt, .confirm, etc) + +1.3.2 / 2013-07-18 +================== + + * add support for sub-commands to co-exist with the original command + +1.3.1 / 2013-07-18 +================== + + * add quick .runningCommand hack so you can opt-out of other logic when running a sub command + +1.3.0 / 2013-07-09 +================== + + * add EACCES error handling + * fix sub-command --help + +1.2.0 / 2013-06-13 +================== + + * allow "-" hyphen as an option argument + * support for RegExp coercion + +1.1.1 / 2012-11-20 +================== + + * add more sub-command padding + * fix .usage() when args are present. Closes #106 + +1.1.0 / 2012-11-16 +================== + + * add git-style executable subcommand support. Closes #94 + +1.0.5 / 2012-10-09 +================== + + * fix `--name` clobbering. Closes #92 + * fix examples/help. Closes #89 + +1.0.4 / 2012-09-03 +================== + + * add `outputHelp()` method. + +1.0.3 / 2012-08-30 +================== + + * remove invalid .version() defaulting + +1.0.2 / 2012-08-24 +================== + + * add `--foo=bar` support [arv] + * fix password on node 0.8.8. Make backward compatible with 0.6 [focusaurus] + +1.0.1 / 2012-08-03 +================== + + * fix issue #56 + * fix tty.setRawMode(mode) was moved to tty.ReadStream#setRawMode() (i.e. process.stdin.setRawMode()) + +1.0.0 / 2012-07-05 +================== + + * add support for optional option descriptions + * add defaulting of `.version()` to package.json's version + +0.6.1 / 2012-06-01 +================== + + * Added: append (yes or no) on confirmation + * Added: allow node.js v0.7.x + +0.6.0 / 2012-04-10 +================== + + * Added `.prompt(obj, callback)` support. Closes #49 + * Added default support to .choose(). Closes #41 + * Fixed the choice example + +0.5.1 / 2011-12-20 +================== + + * Fixed `password()` for recent nodes. Closes #36 + +0.5.0 / 2011-12-04 +================== + + * Added sub-command option support [itay] + +0.4.3 / 2011-12-04 +================== + + * Fixed custom help ordering. Closes #32 + +0.4.2 / 2011-11-24 +================== + + * Added travis support + * Fixed: line-buffered input automatically trimmed. Closes #31 + +0.4.1 / 2011-11-18 +================== + + * Removed listening for "close" on --help + +0.4.0 / 2011-11-15 +================== + + * Added support for `--`. Closes #24 + +0.3.3 / 2011-11-14 +================== + + * Fixed: wait for close event when writing help info [Jerry Hamlet] + +0.3.2 / 2011-11-01 +================== + + * Fixed long flag definitions with values [felixge] + +0.3.1 / 2011-10-31 +================== + + * Changed `--version` short flag to `-V` from `-v` + * Changed `.version()` so it's configurable [felixge] + +0.3.0 / 2011-10-31 +================== + + * Added support for long flags only. Closes #18 + +0.2.1 / 2011-10-24 +================== + + * "node": ">= 0.4.x < 0.7.0". Closes #20 + +0.2.0 / 2011-09-26 +================== + + * Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs] + +0.1.0 / 2011-08-24 +================== + + * Added support for custom `--help` output + +0.0.5 / 2011-08-18 +================== + + * Changed: when the user enters nothing prompt for password again + * Fixed issue with passwords beginning with numbers [NuckChorris] + +0.0.4 / 2011-08-15 +================== + + * Fixed `Commander#args` + +0.0.3 / 2011-08-15 +================== + + * Added default option value support + +0.0.2 / 2011-08-15 +================== + + * Added mask support to `Command#password(str[, mask], fn)` + * Added `Command#password(str, fn)` + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/jade/node_modules/commander/Readme.md b/node_modules/jade/node_modules/commander/Readme.md new file mode 100644 index 0000000..d164401 --- /dev/null +++ b/node_modules/jade/node_modules/commander/Readme.md @@ -0,0 +1,195 @@ +# Commander.js + + The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander). + + [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js) + +## Installation + + $ npm install commander + +## Option parsing + + Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options. + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('commander'); + +program + .version('0.0.1') + .option('-p, --peppers', 'Add peppers') + .option('-P, --pineapple', 'Add pineapple') + .option('-b, --bbq', 'Add bbq sauce') + .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble') + .parse(process.argv); + +console.log('you ordered a pizza with:'); +if (program.peppers) console.log(' - peppers'); +if (program.pineapple) console.log(' - pineapple'); +if (program.bbq) console.log(' - bbq'); +console.log(' - %s cheese', program.cheese); +``` + + Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc. + +## Automated --help + + The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free: + +``` + $ ./examples/pizza --help + + Usage: pizza [options] + + Options: + + -V, --version output the version number + -p, --peppers Add peppers + -P, --pineapple Add pineapple + -b, --bbq Add bbq sauce + -c, --cheese Add the specified type of cheese [marble] + -h, --help output usage information + +``` + +## Coercion + +```js +function range(val) { + return val.split('..').map(Number); +} + +function list(val) { + return val.split(','); +} + +program + .version('0.0.1') + .usage('[options] ') + .option('-i, --integer ', 'An integer argument', parseInt) + .option('-f, --float ', 'A float argument', parseFloat) + .option('-r, --range ..', 'A range', range) + .option('-l, --list ', 'A list', list) + .option('-o, --optional [value]', 'An optional value') + .parse(process.argv); + +console.log(' int: %j', program.integer); +console.log(' float: %j', program.float); +console.log(' optional: %j', program.optional); +program.range = program.range || []; +console.log(' range: %j..%j', program.range[0], program.range[1]); +console.log(' list: %j', program.list); +console.log(' args: %j', program.args); +``` + +## Custom help + + You can display arbitrary `-h, --help` information + by listening for "--help". Commander will automatically + exit once you are done so that the remainder of your program + does not execute causing undesired behaviours, for example + in the following executable "stuff" will not output when + `--help` is used. + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('../'); + +function list(val) { + return val.split(',').map(Number); +} + +program + .version('0.0.1') + .option('-f, --foo', 'enable some foo') + .option('-b, --bar', 'enable some bar') + .option('-B, --baz', 'enable some baz'); + +// must be before .parse() since +// node's emit() is immediate + +program.on('--help', function(){ + console.log(' Examples:'); + console.log(''); + console.log(' $ custom-help --help'); + console.log(' $ custom-help -h'); + console.log(''); +}); + +program.parse(process.argv); + +console.log('stuff'); +``` + +yielding the following help output: + +``` + +Usage: custom-help [options] + +Options: + + -h, --help output usage information + -V, --version output the version number + -f, --foo enable some foo + -b, --bar enable some bar + -B, --baz enable some baz + +Examples: + + $ custom-help --help + $ custom-help -h + +``` + +## .outputHelp() + + Output help information without exiting. + +## .help() + + Output help information and exit immediately. + +## Links + + - [API documentation](http://visionmedia.github.com/commander.js/) + - [ascii tables](https://github.com/LearnBoost/cli-table) + - [progress bars](https://github.com/visionmedia/node-progress) + - [more progress bars](https://github.com/substack/node-multimeter) + - [examples](https://github.com/visionmedia/commander.js/tree/master/examples) + +## License + +(The MIT License) + +Copyright (c) 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/node_modules/jade/node_modules/commander/index.js b/node_modules/jade/node_modules/commander/index.js new file mode 100644 index 0000000..d5778a7 --- /dev/null +++ b/node_modules/jade/node_modules/commander/index.js @@ -0,0 +1,847 @@ + +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter; +var spawn = require('child_process').spawn; +var fs = require('fs'); +var exists = fs.existsSync; +var path = require('path'); +var dirname = path.dirname; +var basename = path.basename; + +/** + * Expose the root command. + */ + +exports = module.exports = new Command; + +/** + * Expose `Command`. + */ + +exports.Command = Command; + +/** + * Expose `Option`. + */ + +exports.Option = Option; + +/** + * Initialize a new `Option` with the given `flags` and `description`. + * + * @param {String} flags + * @param {String} description + * @api public + */ + +function Option(flags, description) { + this.flags = flags; + this.required = ~flags.indexOf('<'); + this.optional = ~flags.indexOf('['); + this.bool = !~flags.indexOf('-no-'); + flags = flags.split(/[ ,|]+/); + if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift(); + this.long = flags.shift(); + this.description = description || ''; +} + +/** + * Return option name. + * + * @return {String} + * @api private + */ + +Option.prototype.name = function(){ + return this.long + .replace('--', '') + .replace('no-', ''); +}; + +/** + * Check if `arg` matches the short or long flag. + * + * @param {String} arg + * @return {Boolean} + * @api private + */ + +Option.prototype.is = function(arg){ + return arg == this.short + || arg == this.long; +}; + +/** + * Initialize a new `Command`. + * + * @param {String} name + * @api public + */ + +function Command(name) { + this.commands = []; + this.options = []; + this._execs = []; + this._args = []; + this._name = name; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Command.prototype.__proto__ = EventEmitter.prototype; + +/** + * Add command `name`. + * + * The `.action()` callback is invoked when the + * command `name` is specified via __ARGV__, + * and the remaining arguments are applied to the + * function for access. + * + * When the `name` is "*" an un-matched command + * will be passed as the first arg, followed by + * the rest of __ARGV__ remaining. + * + * Examples: + * + * program + * .version('0.0.1') + * .option('-C, --chdir ', 'change the working directory') + * .option('-c, --config ', 'set config path. defaults to ./deploy.conf') + * .option('-T, --no-tests', 'ignore test hook') + * + * program + * .command('setup') + * .description('run remote setup commands') + * .action(function(){ + * console.log('setup'); + * }); + * + * program + * .command('exec ') + * .description('run the given remote command') + * .action(function(cmd){ + * console.log('exec "%s"', cmd); + * }); + * + * program + * .command('*') + * .description('deploy the given env') + * .action(function(env){ + * console.log('deploying "%s"', env); + * }); + * + * program.parse(process.argv); + * + * @param {String} name + * @param {String} [desc] + * @return {Command} the new command + * @api public + */ + +Command.prototype.command = function(name, desc){ + var args = name.split(/ +/); + var cmd = new Command(args.shift()); + if (desc) cmd.description(desc); + if (desc) this.executables = true; + if (desc) this._execs[cmd._name] = true; + this.commands.push(cmd); + cmd.parseExpectedArgs(args); + cmd.parent = this; + if (desc) return this; + return cmd; +}; + +/** + * Add an implicit `help [cmd]` subcommand + * which invokes `--help` for the given command. + * + * @api private + */ + +Command.prototype.addImplicitHelpCommand = function() { + this.command('help [cmd]', 'display help for [cmd]'); +}; + +/** + * Parse expected `args`. + * + * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`. + * + * @param {Array} args + * @return {Command} for chaining + * @api public + */ + +Command.prototype.parseExpectedArgs = function(args){ + if (!args.length) return; + var self = this; + args.forEach(function(arg){ + switch (arg[0]) { + case '<': + self._args.push({ required: true, name: arg.slice(1, -1) }); + break; + case '[': + self._args.push({ required: false, name: arg.slice(1, -1) }); + break; + } + }); + return this; +}; + +/** + * Register callback `fn` for the command. + * + * Examples: + * + * program + * .command('help') + * .description('display verbose help') + * .action(function(){ + * // output help here + * }); + * + * @param {Function} fn + * @return {Command} for chaining + * @api public + */ + +Command.prototype.action = function(fn){ + var self = this; + this.parent.on(this._name, function(args, unknown){ + // Parse any so-far unknown options + unknown = unknown || []; + var parsed = self.parseOptions(unknown); + + // Output help if necessary + outputHelpIfNecessary(self, parsed.unknown); + + // If there are still any unknown options, then we simply + // die, unless someone asked for help, in which case we give it + // to them, and then we die. + if (parsed.unknown.length > 0) { + self.unknownOption(parsed.unknown[0]); + } + + // Leftover arguments need to be pushed back. Fixes issue #56 + if (parsed.args.length) args = parsed.args.concat(args); + + self._args.forEach(function(arg, i){ + if (arg.required && null == args[i]) { + self.missingArgument(arg.name); + } + }); + + // Always append ourselves to the end of the arguments, + // to make sure we match the number of arguments the user + // expects + if (self._args.length) { + args[self._args.length] = self; + } else { + args.push(self); + } + + fn.apply(this, args); + }); + return this; +}; + +/** + * Define option with `flags`, `description` and optional + * coercion `fn`. + * + * The `flags` string should contain both the short and long flags, + * separated by comma, a pipe or space. The following are all valid + * all will output this way when `--help` is used. + * + * "-p, --pepper" + * "-p|--pepper" + * "-p --pepper" + * + * Examples: + * + * // simple boolean defaulting to false + * program.option('-p, --pepper', 'add pepper'); + * + * --pepper + * program.pepper + * // => Boolean + * + * // simple boolean defaulting to false + * program.option('-C, --no-cheese', 'remove cheese'); + * + * program.cheese + * // => true + * + * --no-cheese + * program.cheese + * // => true + * + * // required argument + * program.option('-C, --chdir ', 'change the working directory'); + * + * --chdir /tmp + * program.chdir + * // => "/tmp" + * + * // optional argument + * program.option('-c, --cheese [type]', 'add cheese [marble]'); + * + * @param {String} flags + * @param {String} description + * @param {Function|Mixed} fn or default + * @param {Mixed} defaultValue + * @return {Command} for chaining + * @api public + */ + +Command.prototype.option = function(flags, description, fn, defaultValue){ + var self = this + , option = new Option(flags, description) + , oname = option.name() + , name = camelcase(oname); + + // default as 3rd arg + if ('function' != typeof fn) defaultValue = fn, fn = null; + + // preassign default value only for --no-*, [optional], or + if (false == option.bool || option.optional || option.required) { + // when --no-* we make sure default is true + if (false == option.bool) defaultValue = true; + // preassign only if we have a default + if (undefined !== defaultValue) self[name] = defaultValue; + } + + // register the option + this.options.push(option); + + // when it's passed assign the value + // and conditionally invoke the callback + this.on(oname, function(val){ + // coercion + if (null != val && fn) val = fn(val); + + // unassigned or bool + if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) { + // if no value, bool true, and we have a default, then use it! + if (null == val) { + self[name] = option.bool + ? defaultValue || true + : false; + } else { + self[name] = val; + } + } else if (null !== val) { + // reassign + self[name] = val; + } + }); + + return this; +}; + +/** + * Parse `argv`, settings options and invoking commands when defined. + * + * @param {Array} argv + * @return {Command} for chaining + * @api public + */ + +Command.prototype.parse = function(argv){ + // implicit help + if (this.executables) this.addImplicitHelpCommand(); + + // store raw args + this.rawArgs = argv; + + // guess name + this._name = this._name || basename(argv[1]); + + // process argv + var parsed = this.parseOptions(this.normalize(argv.slice(2))); + var args = this.args = parsed.args; + + var result = this.parseArgs(this.args, parsed.unknown); + + // executable sub-commands + var name = result.args[0]; + if (this._execs[name]) return this.executeSubCommand(argv, args, parsed.unknown); + + return result; +}; + +/** + * Execute a sub-command executable. + * + * @param {Array} argv + * @param {Array} args + * @param {Array} unknown + * @api private + */ + +Command.prototype.executeSubCommand = function(argv, args, unknown) { + args = args.concat(unknown); + + if (!args.length) this.help(); + if ('help' == args[0] && 1 == args.length) this.help(); + + // --help + if ('help' == args[0]) { + args[0] = args[1]; + args[1] = '--help'; + } + + // executable + var dir = dirname(argv[1]); + var bin = basename(argv[1]) + '-' + args[0]; + + // check for ./ first + var local = path.join(dir, bin); + + // run it + args = args.slice(1); + var proc = spawn(local, args, { stdio: 'inherit', customFds: [0, 1, 2] }); + proc.on('error', function(err){ + if (err.code == "ENOENT") { + console.error('\n %s(1) does not exist, try --help\n', bin); + } else if (err.code == "EACCES") { + console.error('\n %s(1) not executable. try chmod or run with root\n', bin); + } + }); + + this.runningCommand = proc; +}; + +/** + * Normalize `args`, splitting joined short flags. For example + * the arg "-abc" is equivalent to "-a -b -c". + * This also normalizes equal sign and splits "--abc=def" into "--abc def". + * + * @param {Array} args + * @return {Array} + * @api private + */ + +Command.prototype.normalize = function(args){ + var ret = [] + , arg + , index; + + for (var i = 0, len = args.length; i < len; ++i) { + arg = args[i]; + if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) { + arg.slice(1).split('').forEach(function(c){ + ret.push('-' + c); + }); + } else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) { + ret.push(arg.slice(0, index), arg.slice(index + 1)); + } else { + ret.push(arg); + } + } + + return ret; +}; + +/** + * Parse command `args`. + * + * When listener(s) are available those + * callbacks are invoked, otherwise the "*" + * event is emitted and those actions are invoked. + * + * @param {Array} args + * @return {Command} for chaining + * @api private + */ + +Command.prototype.parseArgs = function(args, unknown){ + var cmds = this.commands + , len = cmds.length + , name; + + if (args.length) { + name = args[0]; + if (this.listeners(name).length) { + this.emit(args.shift(), args, unknown); + } else { + this.emit('*', args); + } + } else { + outputHelpIfNecessary(this, unknown); + + // If there were no args and we have unknown options, + // then they are extraneous and we need to error. + if (unknown.length > 0) { + this.unknownOption(unknown[0]); + } + } + + return this; +}; + +/** + * Return an option matching `arg` if any. + * + * @param {String} arg + * @return {Option} + * @api private + */ + +Command.prototype.optionFor = function(arg){ + for (var i = 0, len = this.options.length; i < len; ++i) { + if (this.options[i].is(arg)) { + return this.options[i]; + } + } +}; + +/** + * Parse options from `argv` returning `argv` + * void of these options. + * + * @param {Array} argv + * @return {Array} + * @api public + */ + +Command.prototype.parseOptions = function(argv){ + var args = [] + , len = argv.length + , literal + , option + , arg; + + var unknownOptions = []; + + // parse options + for (var i = 0; i < len; ++i) { + arg = argv[i]; + + // literal args after -- + if ('--' == arg) { + literal = true; + continue; + } + + if (literal) { + args.push(arg); + continue; + } + + // find matching Option + option = this.optionFor(arg); + + // option is defined + if (option) { + // requires arg + if (option.required) { + arg = argv[++i]; + if (null == arg) return this.optionMissingArgument(option); + if ('-' == arg[0] && '-' != arg) return this.optionMissingArgument(option, arg); + this.emit(option.name(), arg); + // optional arg + } else if (option.optional) { + arg = argv[i+1]; + if (null == arg || ('-' == arg[0] && '-' != arg)) { + arg = null; + } else { + ++i; + } + this.emit(option.name(), arg); + // bool + } else { + this.emit(option.name()); + } + continue; + } + + // looks like an option + if (arg.length > 1 && '-' == arg[0]) { + unknownOptions.push(arg); + + // If the next argument looks like it might be + // an argument for this option, we pass it on. + // If it isn't, then it'll simply be ignored + if (argv[i+1] && '-' != argv[i+1][0]) { + unknownOptions.push(argv[++i]); + } + continue; + } + + // arg + args.push(arg); + } + + return { args: args, unknown: unknownOptions }; +}; + +/** + * Argument `name` is missing. + * + * @param {String} name + * @api private + */ + +Command.prototype.missingArgument = function(name){ + console.error(); + console.error(" error: missing required argument `%s'", name); + console.error(); + process.exit(1); +}; + +/** + * `Option` is missing an argument, but received `flag` or nothing. + * + * @param {String} option + * @param {String} flag + * @api private + */ + +Command.prototype.optionMissingArgument = function(option, flag){ + console.error(); + if (flag) { + console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag); + } else { + console.error(" error: option `%s' argument missing", option.flags); + } + console.error(); + process.exit(1); +}; + +/** + * Unknown option `flag`. + * + * @param {String} flag + * @api private + */ + +Command.prototype.unknownOption = function(flag){ + console.error(); + console.error(" error: unknown option `%s'", flag); + console.error(); + process.exit(1); +}; + + +/** + * Set the program version to `str`. + * + * This method auto-registers the "-V, --version" flag + * which will print the version number when passed. + * + * @param {String} str + * @param {String} flags + * @return {Command} for chaining + * @api public + */ + +Command.prototype.version = function(str, flags){ + if (0 == arguments.length) return this._version; + this._version = str; + flags = flags || '-V, --version'; + this.option(flags, 'output the version number'); + this.on('version', function(){ + console.log(str); + process.exit(0); + }); + return this; +}; + +/** + * Set the description `str`. + * + * @param {String} str + * @return {String|Command} + * @api public + */ + +Command.prototype.description = function(str){ + if (0 == arguments.length) return this._description; + this._description = str; + return this; +}; + +/** + * Set / get the command usage `str`. + * + * @param {String} str + * @return {String|Command} + * @api public + */ + +Command.prototype.usage = function(str){ + var args = this._args.map(function(arg){ + return arg.required + ? '<' + arg.name + '>' + : '[' + arg.name + ']'; + }); + + var usage = '[options' + + (this.commands.length ? '] [command' : '') + + ']' + + (this._args.length ? ' ' + args : ''); + + if (0 == arguments.length) return this._usage || usage; + this._usage = str; + + return this; +}; + +/** + * Return the largest option length. + * + * @return {Number} + * @api private + */ + +Command.prototype.largestOptionLength = function(){ + return this.options.reduce(function(max, option){ + return Math.max(max, option.flags.length); + }, 0); +}; + +/** + * Return help for options. + * + * @return {String} + * @api private + */ + +Command.prototype.optionHelp = function(){ + var width = this.largestOptionLength(); + + // Prepend the help information + return [pad('-h, --help', width) + ' ' + 'output usage information'] + .concat(this.options.map(function(option){ + return pad(option.flags, width) + + ' ' + option.description; + })) + .join('\n'); +}; + +/** + * Return command help documentation. + * + * @return {String} + * @api private + */ + +Command.prototype.commandHelp = function(){ + if (!this.commands.length) return ''; + return [ + '' + , ' Commands:' + , '' + , this.commands.map(function(cmd){ + var args = cmd._args.map(function(arg){ + return arg.required + ? '<' + arg.name + '>' + : '[' + arg.name + ']'; + }).join(' '); + + return pad(cmd._name + + (cmd.options.length + ? ' [options]' + : '') + ' ' + args, 22) + + (cmd.description() + ? ' ' + cmd.description() + : ''); + }).join('\n').replace(/^/gm, ' ') + , '' + ].join('\n'); +}; + +/** + * Return program help documentation. + * + * @return {String} + * @api private + */ + +Command.prototype.helpInformation = function(){ + return [ + '' + , ' Usage: ' + this._name + ' ' + this.usage() + , '' + this.commandHelp() + , ' Options:' + , '' + , '' + this.optionHelp().replace(/^/gm, ' ') + , '' + , '' + ].join('\n'); +}; + +/** + * Output help information for this command + * + * @api public + */ + +Command.prototype.outputHelp = function(){ + process.stdout.write(this.helpInformation()); + this.emit('--help'); +}; + +/** + * Output help information and exit. + * + * @api public + */ + +Command.prototype.help = function(){ + this.outputHelp(); + process.exit(); +}; + +/** + * Camel-case the given `flag` + * + * @param {String} flag + * @return {String} + * @api private + */ + +function camelcase(flag) { + return flag.split('-').reduce(function(str, word){ + return str + word[0].toUpperCase() + word.slice(1); + }); +} + +/** + * Pad `str` to `width`. + * + * @param {String} str + * @param {Number} width + * @return {String} + * @api private + */ + +function pad(str, width) { + var len = Math.max(0, width - str.length); + return str + Array(len + 1).join(' '); +} + +/** + * Output help information if necessary + * + * @param {Command} command to output help for + * @param {Array} array of options to search for -h or --help + * @api private + */ + +function outputHelpIfNecessary(cmd, options) { + options = options || []; + for (var i = 0; i < options.length; i++) { + if (options[i] == '--help' || options[i] == '-h') { + cmd.outputHelp(); + process.exit(0); + } + } +} diff --git a/node_modules/jade/node_modules/commander/package.json b/node_modules/jade/node_modules/commander/package.json new file mode 100644 index 0000000..15604f0 --- /dev/null +++ b/node_modules/jade/node_modules/commander/package.json @@ -0,0 +1,41 @@ +{ + "name": "commander", + "version": "2.0.0", + "description": "the complete solution for node.js command-line programs", + "keywords": [ + "command", + "option", + "parser", + "prompt", + "stdin" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "repository": { + "type": "git", + "url": "https://github.com/visionmedia/commander.js.git" + }, + "devDependencies": { + "should": ">= 0.0.1" + }, + "scripts": { + "test": "make test" + }, + "main": "index", + "engines": { + "node": ">= 0.6.x" + }, + "readme": "# Commander.js\n\n The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander).\n\n [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js)\n\n## Installation\n\n $ npm install commander\n\n## Option parsing\n\n Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('commander');\n\nprogram\n .version('0.0.1')\n .option('-p, --peppers', 'Add peppers')\n .option('-P, --pineapple', 'Add pineapple')\n .option('-b, --bbq', 'Add bbq sauce')\n .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')\n .parse(process.argv);\n\nconsole.log('you ordered a pizza with:');\nif (program.peppers) console.log(' - peppers');\nif (program.pineapple) console.log(' - pineapple');\nif (program.bbq) console.log(' - bbq');\nconsole.log(' - %s cheese', program.cheese);\n```\n\n Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as \"--template-engine\" are camel-cased, becoming `program.templateEngine` etc.\n\n## Automated --help\n\n The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:\n\n``` \n $ ./examples/pizza --help\n\n Usage: pizza [options]\n\n Options:\n\n -V, --version output the version number\n -p, --peppers Add peppers\n -P, --pineapple Add pineapple\n -b, --bbq Add bbq sauce\n -c, --cheese Add the specified type of cheese [marble]\n -h, --help output usage information\n\n```\n\n## Coercion\n\n```js\nfunction range(val) {\n return val.split('..').map(Number);\n}\n\nfunction list(val) {\n return val.split(',');\n}\n\nprogram\n .version('0.0.1')\n .usage('[options] ')\n .option('-i, --integer ', 'An integer argument', parseInt)\n .option('-f, --float ', 'A float argument', parseFloat)\n .option('-r, --range ..', 'A range', range)\n .option('-l, --list ', 'A list', list)\n .option('-o, --optional [value]', 'An optional value')\n .parse(process.argv);\n\nconsole.log(' int: %j', program.integer);\nconsole.log(' float: %j', program.float);\nconsole.log(' optional: %j', program.optional);\nprogram.range = program.range || [];\nconsole.log(' range: %j..%j', program.range[0], program.range[1]);\nconsole.log(' list: %j', program.list);\nconsole.log(' args: %j', program.args);\n```\n\n## Custom help\n\n You can display arbitrary `-h, --help` information\n by listening for \"--help\". Commander will automatically\n exit once you are done so that the remainder of your program\n does not execute causing undesired behaviours, for example\n in the following executable \"stuff\" will not output when\n `--help` is used.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('../');\n\nfunction list(val) {\n return val.split(',').map(Number);\n}\n\nprogram\n .version('0.0.1')\n .option('-f, --foo', 'enable some foo')\n .option('-b, --bar', 'enable some bar')\n .option('-B, --baz', 'enable some baz');\n\n// must be before .parse() since\n// node's emit() is immediate\n\nprogram.on('--help', function(){\n console.log(' Examples:');\n console.log('');\n console.log(' $ custom-help --help');\n console.log(' $ custom-help -h');\n console.log('');\n});\n\nprogram.parse(process.argv);\n\nconsole.log('stuff');\n```\n\nyielding the following help output:\n\n```\n\nUsage: custom-help [options]\n\nOptions:\n\n -h, --help output usage information\n -V, --version output the version number\n -f, --foo enable some foo\n -b, --bar enable some bar\n -B, --baz enable some baz\n\nExamples:\n\n $ custom-help --help\n $ custom-help -h\n\n```\n\n## .outputHelp()\n\n Output help information without exiting.\n\n## .help()\n\n Output help information and exit immediately.\n\n## Links\n\n - [API documentation](http://visionmedia.github.com/commander.js/)\n - [ascii tables](https://github.com/LearnBoost/cli-table)\n - [progress bars](https://github.com/visionmedia/node-progress)\n - [more progress bars](https://github.com/substack/node-multimeter)\n - [examples](https://github.com/visionmedia/commander.js/tree/master/examples)\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/commander.js/issues" + }, + "_id": "commander@2.0.0", + "dist": { + "shasum": "d1b86f901f8b64bd941bdeadaf924530393be928" + }, + "_from": "commander@2.0.0", + "_resolved": "https://registry.npmjs.org/commander/-/commander-2.0.0.tgz" +} diff --git a/node_modules/jade/node_modules/constantinople/.gitattributes b/node_modules/jade/node_modules/constantinople/.gitattributes new file mode 100644 index 0000000..412eeda --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/node_modules/jade/node_modules/constantinople/.npmignore b/node_modules/jade/node_modules/constantinople/.npmignore new file mode 100644 index 0000000..b83202d --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/.npmignore @@ -0,0 +1,13 @@ +lib-cov +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.gz +pids +logs +results +npm-debug.log +node_modules diff --git a/node_modules/jade/node_modules/constantinople/.travis.yml b/node_modules/jade/node_modules/constantinople/.travis.yml new file mode 100644 index 0000000..a12e3f0 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - "0.8" + - "0.10" \ No newline at end of file diff --git a/node_modules/jade/node_modules/constantinople/LICENSE b/node_modules/jade/node_modules/constantinople/LICENSE new file mode 100644 index 0000000..35cc606 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013 Forbes Lindesay + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/jade/node_modules/constantinople/README.md b/node_modules/jade/node_modules/constantinople/README.md new file mode 100644 index 0000000..ad156c0 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/README.md @@ -0,0 +1,35 @@ +# constantinople + +Determine whether a JavaScript expression evaluates to a constant (using UglifyJS). Here it is assumed to be safe to underestimate how constant something is. + +[![Build Status](https://travis-ci.org/ForbesLindesay/constantinople.png?branch=master)](https://travis-ci.org/ForbesLindesay/constantinople) +[![Dependency Status](https://gemnasium.com/ForbesLindesay/constantinople.png)](https://gemnasium.com/ForbesLindesay/constantinople) +[![NPM version](https://badge.fury.io/js/constantinople.png)](http://badge.fury.io/js/constantinople) + +## Installation + + npm install constantinople + +## Usage + +```js +var isConstant = require('constantinople') + +if (isConstant('"foo" + 5')) { + console.dir(isConstant.toConstant('"foo" + 5')) +} +``` + +## API + +### isConstant(src) + +Returns `true` if `src` evaluates to a constant, `false` otherwise. It will also return `false` if there is a syntax error, which makes it safe to use on potentially ES6 code. + +### toConstant(src) + +Returns the value resulting from evaluating `src`. This method throws an error if the expression is not constant. e.g. `toConstant("Math.random()")` would throw an error. + +## License + + MIT \ No newline at end of file diff --git a/node_modules/jade/node_modules/constantinople/index.js b/node_modules/jade/node_modules/constantinople/index.js new file mode 100644 index 0000000..3ed8a00 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/index.js @@ -0,0 +1,35 @@ +'use strict' + +var uglify = require('uglify-js') + +var lastSRC = '(null)' +var lastRes = true + +module.exports = isConstant +function isConstant(src) { + src = '(' + src + ')' + if (lastSRC === src) return lastRes + lastSRC = src + try { + return lastRes = (detect(src).length === 0) + } catch (ex) { + return lastRes = false + } +} +isConstant.isConstant = isConstant + +isConstant.toConstant = toConstant +function toConstant(src) { + if (!isConstant(src)) throw new Error(JSON.stringify(src) + ' is not constant.') + return Function('return (' + src + ')')() +} + +function detect(src) { + var ast = uglify.parse(src.toString()) + ast.figure_out_scope() + var globals = ast.globals + .map(function (node, name) { + return name + }) + return globals +} \ No newline at end of file diff --git a/node_modules/jade/node_modules/constantinople/node_modules/.bin/uglifyjs b/node_modules/jade/node_modules/constantinople/node_modules/.bin/uglifyjs new file mode 120000 index 0000000..fef3468 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/.bin/uglifyjs @@ -0,0 +1 @@ +../uglify-js/bin/uglifyjs \ No newline at end of file diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/.npmignore b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/.npmignore new file mode 100644 index 0000000..94fceeb --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/.npmignore @@ -0,0 +1,2 @@ +tmp/ +node_modules/ diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/.travis.yml b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/.travis.yml new file mode 100644 index 0000000..d959127 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/.travis.yml @@ -0,0 +1,7 @@ +language: node_js +node_js: + - "0.4" + - "0.6" + - "0.8" + - "0.10" + - "0.11" diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/LICENSE b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/LICENSE new file mode 100644 index 0000000..dd7706f --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/LICENSE @@ -0,0 +1,29 @@ +UglifyJS is released under the BSD license: + +Copyright 2012-2013 (c) Mihai Bazon + +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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/README.md b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/README.md new file mode 100644 index 0000000..f2f2f21 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/README.md @@ -0,0 +1,633 @@ +UglifyJS 2 +========== +[![Build Status](https://travis-ci.org/mishoo/UglifyJS2.png)](https://travis-ci.org/mishoo/UglifyJS2) + +UglifyJS is a JavaScript parser, minifier, compressor or beautifier toolkit. + +This page documents the command line utility. For +[API and internals documentation see my website](http://lisperator.net/uglifyjs/). +There's also an +[in-browser online demo](http://lisperator.net/uglifyjs/#demo) (for Firefox, +Chrome and probably Safari). + +Install +------- + +First make sure you have installed the latest version of [node.js](http://nodejs.org/) +(You may need to restart your computer after this step). + +From NPM for use as a command line app: + + npm install uglify-js -g + +From NPM for programmatic use: + + npm install uglify-js + +From Git: + + git clone git://github.com/mishoo/UglifyJS2.git + cd UglifyJS2 + npm link . + +Usage +----- + + uglifyjs [input files] [options] + +UglifyJS2 can take multiple input files. It's recommended that you pass the +input files first, then pass the options. UglifyJS will parse input files +in sequence and apply any compression options. The files are parsed in the +same global scope, that is, a reference from a file to some +variable/function declared in another file will be matched properly. + +If you want to read from STDIN instead, pass a single dash instead of input +files. + +The available options are: + +``` + --source-map Specify an output file where to generate source map. + [string] + --source-map-root The path to the original source to be included in the + source map. [string] + --source-map-url The path to the source map to be added in //# + sourceMappingURL. Defaults to the value passed with + --source-map. [string] + --in-source-map Input source map, useful if you're compressing JS that was + generated from some other original code. + --screw-ie8 Pass this flag if you don't care about full compliance + with Internet Explorer 6-8 quirks (by default UglifyJS + will try to be IE-proof). [boolean] + --expr Parse a single expression, rather than a program (for + parsing JSON) [boolean] + -p, --prefix Skip prefix for original filenames that appear in source + maps. For example -p 3 will drop 3 directories from file + names and ensure they are relative paths. You can also + specify -p relative, which will make UglifyJS figure out + itself the relative paths between original sources, the + source map and the output file. [string] + -o, --output Output file (default STDOUT). + -b, --beautify Beautify output/specify output options. [string] + -m, --mangle Mangle names/pass mangler options. [string] + -r, --reserved Reserved names to exclude from mangling. + -c, --compress Enable compressor/pass compressor options. Pass options + like -c hoist_vars=false,if_return=false. Use -c with no + argument to use the default compression options. [string] + -d, --define Global definitions [string] + -e, --enclose Embed everything in a big function, with a configurable + parameter/argument list. [string] + --comments Preserve copyright comments in the output. By default this + works like Google Closure, keeping JSDoc-style comments + that contain "@license" or "@preserve". You can optionally + pass one of the following arguments to this flag: + - "all" to keep all comments + - a valid JS regexp (needs to start with a slash) to keep + only comments that match. + Note that currently not *all* comments can be kept when + compression is on, because of dead code removal or + cascading statements into sequences. [string] + --preamble Preamble to prepend to the output. You can use this to + insert a comment, for example for licensing information. + This will not be parsed, but the source map will adjust + for its presence. + --stats Display operations run time on STDERR. [boolean] + --acorn Use Acorn for parsing. [boolean] + --spidermonkey Assume input files are SpiderMonkey AST format (as JSON). + [boolean] + --self Build itself (UglifyJS2) as a library (implies + --wrap=UglifyJS --export-all) [boolean] + --wrap Embed everything in a big function, making the “exports” + and “global” variables available. You need to pass an + argument to this option to specify the name that your + module will take when included in, say, a browser. + [string] + --export-all Only used when --wrap, this tells UglifyJS to add code to + automatically export all globals. [boolean] + --lint Display some scope warnings [boolean] + -v, --verbose Verbose [boolean] + -V, --version Print version number and exit. [boolean] +``` + +Specify `--output` (`-o`) to declare the output file. Otherwise the output +goes to STDOUT. + +## Source map options + +UglifyJS2 can generate a source map file, which is highly useful for +debugging your compressed JavaScript. To get a source map, pass +`--source-map output.js.map` (full path to the file where you want the +source map dumped). + +Additionally you might need `--source-map-root` to pass the URL where the +original files can be found. In case you are passing full paths to input +files to UglifyJS, you can use `--prefix` (`-p`) to specify the number of +directories to drop from the path prefix when declaring files in the source +map. + +For example: + + uglifyjs /home/doe/work/foo/src/js/file1.js \ + /home/doe/work/foo/src/js/file2.js \ + -o foo.min.js \ + --source-map foo.min.js.map \ + --source-map-root http://foo.com/src \ + -p 5 -c -m + +The above will compress and mangle `file1.js` and `file2.js`, will drop the +output in `foo.min.js` and the source map in `foo.min.js.map`. The source +mapping will refer to `http://foo.com/src/js/file1.js` and +`http://foo.com/src/js/file2.js` (in fact it will list `http://foo.com/src` +as the source map root, and the original files as `js/file1.js` and +`js/file2.js`). + +### Composed source map + +When you're compressing JS code that was output by a compiler such as +CoffeeScript, mapping to the JS code won't be too helpful. Instead, you'd +like to map back to the original code (i.e. CoffeeScript). UglifyJS has an +option to take an input source map. Assuming you have a mapping from +CoffeeScript → compiled JS, UglifyJS can generate a map from CoffeeScript → +compressed JS by mapping every token in the compiled JS to its original +location. + +To use this feature you need to pass `--in-source-map +/path/to/input/source.map`. Normally the input source map should also point +to the file containing the generated JS, so if that's correct you can omit +input files from the command line. + +## Mangler options + +To enable the mangler you need to pass `--mangle` (`-m`). The following +(comma-separated) options are supported: + +- `sort` — to assign shorter names to most frequently used variables. This + saves a few hundred bytes on jQuery before gzip, but the output is + _bigger_ after gzip (and seems to happen for other libraries I tried it + on) therefore it's not enabled by default. + +- `toplevel` — mangle names declared in the toplevel scope (disabled by + default). + +- `eval` — mangle names visible in scopes where `eval` or `when` are used + (disabled by default). + +When mangling is enabled but you want to prevent certain names from being +mangled, you can declare those names with `--reserved` (`-r`) — pass a +comma-separated list of names. For example: + + uglifyjs ... -m -r '$,require,exports' + +to prevent the `require`, `exports` and `$` names from being changed. + +## Compressor options + +You need to pass `--compress` (`-c`) to enable the compressor. Optionally +you can pass a comma-separated list of options. Options are in the form +`foo=bar`, or just `foo` (the latter implies a boolean option that you want +to set `true`; it's effectively a shortcut for `foo=true`). + +- `sequences` -- join consecutive simple statements using the comma operator + +- `properties` -- rewrite property access using the dot notation, for + example `foo["bar"] → foo.bar` + +- `dead_code` -- remove unreachable code + +- `drop_debugger` -- remove `debugger;` statements + +- `unsafe` (default: false) -- apply "unsafe" transformations (discussion below) + +- `conditionals` -- apply optimizations for `if`-s and conditional + expressions + +- `comparisons` -- apply certain optimizations to binary nodes, for example: + `!(a <= b) → a > b` (only when `unsafe`), attempts to negate binary nodes, + e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc. + +- `evaluate` -- attempt to evaluate constant expressions + +- `booleans` -- various optimizations for boolean context, for example `!!a + ? b : c → a ? b : c` + +- `loops` -- optimizations for `do`, `while` and `for` loops when we can + statically determine the condition + +- `unused` -- drop unreferenced functions and variables + +- `hoist_funs` -- hoist function declarations + +- `hoist_vars` (default: false) -- hoist `var` declarations (this is `false` + by default because it seems to increase the size of the output in general) + +- `if_return` -- optimizations for if/return and if/continue + +- `join_vars` -- join consecutive `var` statements + +- `cascade` -- small optimization for sequences, transform `x, x` into `x` + and `x = something(), x` into `x = something()` + +- `warnings` -- display warnings when dropping unreachable code or unused + declarations etc. + +- `negate_iife` -- negate "Immediately-Called Function Expressions" + where the return value is discarded, to avoid the parens that the + code generator would insert. + +- `pure_getters` -- the default is `false`. If you pass `true` for + this, UglifyJS will assume that object property access + (e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects. + +- `pure_funcs` -- default `null`. You can pass an array of names and + UglifyJS will assume that those functions do not produce side + effects. DANGER: will not check if the name is redefined in scope. + An example case here, for instance `var q = Math.floor(a/b)`. If + variable `q` is not used elsewhere, UglifyJS will drop it, but will + still keep the `Math.floor(a/b)`, not knowing what it does. You can + pass `pure_funcs: [ 'Math.floor' ]` to let it know that this + function won't produce any side effect, in which case the whole + statement would get discarded. The current implementation adds some + overhead (compression will be slower). + +### The `unsafe` option + +It enables some transformations that *might* break code logic in certain +contrived cases, but should be fine for most code. You might want to try it +on your own code, it should reduce the minified size. Here's what happens +when this flag is on: + +- `new Array(1, 2, 3)` or `Array(1, 2, 3)` → `[1, 2, 3 ]` +- `new Object()` → `{}` +- `String(exp)` or `exp.toString()` → `"" + exp` +- `new Object/RegExp/Function/Error/Array (...)` → we discard the `new` +- `typeof foo == "undefined"` → `foo === void 0` +- `void 0` → `undefined` (if there is a variable named "undefined" in + scope; we do it because the variable name will be mangled, typically + reduced to a single character). + +### Conditional compilation + +You can use the `--define` (`-d`) switch in order to declare global +variables that UglifyJS will assume to be constants (unless defined in +scope). For example if you pass `--define DEBUG=false` then, coupled with +dead code removal UglifyJS will discard the following from the output: +```javascript +if (DEBUG) { + console.log("debug stuff"); +} +``` + +UglifyJS will warn about the condition being always false and about dropping +unreachable code; for now there is no option to turn off only this specific +warning, you can pass `warnings=false` to turn off *all* warnings. + +Another way of doing that is to declare your globals as constants in a +separate file and include it into the build. For example you can have a +`build/defines.js` file with the following: +```javascript +const DEBUG = false; +const PRODUCTION = true; +// etc. +``` + +and build your code like this: + + uglifyjs build/defines.js js/foo.js js/bar.js... -c + +UglifyJS will notice the constants and, since they cannot be altered, it +will evaluate references to them to the value itself and drop unreachable +code as usual. The possible downside of this approach is that the build +will contain the `const` declarations. + + +## Beautifier options + +The code generator tries to output shortest code possible by default. In +case you want beautified output, pass `--beautify` (`-b`). Optionally you +can pass additional arguments that control the code output: + +- `beautify` (default `true`) -- whether to actually beautify the output. + Passing `-b` will set this to true, but you might need to pass `-b` even + when you want to generate minified code, in order to specify additional + arguments, so you can use `-b beautify=false` to override it. +- `indent-level` (default 4) +- `indent-start` (default 0) -- prefix all lines by that many spaces +- `quote-keys` (default `false`) -- pass `true` to quote all keys in literal + objects +- `space-colon` (default `true`) -- insert a space after the colon signs +- `ascii-only` (default `false`) -- escape Unicode characters in strings and + regexps +- `inline-script` (default `false`) -- escape the slash in occurrences of + ` 0) { + sys.error("WARN: Ignoring input files since --self was passed"); + } + files = UglifyJS.FILES; + if (!ARGS.wrap) ARGS.wrap = "UglifyJS"; + ARGS.export_all = true; +} + +var ORIG_MAP = ARGS.in_source_map; + +if (ORIG_MAP) { + ORIG_MAP = JSON.parse(fs.readFileSync(ORIG_MAP)); + if (files.length == 0) { + sys.error("INFO: Using file from the input source map: " + ORIG_MAP.file); + files = [ ORIG_MAP.file ]; + } + if (ARGS.source_map_root == null) { + ARGS.source_map_root = ORIG_MAP.sourceRoot; + } +} + +if (files.length == 0) { + files = [ "-" ]; +} + +if (files.indexOf("-") >= 0 && ARGS.source_map) { + sys.error("ERROR: Source map doesn't work with input from STDIN"); + process.exit(1); +} + +if (files.filter(function(el){ return el == "-" }).length > 1) { + sys.error("ERROR: Can read a single file from STDIN (two or more dashes specified)"); + process.exit(1); +} + +var STATS = {}; +var OUTPUT_FILE = ARGS.o; +var TOPLEVEL = null; +var P_RELATIVE = ARGS.p && ARGS.p == "relative"; + +var SOURCE_MAP = ARGS.source_map ? UglifyJS.SourceMap({ + file: P_RELATIVE ? path.relative(path.dirname(ARGS.source_map), OUTPUT_FILE) : OUTPUT_FILE, + root: ARGS.source_map_root, + orig: ORIG_MAP, +}) : null; + +OUTPUT_OPTIONS.source_map = SOURCE_MAP; + +try { + var output = UglifyJS.OutputStream(OUTPUT_OPTIONS); + var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS); +} catch(ex) { + if (ex instanceof UglifyJS.DefaultsError) { + sys.error(ex.msg); + sys.error("Supported options:"); + sys.error(sys.inspect(ex.defs)); + process.exit(1); + } +} + +async.eachLimit(files, 1, function (file, cb) { + read_whole_file(file, function (err, code) { + if (err) { + sys.error("ERROR: can't read file: " + file); + process.exit(1); + } + if (ARGS.p != null) { + if (P_RELATIVE) { + file = path.relative(path.dirname(ARGS.source_map), file); + } else { + var p = parseInt(ARGS.p, 10); + if (!isNaN(p)) { + file = file.replace(/^\/+/, "").split(/\/+/).slice(ARGS.p).join("/"); + } + } + } + time_it("parse", function(){ + if (ARGS.spidermonkey) { + var program = JSON.parse(code); + if (!TOPLEVEL) TOPLEVEL = program; + else TOPLEVEL.body = TOPLEVEL.body.concat(program.body); + } + else if (ARGS.acorn) { + TOPLEVEL = acorn.parse(code, { + locations : true, + sourceFile : file, + program : TOPLEVEL + }); + } + else { + try { + TOPLEVEL = UglifyJS.parse(code, { + filename : file, + toplevel : TOPLEVEL, + expression : ARGS.expr, + }); + } catch(ex) { + if (ex instanceof UglifyJS.JS_Parse_Error) { + sys.error("Parse error at " + file + ":" + ex.line + "," + ex.col); + sys.error(ex.message); + sys.error(ex.stack); + process.exit(1); + } + throw ex; + } + }; + }); + cb(); + }); +}, function () { + if (ARGS.acorn || ARGS.spidermonkey) time_it("convert_ast", function(){ + TOPLEVEL = UglifyJS.AST_Node.from_mozilla_ast(TOPLEVEL); + }); + + if (ARGS.wrap) { + TOPLEVEL = TOPLEVEL.wrap_commonjs(ARGS.wrap, ARGS.export_all); + } + + if (ARGS.enclose) { + var arg_parameter_list = ARGS.enclose; + if (arg_parameter_list === true) { + arg_parameter_list = []; + } + else if (!(arg_parameter_list instanceof Array)) { + arg_parameter_list = [arg_parameter_list]; + } + TOPLEVEL = TOPLEVEL.wrap_enclose(arg_parameter_list); + } + + var SCOPE_IS_NEEDED = COMPRESS || MANGLE || ARGS.lint; + + if (SCOPE_IS_NEEDED) { + time_it("scope", function(){ + TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8 }); + if (ARGS.lint) { + TOPLEVEL.scope_warnings(); + } + }); + } + + if (COMPRESS) { + time_it("squeeze", function(){ + TOPLEVEL = TOPLEVEL.transform(compressor); + }); + } + + if (SCOPE_IS_NEEDED) { + time_it("scope", function(){ + TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8 }); + if (MANGLE) { + TOPLEVEL.compute_char_frequency(MANGLE); + } + }); + } + + if (MANGLE) time_it("mangle", function(){ + TOPLEVEL.mangle_names(MANGLE); + }); + time_it("generate", function(){ + TOPLEVEL.print(output); + }); + + output = output.get(); + + if (SOURCE_MAP) { + fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8"); + var source_map_url = ARGS.source_map_url || ( + P_RELATIVE + ? path.relative(path.dirname(OUTPUT_FILE), ARGS.source_map) + : ARGS.source_map + ); + output += "\n//# sourceMappingURL=" + source_map_url; + } + + if (OUTPUT_FILE) { + fs.writeFileSync(OUTPUT_FILE, output, "utf8"); + } else { + sys.print(output); + sys.error("\n"); + } + + if (ARGS.stats) { + sys.error(UglifyJS.string_template("Timing information (compressed {count} files):", { + count: files.length + })); + for (var i in STATS) if (STATS.hasOwnProperty(i)) { + sys.error(UglifyJS.string_template("- {name}: {time}s", { + name: i, + time: (STATS[i] / 1000).toFixed(3) + })); + } + } +}); + +/* -----[ functions ]----- */ + +function normalize(o) { + for (var i in o) if (o.hasOwnProperty(i) && /-/.test(i)) { + o[i.replace(/-/g, "_")] = o[i]; + delete o[i]; + } +} + +function getOptions(x, constants) { + x = ARGS[x]; + if (!x) return null; + var ret = {}; + if (x !== true) { + var ast; + try { + ast = UglifyJS.parse(x, { expression: true }); + } catch(ex) { + if (ex instanceof UglifyJS.JS_Parse_Error) { + sys.error("Error parsing arguments in: " + x); + process.exit(1); + } + } + ast.walk(new UglifyJS.TreeWalker(function(node){ + if (node instanceof UglifyJS.AST_Seq) return; // descend + if (node instanceof UglifyJS.AST_Assign) { + var name = node.left.print_to_string({ beautify: false }).replace(/-/g, "_"); + var value = node.right; + if (constants) + value = new Function("return (" + value.print_to_string() + ")")(); + ret[name] = value; + return true; // no descend + } + if (node instanceof UglifyJS.AST_Symbol || node instanceof UglifyJS.AST_Binary) { + var name = node.print_to_string({ beautify: false }).replace(/-/g, "_"); + ret[name] = true; + return true; // no descend + } + sys.error(node.TYPE) + sys.error("Error parsing arguments in: " + x); + process.exit(1); + })); + } + return ret; +} + +function read_whole_file(filename, cb) { + if (filename == "-") { + var chunks = []; + process.stdin.setEncoding('utf-8'); + process.stdin.on('data', function (chunk) { + chunks.push(chunk); + }).on('end', function () { + cb(null, chunks.join("")); + }); + process.openStdin(); + } else { + fs.readFile(filename, "utf-8", cb); + } +} + +function time_it(name, cont) { + var t1 = new Date().getTime(); + var ret = cont(); + if (ARGS.stats) { + var spent = new Date().getTime() - t1; + if (STATS[name]) STATS[name] += spent; + else STATS[name] = spent; + } + return ret; +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/ast.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/ast.js new file mode 100644 index 0000000..0fa48e2 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/ast.js @@ -0,0 +1,990 @@ +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + 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. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 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. + + ***********************************************************************/ + +"use strict"; + +function DEFNODE(type, props, methods, base) { + if (arguments.length < 4) base = AST_Node; + if (!props) props = []; + else props = props.split(/\s+/); + var self_props = props; + if (base && base.PROPS) + props = props.concat(base.PROPS); + var code = "return function AST_" + type + "(props){ if (props) { "; + for (var i = props.length; --i >= 0;) { + code += "this." + props[i] + " = props." + props[i] + ";"; + } + var proto = base && new base; + if (proto && proto.initialize || (methods && methods.initialize)) + code += "this.initialize();"; + code += "}}"; + var ctor = new Function(code)(); + if (proto) { + ctor.prototype = proto; + ctor.BASE = base; + } + if (base) base.SUBCLASSES.push(ctor); + ctor.prototype.CTOR = ctor; + ctor.PROPS = props || null; + ctor.SELF_PROPS = self_props; + ctor.SUBCLASSES = []; + if (type) { + ctor.prototype.TYPE = ctor.TYPE = type; + } + if (methods) for (i in methods) if (methods.hasOwnProperty(i)) { + if (/^\$/.test(i)) { + ctor[i.substr(1)] = methods[i]; + } else { + ctor.prototype[i] = methods[i]; + } + } + ctor.DEFMETHOD = function(name, method) { + this.prototype[name] = method; + }; + return ctor; +}; + +var AST_Token = DEFNODE("Token", "type value line col pos endpos nlb comments_before file", { +}, null); + +var AST_Node = DEFNODE("Node", "start end", { + clone: function() { + return new this.CTOR(this); + }, + $documentation: "Base class of all AST nodes", + $propdoc: { + start: "[AST_Token] The first token of this node", + end: "[AST_Token] The last token of this node" + }, + _walk: function(visitor) { + return visitor._visit(this); + }, + walk: function(visitor) { + return this._walk(visitor); // not sure the indirection will be any help + } +}, null); + +AST_Node.warn_function = null; +AST_Node.warn = function(txt, props) { + if (AST_Node.warn_function) + AST_Node.warn_function(string_template(txt, props)); +}; + +/* -----[ statements ]----- */ + +var AST_Statement = DEFNODE("Statement", null, { + $documentation: "Base class of all statements", +}); + +var AST_Debugger = DEFNODE("Debugger", null, { + $documentation: "Represents a debugger statement", +}, AST_Statement); + +var AST_Directive = DEFNODE("Directive", "value scope", { + $documentation: "Represents a directive, like \"use strict\";", + $propdoc: { + value: "[string] The value of this directive as a plain string (it's not an AST_String!)", + scope: "[AST_Scope/S] The scope that this directive affects" + }, +}, AST_Statement); + +var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", { + $documentation: "A statement consisting of an expression, i.e. a = 1 + 2", + $propdoc: { + body: "[AST_Node] an expression node (should not be instanceof AST_Statement)" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.body._walk(visitor); + }); + } +}, AST_Statement); + +function walk_body(node, visitor) { + if (node.body instanceof AST_Statement) { + node.body._walk(visitor); + } + else node.body.forEach(function(stat){ + stat._walk(visitor); + }); +}; + +var AST_Block = DEFNODE("Block", "body", { + $documentation: "A body of statements (usually bracketed)", + $propdoc: { + body: "[AST_Statement*] an array of statements" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + walk_body(this, visitor); + }); + } +}, AST_Statement); + +var AST_BlockStatement = DEFNODE("BlockStatement", null, { + $documentation: "A block statement", +}, AST_Block); + +var AST_EmptyStatement = DEFNODE("EmptyStatement", null, { + $documentation: "The empty statement (empty block or simply a semicolon)", + _walk: function(visitor) { + return visitor._visit(this); + } +}, AST_Statement); + +var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", { + $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`", + $propdoc: { + body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.body._walk(visitor); + }); + } +}, AST_Statement); + +var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", { + $documentation: "Statement with a label", + $propdoc: { + label: "[AST_Label] a label definition" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.label._walk(visitor); + this.body._walk(visitor); + }); + } +}, AST_StatementWithBody); + +var AST_IterationStatement = DEFNODE("IterationStatement", null, { + $documentation: "Internal class. All loops inherit from it." +}, AST_StatementWithBody); + +var AST_DWLoop = DEFNODE("DWLoop", "condition", { + $documentation: "Base class for do/while statements", + $propdoc: { + condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.condition._walk(visitor); + this.body._walk(visitor); + }); + } +}, AST_IterationStatement); + +var AST_Do = DEFNODE("Do", null, { + $documentation: "A `do` statement", +}, AST_DWLoop); + +var AST_While = DEFNODE("While", null, { + $documentation: "A `while` statement", +}, AST_DWLoop); + +var AST_For = DEFNODE("For", "init condition step", { + $documentation: "A `for` statement", + $propdoc: { + init: "[AST_Node?] the `for` initialization code, or null if empty", + condition: "[AST_Node?] the `for` termination clause, or null if empty", + step: "[AST_Node?] the `for` update clause, or null if empty" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + if (this.init) this.init._walk(visitor); + if (this.condition) this.condition._walk(visitor); + if (this.step) this.step._walk(visitor); + this.body._walk(visitor); + }); + } +}, AST_IterationStatement); + +var AST_ForIn = DEFNODE("ForIn", "init name object", { + $documentation: "A `for ... in` statement", + $propdoc: { + init: "[AST_Node] the `for/in` initialization code", + name: "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var", + object: "[AST_Node] the object that we're looping through" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.init._walk(visitor); + this.object._walk(visitor); + this.body._walk(visitor); + }); + } +}, AST_IterationStatement); + +var AST_With = DEFNODE("With", "expression", { + $documentation: "A `with` statement", + $propdoc: { + expression: "[AST_Node] the `with` expression" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.expression._walk(visitor); + this.body._walk(visitor); + }); + } +}, AST_StatementWithBody); + +/* -----[ scope and functions ]----- */ + +var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", { + $documentation: "Base class for all statements introducing a lexical scope", + $propdoc: { + directives: "[string*/S] an array of directives declared in this scope", + variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope", + functions: "[Object/S] like `variables`, but only lists function declarations", + uses_with: "[boolean/S] tells whether this scope uses the `with` statement", + uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`", + parent_scope: "[AST_Scope?/S] link to the parent scope", + enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes", + cname: "[integer/S] current index for mangling variables (used internally by the mangler)", + }, +}, AST_Block); + +var AST_Toplevel = DEFNODE("Toplevel", "globals", { + $documentation: "The toplevel scope", + $propdoc: { + globals: "[Object/S] a map of name -> SymbolDef for all undeclared names", + }, + wrap_enclose: function(arg_parameter_pairs) { + var self = this; + var args = []; + var parameters = []; + + arg_parameter_pairs.forEach(function(pair) { + var split = pair.split(":"); + + args.push(split[0]); + parameters.push(split[1]); + }); + + var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")"; + wrapped_tl = parse(wrapped_tl); + wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){ + if (node instanceof AST_Directive && node.value == "$ORIG") { + return MAP.splice(self.body); + } + })); + return wrapped_tl; + }, + wrap_commonjs: function(name, export_all) { + var self = this; + var to_export = []; + if (export_all) { + self.figure_out_scope(); + self.walk(new TreeWalker(function(node){ + if (node instanceof AST_SymbolDeclaration && node.definition().global) { + if (!find_if(function(n){ return n.name == node.name }, to_export)) + to_export.push(node); + } + })); + } + var wrapped_tl = "(function(exports, global){ global['" + name + "'] = exports; '$ORIG'; '$EXPORTS'; }({}, (function(){return this}())))"; + wrapped_tl = parse(wrapped_tl); + wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){ + if (node instanceof AST_SimpleStatement) { + node = node.body; + if (node instanceof AST_String) switch (node.getValue()) { + case "$ORIG": + return MAP.splice(self.body); + case "$EXPORTS": + var body = []; + to_export.forEach(function(sym){ + body.push(new AST_SimpleStatement({ + body: new AST_Assign({ + left: new AST_Sub({ + expression: new AST_SymbolRef({ name: "exports" }), + property: new AST_String({ value: sym.name }), + }), + operator: "=", + right: new AST_SymbolRef(sym), + }), + })); + }); + return MAP.splice(body); + } + } + })); + return wrapped_tl; + } +}, AST_Scope); + +var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", { + $documentation: "Base class for functions", + $propdoc: { + name: "[AST_SymbolDeclaration?] the name of this function", + argnames: "[AST_SymbolFunarg*] array of function arguments", + uses_arguments: "[boolean/S] tells whether this function accesses the arguments array" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + if (this.name) this.name._walk(visitor); + this.argnames.forEach(function(arg){ + arg._walk(visitor); + }); + walk_body(this, visitor); + }); + } +}, AST_Scope); + +var AST_Accessor = DEFNODE("Accessor", null, { + $documentation: "A setter/getter function. The `name` property is always null." +}, AST_Lambda); + +var AST_Function = DEFNODE("Function", null, { + $documentation: "A function expression" +}, AST_Lambda); + +var AST_Defun = DEFNODE("Defun", null, { + $documentation: "A function definition" +}, AST_Lambda); + +/* -----[ JUMPS ]----- */ + +var AST_Jump = DEFNODE("Jump", null, { + $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)" +}, AST_Statement); + +var AST_Exit = DEFNODE("Exit", "value", { + $documentation: "Base class for “exits” (`return` and `throw`)", + $propdoc: { + value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return" + }, + _walk: function(visitor) { + return visitor._visit(this, this.value && function(){ + this.value._walk(visitor); + }); + } +}, AST_Jump); + +var AST_Return = DEFNODE("Return", null, { + $documentation: "A `return` statement" +}, AST_Exit); + +var AST_Throw = DEFNODE("Throw", null, { + $documentation: "A `throw` statement" +}, AST_Exit); + +var AST_LoopControl = DEFNODE("LoopControl", "label", { + $documentation: "Base class for loop control statements (`break` and `continue`)", + $propdoc: { + label: "[AST_LabelRef?] the label, or null if none", + }, + _walk: function(visitor) { + return visitor._visit(this, this.label && function(){ + this.label._walk(visitor); + }); + } +}, AST_Jump); + +var AST_Break = DEFNODE("Break", null, { + $documentation: "A `break` statement" +}, AST_LoopControl); + +var AST_Continue = DEFNODE("Continue", null, { + $documentation: "A `continue` statement" +}, AST_LoopControl); + +/* -----[ IF ]----- */ + +var AST_If = DEFNODE("If", "condition alternative", { + $documentation: "A `if` statement", + $propdoc: { + condition: "[AST_Node] the `if` condition", + alternative: "[AST_Statement?] the `else` part, or null if not present" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.condition._walk(visitor); + this.body._walk(visitor); + if (this.alternative) this.alternative._walk(visitor); + }); + } +}, AST_StatementWithBody); + +/* -----[ SWITCH ]----- */ + +var AST_Switch = DEFNODE("Switch", "expression", { + $documentation: "A `switch` statement", + $propdoc: { + expression: "[AST_Node] the `switch` “discriminant”" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.expression._walk(visitor); + walk_body(this, visitor); + }); + } +}, AST_Block); + +var AST_SwitchBranch = DEFNODE("SwitchBranch", null, { + $documentation: "Base class for `switch` branches", +}, AST_Block); + +var AST_Default = DEFNODE("Default", null, { + $documentation: "A `default` switch branch", +}, AST_SwitchBranch); + +var AST_Case = DEFNODE("Case", "expression", { + $documentation: "A `case` switch branch", + $propdoc: { + expression: "[AST_Node] the `case` expression" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.expression._walk(visitor); + walk_body(this, visitor); + }); + } +}, AST_SwitchBranch); + +/* -----[ EXCEPTIONS ]----- */ + +var AST_Try = DEFNODE("Try", "bcatch bfinally", { + $documentation: "A `try` statement", + $propdoc: { + bcatch: "[AST_Catch?] the catch block, or null if not present", + bfinally: "[AST_Finally?] the finally block, or null if not present" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + walk_body(this, visitor); + if (this.bcatch) this.bcatch._walk(visitor); + if (this.bfinally) this.bfinally._walk(visitor); + }); + } +}, AST_Block); + +// XXX: this is wrong according to ECMA-262 (12.4). the catch block +// should introduce another scope, as the argname should be visible +// only inside the catch block. However, doing it this way because of +// IE which simply introduces the name in the surrounding scope. If +// we ever want to fix this then AST_Catch should inherit from +// AST_Scope. +var AST_Catch = DEFNODE("Catch", "argname", { + $documentation: "A `catch` node; only makes sense as part of a `try` statement", + $propdoc: { + argname: "[AST_SymbolCatch] symbol for the exception" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.argname._walk(visitor); + walk_body(this, visitor); + }); + } +}, AST_Block); + +var AST_Finally = DEFNODE("Finally", null, { + $documentation: "A `finally` node; only makes sense as part of a `try` statement" +}, AST_Block); + +/* -----[ VAR/CONST ]----- */ + +var AST_Definitions = DEFNODE("Definitions", "definitions", { + $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)", + $propdoc: { + definitions: "[AST_VarDef*] array of variable definitions" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.definitions.forEach(function(def){ + def._walk(visitor); + }); + }); + } +}, AST_Statement); + +var AST_Var = DEFNODE("Var", null, { + $documentation: "A `var` statement" +}, AST_Definitions); + +var AST_Const = DEFNODE("Const", null, { + $documentation: "A `const` statement" +}, AST_Definitions); + +var AST_VarDef = DEFNODE("VarDef", "name value", { + $documentation: "A variable declaration; only appears in a AST_Definitions node", + $propdoc: { + name: "[AST_SymbolVar|AST_SymbolConst] name of the variable", + value: "[AST_Node?] initializer, or null of there's no initializer" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.name._walk(visitor); + if (this.value) this.value._walk(visitor); + }); + } +}); + +/* -----[ OTHER ]----- */ + +var AST_Call = DEFNODE("Call", "expression args", { + $documentation: "A function call expression", + $propdoc: { + expression: "[AST_Node] expression to invoke as function", + args: "[AST_Node*] array of arguments" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.expression._walk(visitor); + this.args.forEach(function(arg){ + arg._walk(visitor); + }); + }); + } +}); + +var AST_New = DEFNODE("New", null, { + $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties" +}, AST_Call); + +var AST_Seq = DEFNODE("Seq", "car cdr", { + $documentation: "A sequence expression (two comma-separated expressions)", + $propdoc: { + car: "[AST_Node] first element in sequence", + cdr: "[AST_Node] second element in sequence" + }, + $cons: function(x, y) { + var seq = new AST_Seq(x); + seq.car = x; + seq.cdr = y; + return seq; + }, + $from_array: function(array) { + if (array.length == 0) return null; + if (array.length == 1) return array[0].clone(); + var list = null; + for (var i = array.length; --i >= 0;) { + list = AST_Seq.cons(array[i], list); + } + var p = list; + while (p) { + if (p.cdr && !p.cdr.cdr) { + p.cdr = p.cdr.car; + break; + } + p = p.cdr; + } + return list; + }, + to_array: function() { + var p = this, a = []; + while (p) { + a.push(p.car); + if (p.cdr && !(p.cdr instanceof AST_Seq)) { + a.push(p.cdr); + break; + } + p = p.cdr; + } + return a; + }, + add: function(node) { + var p = this; + while (p) { + if (!(p.cdr instanceof AST_Seq)) { + var cell = AST_Seq.cons(p.cdr, node); + return p.cdr = cell; + } + p = p.cdr; + } + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.car._walk(visitor); + if (this.cdr) this.cdr._walk(visitor); + }); + } +}); + +var AST_PropAccess = DEFNODE("PropAccess", "expression property", { + $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`", + $propdoc: { + expression: "[AST_Node] the “container” expression", + property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node" + } +}); + +var AST_Dot = DEFNODE("Dot", null, { + $documentation: "A dotted property access expression", + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.expression._walk(visitor); + }); + } +}, AST_PropAccess); + +var AST_Sub = DEFNODE("Sub", null, { + $documentation: "Index-style property access, i.e. `a[\"foo\"]`", + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.expression._walk(visitor); + this.property._walk(visitor); + }); + } +}, AST_PropAccess); + +var AST_Unary = DEFNODE("Unary", "operator expression", { + $documentation: "Base class for unary expressions", + $propdoc: { + operator: "[string] the operator", + expression: "[AST_Node] expression that this unary operator applies to" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.expression._walk(visitor); + }); + } +}); + +var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, { + $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`" +}, AST_Unary); + +var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, { + $documentation: "Unary postfix expression, i.e. `i++`" +}, AST_Unary); + +var AST_Binary = DEFNODE("Binary", "left operator right", { + $documentation: "Binary expression, i.e. `a + b`", + $propdoc: { + left: "[AST_Node] left-hand side expression", + operator: "[string] the operator", + right: "[AST_Node] right-hand side expression" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.left._walk(visitor); + this.right._walk(visitor); + }); + } +}); + +var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", { + $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`", + $propdoc: { + condition: "[AST_Node]", + consequent: "[AST_Node]", + alternative: "[AST_Node]" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.condition._walk(visitor); + this.consequent._walk(visitor); + this.alternative._walk(visitor); + }); + } +}); + +var AST_Assign = DEFNODE("Assign", null, { + $documentation: "An assignment expression — `a = b + 5`", +}, AST_Binary); + +/* -----[ LITERALS ]----- */ + +var AST_Array = DEFNODE("Array", "elements", { + $documentation: "An array literal", + $propdoc: { + elements: "[AST_Node*] array of elements" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.elements.forEach(function(el){ + el._walk(visitor); + }); + }); + } +}); + +var AST_Object = DEFNODE("Object", "properties", { + $documentation: "An object literal", + $propdoc: { + properties: "[AST_ObjectProperty*] array of properties" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.properties.forEach(function(prop){ + prop._walk(visitor); + }); + }); + } +}); + +var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", { + $documentation: "Base class for literal object properties", + $propdoc: { + key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an arbitrary AST_Node.", + value: "[AST_Node] property value. For setters and getters this is an AST_Function." + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.value._walk(visitor); + }); + } +}); + +var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, { + $documentation: "A key: value object property", +}, AST_ObjectProperty); + +var AST_ObjectSetter = DEFNODE("ObjectSetter", null, { + $documentation: "An object setter property", +}, AST_ObjectProperty); + +var AST_ObjectGetter = DEFNODE("ObjectGetter", null, { + $documentation: "An object getter property", +}, AST_ObjectProperty); + +var AST_Symbol = DEFNODE("Symbol", "scope name thedef", { + $propdoc: { + name: "[string] name of this symbol", + scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)", + thedef: "[SymbolDef/S] the definition of this symbol" + }, + $documentation: "Base class for all symbols", +}); + +var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, { + $documentation: "The name of a property accessor (setter/getter function)" +}, AST_Symbol); + +var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", { + $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)", + $propdoc: { + init: "[AST_Node*/S] array of initializers for this declaration." + } +}, AST_Symbol); + +var AST_SymbolVar = DEFNODE("SymbolVar", null, { + $documentation: "Symbol defining a variable", +}, AST_SymbolDeclaration); + +var AST_SymbolConst = DEFNODE("SymbolConst", null, { + $documentation: "A constant declaration" +}, AST_SymbolDeclaration); + +var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, { + $documentation: "Symbol naming a function argument", +}, AST_SymbolVar); + +var AST_SymbolDefun = DEFNODE("SymbolDefun", null, { + $documentation: "Symbol defining a function", +}, AST_SymbolDeclaration); + +var AST_SymbolLambda = DEFNODE("SymbolLambda", null, { + $documentation: "Symbol naming a function expression", +}, AST_SymbolDeclaration); + +var AST_SymbolCatch = DEFNODE("SymbolCatch", null, { + $documentation: "Symbol naming the exception in catch", +}, AST_SymbolDeclaration); + +var AST_Label = DEFNODE("Label", "references", { + $documentation: "Symbol naming a label (declaration)", + $propdoc: { + references: "[AST_LoopControl*] a list of nodes referring to this label" + }, + initialize: function() { + this.references = []; + this.thedef = this; + } +}, AST_Symbol); + +var AST_SymbolRef = DEFNODE("SymbolRef", null, { + $documentation: "Reference to some symbol (not definition/declaration)", +}, AST_Symbol); + +var AST_LabelRef = DEFNODE("LabelRef", null, { + $documentation: "Reference to a label symbol", +}, AST_Symbol); + +var AST_This = DEFNODE("This", null, { + $documentation: "The `this` symbol", +}, AST_Symbol); + +var AST_Constant = DEFNODE("Constant", null, { + $documentation: "Base class for all constants", + getValue: function() { + return this.value; + } +}); + +var AST_String = DEFNODE("String", "value", { + $documentation: "A string literal", + $propdoc: { + value: "[string] the contents of this string" + } +}, AST_Constant); + +var AST_Number = DEFNODE("Number", "value", { + $documentation: "A number literal", + $propdoc: { + value: "[number] the numeric value" + } +}, AST_Constant); + +var AST_RegExp = DEFNODE("RegExp", "value", { + $documentation: "A regexp literal", + $propdoc: { + value: "[RegExp] the actual regexp" + } +}, AST_Constant); + +var AST_Atom = DEFNODE("Atom", null, { + $documentation: "Base class for atoms", +}, AST_Constant); + +var AST_Null = DEFNODE("Null", null, { + $documentation: "The `null` atom", + value: null +}, AST_Atom); + +var AST_NaN = DEFNODE("NaN", null, { + $documentation: "The impossible value", + value: 0/0 +}, AST_Atom); + +var AST_Undefined = DEFNODE("Undefined", null, { + $documentation: "The `undefined` value", + value: (function(){}()) +}, AST_Atom); + +var AST_Hole = DEFNODE("Hole", null, { + $documentation: "A hole in an array", + value: (function(){}()) +}, AST_Atom); + +var AST_Infinity = DEFNODE("Infinity", null, { + $documentation: "The `Infinity` value", + value: 1/0 +}, AST_Atom); + +var AST_Boolean = DEFNODE("Boolean", null, { + $documentation: "Base class for booleans", +}, AST_Atom); + +var AST_False = DEFNODE("False", null, { + $documentation: "The `false` atom", + value: false +}, AST_Boolean); + +var AST_True = DEFNODE("True", null, { + $documentation: "The `true` atom", + value: true +}, AST_Boolean); + +/* -----[ TreeWalker ]----- */ + +function TreeWalker(callback) { + this.visit = callback; + this.stack = []; +}; +TreeWalker.prototype = { + _visit: function(node, descend) { + this.stack.push(node); + var ret = this.visit(node, descend ? function(){ + descend.call(node); + } : noop); + if (!ret && descend) { + descend.call(node); + } + this.stack.pop(); + return ret; + }, + parent: function(n) { + return this.stack[this.stack.length - 2 - (n || 0)]; + }, + push: function (node) { + this.stack.push(node); + }, + pop: function() { + return this.stack.pop(); + }, + self: function() { + return this.stack[this.stack.length - 1]; + }, + find_parent: function(type) { + var stack = this.stack; + for (var i = stack.length; --i >= 0;) { + var x = stack[i]; + if (x instanceof type) return x; + } + }, + has_directive: function(type) { + return this.find_parent(AST_Scope).has_directive(type); + }, + in_boolean_context: function() { + var stack = this.stack; + var i = stack.length, self = stack[--i]; + while (i > 0) { + var p = stack[--i]; + if ((p instanceof AST_If && p.condition === self) || + (p instanceof AST_Conditional && p.condition === self) || + (p instanceof AST_DWLoop && p.condition === self) || + (p instanceof AST_For && p.condition === self) || + (p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self)) + { + return true; + } + if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||"))) + return false; + self = p; + } + }, + loopcontrol_target: function(label) { + var stack = this.stack; + if (label) for (var i = stack.length; --i >= 0;) { + var x = stack[i]; + if (x instanceof AST_LabeledStatement && x.label.name == label.name) { + return x.body; + } + } else for (var i = stack.length; --i >= 0;) { + var x = stack[i]; + if (x instanceof AST_Switch || x instanceof AST_IterationStatement) + return x; + } + } +}; diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/compress.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/compress.js new file mode 100644 index 0000000..f44277c --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/compress.js @@ -0,0 +1,2267 @@ +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + 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. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 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. + + ***********************************************************************/ + +"use strict"; + +function Compressor(options, false_by_default) { + if (!(this instanceof Compressor)) + return new Compressor(options, false_by_default); + TreeTransformer.call(this, this.before, this.after); + this.options = defaults(options, { + sequences : !false_by_default, + properties : !false_by_default, + dead_code : !false_by_default, + drop_debugger : !false_by_default, + unsafe : false, + unsafe_comps : false, + conditionals : !false_by_default, + comparisons : !false_by_default, + evaluate : !false_by_default, + booleans : !false_by_default, + loops : !false_by_default, + unused : !false_by_default, + hoist_funs : !false_by_default, + hoist_vars : false, + if_return : !false_by_default, + join_vars : !false_by_default, + cascade : !false_by_default, + side_effects : !false_by_default, + pure_getters : false, + pure_funcs : null, + negate_iife : !false_by_default, + screw_ie8 : false, + + warnings : true, + global_defs : {} + }, true); +}; + +Compressor.prototype = new TreeTransformer; +merge(Compressor.prototype, { + option: function(key) { return this.options[key] }, + warn: function() { + if (this.options.warnings) + AST_Node.warn.apply(AST_Node, arguments); + }, + before: function(node, descend, in_list) { + if (node._squeezed) return node; + if (node instanceof AST_Scope) { + //node.drop_unused(this); + node = node.hoist_declarations(this); + } + descend(node, this); + node = node.optimize(this); + if (node instanceof AST_Scope) { + node.drop_unused(this); + descend(node, this); + } + node._squeezed = true; + return node; + } +}); + +(function(){ + + function OPT(node, optimizer) { + node.DEFMETHOD("optimize", function(compressor){ + var self = this; + if (self._optimized) return self; + var opt = optimizer(self, compressor); + opt._optimized = true; + if (opt === self) return opt; + return opt.transform(compressor); + }); + }; + + OPT(AST_Node, function(self, compressor){ + return self; + }); + + AST_Node.DEFMETHOD("equivalent_to", function(node){ + // XXX: this is a rather expensive way to test two node's equivalence: + return this.print_to_string() == node.print_to_string(); + }); + + function make_node(ctor, orig, props) { + if (!props) props = {}; + if (orig) { + if (!props.start) props.start = orig.start; + if (!props.end) props.end = orig.end; + } + return new ctor(props); + }; + + function make_node_from_constant(compressor, val, orig) { + // XXX: WIP. + // if (val instanceof AST_Node) return val.transform(new TreeTransformer(null, function(node){ + // if (node instanceof AST_SymbolRef) { + // var scope = compressor.find_parent(AST_Scope); + // var def = scope.find_variable(node); + // node.thedef = def; + // return node; + // } + // })).transform(compressor); + + if (val instanceof AST_Node) return val.transform(compressor); + switch (typeof val) { + case "string": + return make_node(AST_String, orig, { + value: val + }).optimize(compressor); + case "number": + return make_node(isNaN(val) ? AST_NaN : AST_Number, orig, { + value: val + }).optimize(compressor); + case "boolean": + return make_node(val ? AST_True : AST_False, orig).optimize(compressor); + case "undefined": + return make_node(AST_Undefined, orig).optimize(compressor); + default: + if (val === null) { + return make_node(AST_Null, orig).optimize(compressor); + } + if (val instanceof RegExp) { + return make_node(AST_RegExp, orig).optimize(compressor); + } + throw new Error(string_template("Can't handle constant of type: {type}", { + type: typeof val + })); + } + }; + + function as_statement_array(thing) { + if (thing === null) return []; + if (thing instanceof AST_BlockStatement) return thing.body; + if (thing instanceof AST_EmptyStatement) return []; + if (thing instanceof AST_Statement) return [ thing ]; + throw new Error("Can't convert thing to statement array"); + }; + + function is_empty(thing) { + if (thing === null) return true; + if (thing instanceof AST_EmptyStatement) return true; + if (thing instanceof AST_BlockStatement) return thing.body.length == 0; + return false; + }; + + function loop_body(x) { + if (x instanceof AST_Switch) return x; + if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) { + return (x.body instanceof AST_BlockStatement ? x.body : x); + } + return x; + }; + + function tighten_body(statements, compressor) { + var CHANGED; + do { + CHANGED = false; + statements = eliminate_spurious_blocks(statements); + if (compressor.option("dead_code")) { + statements = eliminate_dead_code(statements, compressor); + } + if (compressor.option("if_return")) { + statements = handle_if_return(statements, compressor); + } + if (compressor.option("sequences")) { + statements = sequencesize(statements, compressor); + } + if (compressor.option("join_vars")) { + statements = join_consecutive_vars(statements, compressor); + } + } while (CHANGED); + + if (compressor.option("negate_iife")) { + negate_iifes(statements, compressor); + } + + return statements; + + function eliminate_spurious_blocks(statements) { + var seen_dirs = []; + return statements.reduce(function(a, stat){ + if (stat instanceof AST_BlockStatement) { + CHANGED = true; + a.push.apply(a, eliminate_spurious_blocks(stat.body)); + } else if (stat instanceof AST_EmptyStatement) { + CHANGED = true; + } else if (stat instanceof AST_Directive) { + if (seen_dirs.indexOf(stat.value) < 0) { + a.push(stat); + seen_dirs.push(stat.value); + } else { + CHANGED = true; + } + } else { + a.push(stat); + } + return a; + }, []); + }; + + function handle_if_return(statements, compressor) { + var self = compressor.self(); + var in_lambda = self instanceof AST_Lambda; + var ret = []; + loop: for (var i = statements.length; --i >= 0;) { + var stat = statements[i]; + switch (true) { + case (in_lambda && stat instanceof AST_Return && !stat.value && ret.length == 0): + CHANGED = true; + // note, ret.length is probably always zero + // because we drop unreachable code before this + // step. nevertheless, it's good to check. + continue loop; + case stat instanceof AST_If: + if (stat.body instanceof AST_Return) { + //--- + // pretty silly case, but: + // if (foo()) return; return; ==> foo(); return; + if (((in_lambda && ret.length == 0) + || (ret[0] instanceof AST_Return && !ret[0].value)) + && !stat.body.value && !stat.alternative) { + CHANGED = true; + var cond = make_node(AST_SimpleStatement, stat.condition, { + body: stat.condition + }); + ret.unshift(cond); + continue loop; + } + //--- + // if (foo()) return x; return y; ==> return foo() ? x : y; + if (ret[0] instanceof AST_Return && stat.body.value && ret[0].value && !stat.alternative) { + CHANGED = true; + stat = stat.clone(); + stat.alternative = ret[0]; + ret[0] = stat.transform(compressor); + continue loop; + } + //--- + // if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined; + if ((ret.length == 0 || ret[0] instanceof AST_Return) && stat.body.value && !stat.alternative && in_lambda) { + CHANGED = true; + stat = stat.clone(); + stat.alternative = ret[0] || make_node(AST_Return, stat, { + value: make_node(AST_Undefined, stat) + }); + ret[0] = stat.transform(compressor); + continue loop; + } + //--- + // if (foo()) return; [ else x... ]; y... ==> if (!foo()) { x...; y... } + if (!stat.body.value && in_lambda) { + CHANGED = true; + stat = stat.clone(); + stat.condition = stat.condition.negate(compressor); + stat.body = make_node(AST_BlockStatement, stat, { + body: as_statement_array(stat.alternative).concat(ret) + }); + stat.alternative = null; + ret = [ stat.transform(compressor) ]; + continue loop; + } + //--- + if (ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement + && (!stat.alternative || stat.alternative instanceof AST_SimpleStatement)) { + CHANGED = true; + ret.push(make_node(AST_Return, ret[0], { + value: make_node(AST_Undefined, ret[0]) + }).transform(compressor)); + ret = as_statement_array(stat.alternative).concat(ret); + ret.unshift(stat); + continue loop; + } + } + + var ab = aborts(stat.body); + var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null; + if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda) + || (ab instanceof AST_Continue && self === loop_body(lct)) + || (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) { + if (ab.label) { + remove(ab.label.thedef.references, ab); + } + CHANGED = true; + var body = as_statement_array(stat.body).slice(0, -1); + stat = stat.clone(); + stat.condition = stat.condition.negate(compressor); + stat.body = make_node(AST_BlockStatement, stat, { + body: ret + }); + stat.alternative = make_node(AST_BlockStatement, stat, { + body: body + }); + ret = [ stat.transform(compressor) ]; + continue loop; + } + + var ab = aborts(stat.alternative); + var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null; + if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda) + || (ab instanceof AST_Continue && self === loop_body(lct)) + || (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) { + if (ab.label) { + remove(ab.label.thedef.references, ab); + } + CHANGED = true; + stat = stat.clone(); + stat.body = make_node(AST_BlockStatement, stat.body, { + body: as_statement_array(stat.body).concat(ret) + }); + stat.alternative = make_node(AST_BlockStatement, stat.alternative, { + body: as_statement_array(stat.alternative).slice(0, -1) + }); + ret = [ stat.transform(compressor) ]; + continue loop; + } + + ret.unshift(stat); + break; + default: + ret.unshift(stat); + break; + } + } + return ret; + }; + + function eliminate_dead_code(statements, compressor) { + var has_quit = false; + var orig = statements.length; + var self = compressor.self(); + statements = statements.reduce(function(a, stat){ + if (has_quit) { + extract_declarations_from_unreachable_code(compressor, stat, a); + } else { + if (stat instanceof AST_LoopControl) { + var lct = compressor.loopcontrol_target(stat.label); + if ((stat instanceof AST_Break + && lct instanceof AST_BlockStatement + && loop_body(lct) === self) || (stat instanceof AST_Continue + && loop_body(lct) === self)) { + if (stat.label) { + remove(stat.label.thedef.references, stat); + } + } else { + a.push(stat); + } + } else { + a.push(stat); + } + if (aborts(stat)) has_quit = true; + } + return a; + }, []); + CHANGED = statements.length != orig; + return statements; + }; + + function sequencesize(statements, compressor) { + if (statements.length < 2) return statements; + var seq = [], ret = []; + function push_seq() { + seq = AST_Seq.from_array(seq); + if (seq) ret.push(make_node(AST_SimpleStatement, seq, { + body: seq + })); + seq = []; + }; + statements.forEach(function(stat){ + if (stat instanceof AST_SimpleStatement) seq.push(stat.body); + else push_seq(), ret.push(stat); + }); + push_seq(); + ret = sequencesize_2(ret, compressor); + CHANGED = ret.length != statements.length; + return ret; + }; + + function sequencesize_2(statements, compressor) { + function cons_seq(right) { + ret.pop(); + var left = prev.body; + if (left instanceof AST_Seq) { + left.add(right); + } else { + left = AST_Seq.cons(left, right); + } + return left.transform(compressor); + }; + var ret = [], prev = null; + statements.forEach(function(stat){ + if (prev) { + if (stat instanceof AST_For) { + var opera = {}; + try { + prev.body.walk(new TreeWalker(function(node){ + if (node instanceof AST_Binary && node.operator == "in") + throw opera; + })); + if (stat.init && !(stat.init instanceof AST_Definitions)) { + stat.init = cons_seq(stat.init); + } + else if (!stat.init) { + stat.init = prev.body; + ret.pop(); + } + } catch(ex) { + if (ex !== opera) throw ex; + } + } + else if (stat instanceof AST_If) { + stat.condition = cons_seq(stat.condition); + } + else if (stat instanceof AST_With) { + stat.expression = cons_seq(stat.expression); + } + else if (stat instanceof AST_Exit && stat.value) { + stat.value = cons_seq(stat.value); + } + else if (stat instanceof AST_Exit) { + stat.value = cons_seq(make_node(AST_Undefined, stat)); + } + else if (stat instanceof AST_Switch) { + stat.expression = cons_seq(stat.expression); + } + } + ret.push(stat); + prev = stat instanceof AST_SimpleStatement ? stat : null; + }); + return ret; + }; + + function join_consecutive_vars(statements, compressor) { + var prev = null; + return statements.reduce(function(a, stat){ + if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) { + prev.definitions = prev.definitions.concat(stat.definitions); + CHANGED = true; + } + else if (stat instanceof AST_For + && prev instanceof AST_Definitions + && (!stat.init || stat.init.TYPE == prev.TYPE)) { + CHANGED = true; + a.pop(); + if (stat.init) { + stat.init.definitions = prev.definitions.concat(stat.init.definitions); + } else { + stat.init = prev; + } + a.push(stat); + prev = stat; + } + else { + prev = stat; + a.push(stat); + } + return a; + }, []); + }; + + function negate_iifes(statements, compressor) { + statements.forEach(function(stat){ + if (stat instanceof AST_SimpleStatement) { + stat.body = (function transform(thing) { + return thing.transform(new TreeTransformer(function(node){ + if (node instanceof AST_Call && node.expression instanceof AST_Function) { + return make_node(AST_UnaryPrefix, node, { + operator: "!", + expression: node + }); + } + else if (node instanceof AST_Call) { + node.expression = transform(node.expression); + } + else if (node instanceof AST_Seq) { + node.car = transform(node.car); + } + else if (node instanceof AST_Conditional) { + var expr = transform(node.condition); + if (expr !== node.condition) { + // it has been negated, reverse + node.condition = expr; + var tmp = node.consequent; + node.consequent = node.alternative; + node.alternative = tmp; + } + } + return node; + })); + })(stat.body); + } + }); + }; + + }; + + function extract_declarations_from_unreachable_code(compressor, stat, target) { + compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start); + stat.walk(new TreeWalker(function(node){ + if (node instanceof AST_Definitions) { + compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start); + node.remove_initializers(); + target.push(node); + return true; + } + if (node instanceof AST_Defun) { + target.push(node); + return true; + } + if (node instanceof AST_Scope) { + return true; + } + })); + }; + + /* -----[ boolean/negation helpers ]----- */ + + // methods to determine whether an expression has a boolean result type + (function (def){ + var unary_bool = [ "!", "delete" ]; + var binary_bool = [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ]; + def(AST_Node, function(){ return false }); + def(AST_UnaryPrefix, function(){ + return member(this.operator, unary_bool); + }); + def(AST_Binary, function(){ + return member(this.operator, binary_bool) || + ( (this.operator == "&&" || this.operator == "||") && + this.left.is_boolean() && this.right.is_boolean() ); + }); + def(AST_Conditional, function(){ + return this.consequent.is_boolean() && this.alternative.is_boolean(); + }); + def(AST_Assign, function(){ + return this.operator == "=" && this.right.is_boolean(); + }); + def(AST_Seq, function(){ + return this.cdr.is_boolean(); + }); + def(AST_True, function(){ return true }); + def(AST_False, function(){ return true }); + })(function(node, func){ + node.DEFMETHOD("is_boolean", func); + }); + + // methods to determine if an expression has a string result type + (function (def){ + def(AST_Node, function(){ return false }); + def(AST_String, function(){ return true }); + def(AST_UnaryPrefix, function(){ + return this.operator == "typeof"; + }); + def(AST_Binary, function(compressor){ + return this.operator == "+" && + (this.left.is_string(compressor) || this.right.is_string(compressor)); + }); + def(AST_Assign, function(compressor){ + return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor); + }); + def(AST_Seq, function(compressor){ + return this.cdr.is_string(compressor); + }); + def(AST_Conditional, function(compressor){ + return this.consequent.is_string(compressor) && this.alternative.is_string(compressor); + }); + def(AST_Call, function(compressor){ + return compressor.option("unsafe") + && this.expression instanceof AST_SymbolRef + && this.expression.name == "String" + && this.expression.undeclared(); + }); + })(function(node, func){ + node.DEFMETHOD("is_string", func); + }); + + function best_of(ast1, ast2) { + return ast1.print_to_string().length > + ast2.print_to_string().length + ? ast2 : ast1; + }; + + // methods to evaluate a constant expression + (function (def){ + // The evaluate method returns an array with one or two + // elements. If the node has been successfully reduced to a + // constant, then the second element tells us the value; + // otherwise the second element is missing. The first element + // of the array is always an AST_Node descendant; if + // evaluation was successful it's a node that represents the + // constant; otherwise it's the original or a replacement node. + AST_Node.DEFMETHOD("evaluate", function(compressor){ + if (!compressor.option("evaluate")) return [ this ]; + try { + var val = this._eval(compressor); + return [ best_of(make_node_from_constant(compressor, val, this), this), val ]; + } catch(ex) { + if (ex !== def) throw ex; + return [ this ]; + } + }); + def(AST_Statement, function(){ + throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start)); + }); + def(AST_Function, function(){ + // XXX: AST_Function inherits from AST_Scope, which itself + // inherits from AST_Statement; however, an AST_Function + // isn't really a statement. This could byte in other + // places too. :-( Wish JS had multiple inheritance. + throw def; + }); + function ev(node, compressor) { + if (!compressor) throw new Error("Compressor must be passed"); + + return node._eval(compressor); + }; + def(AST_Node, function(){ + throw def; // not constant + }); + def(AST_Constant, function(){ + return this.getValue(); + }); + def(AST_UnaryPrefix, function(compressor){ + var e = this.expression; + switch (this.operator) { + case "!": return !ev(e, compressor); + case "typeof": + // Function would be evaluated to an array and so typeof would + // incorrectly return 'object'. Hence making is a special case. + if (e instanceof AST_Function) return typeof function(){}; + + e = ev(e, compressor); + + // typeof returns "object" or "function" on different platforms + // so cannot evaluate reliably + if (e instanceof RegExp) throw def; + + return typeof e; + case "void": return void ev(e, compressor); + case "~": return ~ev(e, compressor); + case "-": + e = ev(e, compressor); + if (e === 0) throw def; + return -e; + case "+": return +ev(e, compressor); + } + throw def; + }); + def(AST_Binary, function(c){ + var left = this.left, right = this.right; + switch (this.operator) { + case "&&" : return ev(left, c) && ev(right, c); + case "||" : return ev(left, c) || ev(right, c); + case "|" : return ev(left, c) | ev(right, c); + case "&" : return ev(left, c) & ev(right, c); + case "^" : return ev(left, c) ^ ev(right, c); + case "+" : return ev(left, c) + ev(right, c); + case "*" : return ev(left, c) * ev(right, c); + case "/" : return ev(left, c) / ev(right, c); + case "%" : return ev(left, c) % ev(right, c); + case "-" : return ev(left, c) - ev(right, c); + case "<<" : return ev(left, c) << ev(right, c); + case ">>" : return ev(left, c) >> ev(right, c); + case ">>>" : return ev(left, c) >>> ev(right, c); + case "==" : return ev(left, c) == ev(right, c); + case "===" : return ev(left, c) === ev(right, c); + case "!=" : return ev(left, c) != ev(right, c); + case "!==" : return ev(left, c) !== ev(right, c); + case "<" : return ev(left, c) < ev(right, c); + case "<=" : return ev(left, c) <= ev(right, c); + case ">" : return ev(left, c) > ev(right, c); + case ">=" : return ev(left, c) >= ev(right, c); + case "in" : return ev(left, c) in ev(right, c); + case "instanceof" : return ev(left, c) instanceof ev(right, c); + } + throw def; + }); + def(AST_Conditional, function(compressor){ + return ev(this.condition, compressor) + ? ev(this.consequent, compressor) + : ev(this.alternative, compressor); + }); + def(AST_SymbolRef, function(compressor){ + var d = this.definition(); + if (d && d.constant && d.init) return ev(d.init, compressor); + throw def; + }); + })(function(node, func){ + node.DEFMETHOD("_eval", func); + }); + + // method to negate an expression + (function(def){ + function basic_negation(exp) { + return make_node(AST_UnaryPrefix, exp, { + operator: "!", + expression: exp + }); + }; + def(AST_Node, function(){ + return basic_negation(this); + }); + def(AST_Statement, function(){ + throw new Error("Cannot negate a statement"); + }); + def(AST_Function, function(){ + return basic_negation(this); + }); + def(AST_UnaryPrefix, function(){ + if (this.operator == "!") + return this.expression; + return basic_negation(this); + }); + def(AST_Seq, function(compressor){ + var self = this.clone(); + self.cdr = self.cdr.negate(compressor); + return self; + }); + def(AST_Conditional, function(compressor){ + var self = this.clone(); + self.consequent = self.consequent.negate(compressor); + self.alternative = self.alternative.negate(compressor); + return best_of(basic_negation(this), self); + }); + def(AST_Binary, function(compressor){ + var self = this.clone(), op = this.operator; + if (compressor.option("unsafe_comps")) { + switch (op) { + case "<=" : self.operator = ">" ; return self; + case "<" : self.operator = ">=" ; return self; + case ">=" : self.operator = "<" ; return self; + case ">" : self.operator = "<=" ; return self; + } + } + switch (op) { + case "==" : self.operator = "!="; return self; + case "!=" : self.operator = "=="; return self; + case "===": self.operator = "!=="; return self; + case "!==": self.operator = "==="; return self; + case "&&": + self.operator = "||"; + self.left = self.left.negate(compressor); + self.right = self.right.negate(compressor); + return best_of(basic_negation(this), self); + case "||": + self.operator = "&&"; + self.left = self.left.negate(compressor); + self.right = self.right.negate(compressor); + return best_of(basic_negation(this), self); + } + return basic_negation(this); + }); + })(function(node, func){ + node.DEFMETHOD("negate", function(compressor){ + return func.call(this, compressor); + }); + }); + + // determine if expression has side effects + (function(def){ + def(AST_Node, function(compressor){ return true }); + + def(AST_EmptyStatement, function(compressor){ return false }); + def(AST_Constant, function(compressor){ return false }); + def(AST_This, function(compressor){ return false }); + + def(AST_Call, function(compressor){ + var pure = compressor.option("pure_funcs"); + if (!pure) return true; + return pure.indexOf(this.expression.print_to_string()) < 0; + }); + + def(AST_Block, function(compressor){ + for (var i = this.body.length; --i >= 0;) { + if (this.body[i].has_side_effects(compressor)) + return true; + } + return false; + }); + + def(AST_SimpleStatement, function(compressor){ + return this.body.has_side_effects(compressor); + }); + def(AST_Defun, function(compressor){ return true }); + def(AST_Function, function(compressor){ return false }); + def(AST_Binary, function(compressor){ + return this.left.has_side_effects(compressor) + || this.right.has_side_effects(compressor); + }); + def(AST_Assign, function(compressor){ return true }); + def(AST_Conditional, function(compressor){ + return this.condition.has_side_effects(compressor) + || this.consequent.has_side_effects(compressor) + || this.alternative.has_side_effects(compressor); + }); + def(AST_Unary, function(compressor){ + return this.operator == "delete" + || this.operator == "++" + || this.operator == "--" + || this.expression.has_side_effects(compressor); + }); + def(AST_SymbolRef, function(compressor){ return false }); + def(AST_Object, function(compressor){ + for (var i = this.properties.length; --i >= 0;) + if (this.properties[i].has_side_effects(compressor)) + return true; + return false; + }); + def(AST_ObjectProperty, function(compressor){ + return this.value.has_side_effects(compressor); + }); + def(AST_Array, function(compressor){ + for (var i = this.elements.length; --i >= 0;) + if (this.elements[i].has_side_effects(compressor)) + return true; + return false; + }); + def(AST_Dot, function(compressor){ + if (!compressor.option("pure_getters")) return true; + return this.expression.has_side_effects(compressor); + }); + def(AST_Sub, function(compressor){ + if (!compressor.option("pure_getters")) return true; + return this.expression.has_side_effects(compressor) + || this.property.has_side_effects(compressor); + }); + def(AST_PropAccess, function(compressor){ + return !compressor.option("pure_getters"); + }); + def(AST_Seq, function(compressor){ + return this.car.has_side_effects(compressor) + || this.cdr.has_side_effects(compressor); + }); + })(function(node, func){ + node.DEFMETHOD("has_side_effects", func); + }); + + // tell me if a statement aborts + function aborts(thing) { + return thing && thing.aborts(); + }; + (function(def){ + def(AST_Statement, function(){ return null }); + def(AST_Jump, function(){ return this }); + function block_aborts(){ + var n = this.body.length; + return n > 0 && aborts(this.body[n - 1]); + }; + def(AST_BlockStatement, block_aborts); + def(AST_SwitchBranch, block_aborts); + def(AST_If, function(){ + return this.alternative && aborts(this.body) && aborts(this.alternative); + }); + })(function(node, func){ + node.DEFMETHOD("aborts", func); + }); + + /* -----[ optimizers ]----- */ + + OPT(AST_Directive, function(self, compressor){ + if (self.scope.has_directive(self.value) !== self.scope) { + return make_node(AST_EmptyStatement, self); + } + return self; + }); + + OPT(AST_Debugger, function(self, compressor){ + if (compressor.option("drop_debugger")) + return make_node(AST_EmptyStatement, self); + return self; + }); + + OPT(AST_LabeledStatement, function(self, compressor){ + if (self.body instanceof AST_Break + && compressor.loopcontrol_target(self.body.label) === self.body) { + return make_node(AST_EmptyStatement, self); + } + return self.label.references.length == 0 ? self.body : self; + }); + + OPT(AST_Block, function(self, compressor){ + self.body = tighten_body(self.body, compressor); + return self; + }); + + OPT(AST_BlockStatement, function(self, compressor){ + self.body = tighten_body(self.body, compressor); + switch (self.body.length) { + case 1: return self.body[0]; + case 0: return make_node(AST_EmptyStatement, self); + } + return self; + }); + + AST_Scope.DEFMETHOD("drop_unused", function(compressor){ + var self = this; + if (compressor.option("unused") + && !(self instanceof AST_Toplevel) + && !self.uses_eval + ) { + var in_use = []; + var initializations = new Dictionary(); + // pass 1: find out which symbols are directly used in + // this scope (not in nested scopes). + var scope = this; + var tw = new TreeWalker(function(node, descend){ + if (node !== self) { + if (node instanceof AST_Defun) { + initializations.add(node.name.name, node); + return true; // don't go in nested scopes + } + if (node instanceof AST_Definitions && scope === self) { + node.definitions.forEach(function(def){ + if (def.value) { + initializations.add(def.name.name, def.value); + if (def.value.has_side_effects(compressor)) { + def.value.walk(tw); + } + } + }); + return true; + } + if (node instanceof AST_SymbolRef) { + push_uniq(in_use, node.definition()); + return true; + } + if (node instanceof AST_Scope) { + var save_scope = scope; + scope = node; + descend(); + scope = save_scope; + return true; + } + } + }); + self.walk(tw); + // pass 2: for every used symbol we need to walk its + // initialization code to figure out if it uses other + // symbols (that may not be in_use). + for (var i = 0; i < in_use.length; ++i) { + in_use[i].orig.forEach(function(decl){ + // undeclared globals will be instanceof AST_SymbolRef + var init = initializations.get(decl.name); + if (init) init.forEach(function(init){ + var tw = new TreeWalker(function(node){ + if (node instanceof AST_SymbolRef) { + push_uniq(in_use, node.definition()); + } + }); + init.walk(tw); + }); + }); + } + // pass 3: we should drop declarations not in_use + var tt = new TreeTransformer( + function before(node, descend, in_list) { + if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) { + for (var a = node.argnames, i = a.length; --i >= 0;) { + var sym = a[i]; + if (sym.unreferenced()) { + a.pop(); + compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", { + name : sym.name, + file : sym.start.file, + line : sym.start.line, + col : sym.start.col + }); + } + else break; + } + } + if (node instanceof AST_Defun && node !== self) { + if (!member(node.name.definition(), in_use)) { + compressor.warn("Dropping unused function {name} [{file}:{line},{col}]", { + name : node.name.name, + file : node.name.start.file, + line : node.name.start.line, + col : node.name.start.col + }); + return make_node(AST_EmptyStatement, node); + } + return node; + } + if (node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn)) { + var def = node.definitions.filter(function(def){ + if (member(def.name.definition(), in_use)) return true; + var w = { + name : def.name.name, + file : def.name.start.file, + line : def.name.start.line, + col : def.name.start.col + }; + if (def.value && def.value.has_side_effects(compressor)) { + def._unused_side_effects = true; + compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", w); + return true; + } + compressor.warn("Dropping unused variable {name} [{file}:{line},{col}]", w); + return false; + }); + // place uninitialized names at the start + def = mergeSort(def, function(a, b){ + if (!a.value && b.value) return -1; + if (!b.value && a.value) return 1; + return 0; + }); + // for unused names whose initialization has + // side effects, we can cascade the init. code + // into the next one, or next statement. + var side_effects = []; + for (var i = 0; i < def.length;) { + var x = def[i]; + if (x._unused_side_effects) { + side_effects.push(x.value); + def.splice(i, 1); + } else { + if (side_effects.length > 0) { + side_effects.push(x.value); + x.value = AST_Seq.from_array(side_effects); + side_effects = []; + } + ++i; + } + } + if (side_effects.length > 0) { + side_effects = make_node(AST_BlockStatement, node, { + body: [ make_node(AST_SimpleStatement, node, { + body: AST_Seq.from_array(side_effects) + }) ] + }); + } else { + side_effects = null; + } + if (def.length == 0 && !side_effects) { + return make_node(AST_EmptyStatement, node); + } + if (def.length == 0) { + return side_effects; + } + node.definitions = def; + if (side_effects) { + side_effects.body.unshift(node); + node = side_effects; + } + return node; + } + if (node instanceof AST_For) { + descend(node, this); + + if (node.init instanceof AST_BlockStatement) { + // certain combination of unused name + side effect leads to: + // https://github.com/mishoo/UglifyJS2/issues/44 + // that's an invalid AST. + // We fix it at this stage by moving the `var` outside the `for`. + + var body = node.init.body.slice(0, -1); + node.init = node.init.body.slice(-1)[0].body; + body.push(node); + + return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, { + body: body + }); + } + } + if (node instanceof AST_Scope && node !== self) + return node; + } + ); + self.transform(tt); + } + }); + + AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){ + var hoist_funs = compressor.option("hoist_funs"); + var hoist_vars = compressor.option("hoist_vars"); + var self = this; + if (hoist_funs || hoist_vars) { + var dirs = []; + var hoisted = []; + var vars = new Dictionary(), vars_found = 0, var_decl = 0; + // let's count var_decl first, we seem to waste a lot of + // space if we hoist `var` when there's only one. + self.walk(new TreeWalker(function(node){ + if (node instanceof AST_Scope && node !== self) + return true; + if (node instanceof AST_Var) { + ++var_decl; + return true; + } + })); + hoist_vars = hoist_vars && var_decl > 1; + var tt = new TreeTransformer( + function before(node) { + if (node !== self) { + if (node instanceof AST_Directive) { + dirs.push(node); + return make_node(AST_EmptyStatement, node); + } + if (node instanceof AST_Defun && hoist_funs) { + hoisted.push(node); + return make_node(AST_EmptyStatement, node); + } + if (node instanceof AST_Var && hoist_vars) { + node.definitions.forEach(function(def){ + vars.set(def.name.name, def); + ++vars_found; + }); + var seq = node.to_assignments(); + var p = tt.parent(); + if (p instanceof AST_ForIn && p.init === node) { + if (seq == null) return node.definitions[0].name; + return seq; + } + if (p instanceof AST_For && p.init === node) { + return seq; + } + if (!seq) return make_node(AST_EmptyStatement, node); + return make_node(AST_SimpleStatement, node, { + body: seq + }); + } + if (node instanceof AST_Scope) + return node; // to avoid descending in nested scopes + } + } + ); + self = self.transform(tt); + if (vars_found > 0) { + // collect only vars which don't show up in self's arguments list + var defs = []; + vars.each(function(def, name){ + if (self instanceof AST_Lambda + && find_if(function(x){ return x.name == def.name.name }, + self.argnames)) { + vars.del(name); + } else { + def = def.clone(); + def.value = null; + defs.push(def); + vars.set(name, def); + } + }); + if (defs.length > 0) { + // try to merge in assignments + for (var i = 0; i < self.body.length;) { + if (self.body[i] instanceof AST_SimpleStatement) { + var expr = self.body[i].body, sym, assign; + if (expr instanceof AST_Assign + && expr.operator == "=" + && (sym = expr.left) instanceof AST_Symbol + && vars.has(sym.name)) + { + var def = vars.get(sym.name); + if (def.value) break; + def.value = expr.right; + remove(defs, def); + defs.push(def); + self.body.splice(i, 1); + continue; + } + if (expr instanceof AST_Seq + && (assign = expr.car) instanceof AST_Assign + && assign.operator == "=" + && (sym = assign.left) instanceof AST_Symbol + && vars.has(sym.name)) + { + var def = vars.get(sym.name); + if (def.value) break; + def.value = assign.right; + remove(defs, def); + defs.push(def); + self.body[i].body = expr.cdr; + continue; + } + } + if (self.body[i] instanceof AST_EmptyStatement) { + self.body.splice(i, 1); + continue; + } + if (self.body[i] instanceof AST_BlockStatement) { + var tmp = [ i, 1 ].concat(self.body[i].body); + self.body.splice.apply(self.body, tmp); + continue; + } + break; + } + defs = make_node(AST_Var, self, { + definitions: defs + }); + hoisted.push(defs); + }; + } + self.body = dirs.concat(hoisted, self.body); + } + return self; + }); + + OPT(AST_SimpleStatement, function(self, compressor){ + if (compressor.option("side_effects")) { + if (!self.body.has_side_effects(compressor)) { + compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start); + return make_node(AST_EmptyStatement, self); + } + } + return self; + }); + + OPT(AST_DWLoop, function(self, compressor){ + var cond = self.condition.evaluate(compressor); + self.condition = cond[0]; + if (!compressor.option("loops")) return self; + if (cond.length > 1) { + if (cond[1]) { + return make_node(AST_For, self, { + body: self.body + }); + } else if (self instanceof AST_While) { + if (compressor.option("dead_code")) { + var a = []; + extract_declarations_from_unreachable_code(compressor, self.body, a); + return make_node(AST_BlockStatement, self, { body: a }); + } + } + } + return self; + }); + + function if_break_in_loop(self, compressor) { + function drop_it(rest) { + rest = as_statement_array(rest); + if (self.body instanceof AST_BlockStatement) { + self.body = self.body.clone(); + self.body.body = rest.concat(self.body.body.slice(1)); + self.body = self.body.transform(compressor); + } else { + self.body = make_node(AST_BlockStatement, self.body, { + body: rest + }).transform(compressor); + } + if_break_in_loop(self, compressor); + } + var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body; + if (first instanceof AST_If) { + if (first.body instanceof AST_Break + && compressor.loopcontrol_target(first.body.label) === self) { + if (self.condition) { + self.condition = make_node(AST_Binary, self.condition, { + left: self.condition, + operator: "&&", + right: first.condition.negate(compressor), + }); + } else { + self.condition = first.condition.negate(compressor); + } + drop_it(first.alternative); + } + else if (first.alternative instanceof AST_Break + && compressor.loopcontrol_target(first.alternative.label) === self) { + if (self.condition) { + self.condition = make_node(AST_Binary, self.condition, { + left: self.condition, + operator: "&&", + right: first.condition, + }); + } else { + self.condition = first.condition; + } + drop_it(first.body); + } + } + }; + + OPT(AST_While, function(self, compressor) { + if (!compressor.option("loops")) return self; + self = AST_DWLoop.prototype.optimize.call(self, compressor); + if (self instanceof AST_While) { + if_break_in_loop(self, compressor); + self = make_node(AST_For, self, self).transform(compressor); + } + return self; + }); + + OPT(AST_For, function(self, compressor){ + var cond = self.condition; + if (cond) { + cond = cond.evaluate(compressor); + self.condition = cond[0]; + } + if (!compressor.option("loops")) return self; + if (cond) { + if (cond.length > 1 && !cond[1]) { + if (compressor.option("dead_code")) { + var a = []; + if (self.init instanceof AST_Statement) { + a.push(self.init); + } + else if (self.init) { + a.push(make_node(AST_SimpleStatement, self.init, { + body: self.init + })); + } + extract_declarations_from_unreachable_code(compressor, self.body, a); + return make_node(AST_BlockStatement, self, { body: a }); + } + } + } + if_break_in_loop(self, compressor); + return self; + }); + + OPT(AST_If, function(self, compressor){ + if (!compressor.option("conditionals")) return self; + // if condition can be statically determined, warn and drop + // one of the blocks. note, statically determined implies + // “has no side effects”; also it doesn't work for cases like + // `x && true`, though it probably should. + var cond = self.condition.evaluate(compressor); + self.condition = cond[0]; + if (cond.length > 1) { + if (cond[1]) { + compressor.warn("Condition always true [{file}:{line},{col}]", self.condition.start); + if (compressor.option("dead_code")) { + var a = []; + if (self.alternative) { + extract_declarations_from_unreachable_code(compressor, self.alternative, a); + } + a.push(self.body); + return make_node(AST_BlockStatement, self, { body: a }).transform(compressor); + } + } else { + compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start); + if (compressor.option("dead_code")) { + var a = []; + extract_declarations_from_unreachable_code(compressor, self.body, a); + if (self.alternative) a.push(self.alternative); + return make_node(AST_BlockStatement, self, { body: a }).transform(compressor); + } + } + } + if (is_empty(self.alternative)) self.alternative = null; + var negated = self.condition.negate(compressor); + var negated_is_best = best_of(self.condition, negated) === negated; + if (self.alternative && negated_is_best) { + negated_is_best = false; // because we already do the switch here. + self.condition = negated; + var tmp = self.body; + self.body = self.alternative || make_node(AST_EmptyStatement); + self.alternative = tmp; + } + if (is_empty(self.body) && is_empty(self.alternative)) { + return make_node(AST_SimpleStatement, self.condition, { + body: self.condition + }).transform(compressor); + } + if (self.body instanceof AST_SimpleStatement + && self.alternative instanceof AST_SimpleStatement) { + return make_node(AST_SimpleStatement, self, { + body: make_node(AST_Conditional, self, { + condition : self.condition, + consequent : self.body.body, + alternative : self.alternative.body + }) + }).transform(compressor); + } + if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) { + if (negated_is_best) return make_node(AST_SimpleStatement, self, { + body: make_node(AST_Binary, self, { + operator : "||", + left : negated, + right : self.body.body + }) + }).transform(compressor); + return make_node(AST_SimpleStatement, self, { + body: make_node(AST_Binary, self, { + operator : "&&", + left : self.condition, + right : self.body.body + }) + }).transform(compressor); + } + if (self.body instanceof AST_EmptyStatement + && self.alternative + && self.alternative instanceof AST_SimpleStatement) { + return make_node(AST_SimpleStatement, self, { + body: make_node(AST_Binary, self, { + operator : "||", + left : self.condition, + right : self.alternative.body + }) + }).transform(compressor); + } + if (self.body instanceof AST_Exit + && self.alternative instanceof AST_Exit + && self.body.TYPE == self.alternative.TYPE) { + return make_node(self.body.CTOR, self, { + value: make_node(AST_Conditional, self, { + condition : self.condition, + consequent : self.body.value || make_node(AST_Undefined, self.body).optimize(compressor), + alternative : self.alternative.value || make_node(AST_Undefined, self.alternative).optimize(compressor) + }) + }).transform(compressor); + } + if (self.body instanceof AST_If + && !self.body.alternative + && !self.alternative) { + self.condition = make_node(AST_Binary, self.condition, { + operator: "&&", + left: self.condition, + right: self.body.condition + }).transform(compressor); + self.body = self.body.body; + } + if (aborts(self.body)) { + if (self.alternative) { + var alt = self.alternative; + self.alternative = null; + return make_node(AST_BlockStatement, self, { + body: [ self, alt ] + }).transform(compressor); + } + } + if (aborts(self.alternative)) { + var body = self.body; + self.body = self.alternative; + self.condition = negated_is_best ? negated : self.condition.negate(compressor); + self.alternative = null; + return make_node(AST_BlockStatement, self, { + body: [ self, body ] + }).transform(compressor); + } + return self; + }); + + OPT(AST_Switch, function(self, compressor){ + if (self.body.length == 0 && compressor.option("conditionals")) { + return make_node(AST_SimpleStatement, self, { + body: self.expression + }).transform(compressor); + } + for(;;) { + var last_branch = self.body[self.body.length - 1]; + if (last_branch) { + var stat = last_branch.body[last_branch.body.length - 1]; // last statement + if (stat instanceof AST_Break && loop_body(compressor.loopcontrol_target(stat.label)) === self) + last_branch.body.pop(); + if (last_branch instanceof AST_Default && last_branch.body.length == 0) { + self.body.pop(); + continue; + } + } + break; + } + var exp = self.expression.evaluate(compressor); + out: if (exp.length == 2) try { + // constant expression + self.expression = exp[0]; + if (!compressor.option("dead_code")) break out; + var value = exp[1]; + var in_if = false; + var in_block = false; + var started = false; + var stopped = false; + var ruined = false; + var tt = new TreeTransformer(function(node, descend, in_list){ + if (node instanceof AST_Lambda || node instanceof AST_SimpleStatement) { + // no need to descend these node types + return node; + } + else if (node instanceof AST_Switch && node === self) { + node = node.clone(); + descend(node, this); + return ruined ? node : make_node(AST_BlockStatement, node, { + body: node.body.reduce(function(a, branch){ + return a.concat(branch.body); + }, []) + }).transform(compressor); + } + else if (node instanceof AST_If || node instanceof AST_Try) { + var save = in_if; + in_if = !in_block; + descend(node, this); + in_if = save; + return node; + } + else if (node instanceof AST_StatementWithBody || node instanceof AST_Switch) { + var save = in_block; + in_block = true; + descend(node, this); + in_block = save; + return node; + } + else if (node instanceof AST_Break && this.loopcontrol_target(node.label) === self) { + if (in_if) { + ruined = true; + return node; + } + if (in_block) return node; + stopped = true; + return in_list ? MAP.skip : make_node(AST_EmptyStatement, node); + } + else if (node instanceof AST_SwitchBranch && this.parent() === self) { + if (stopped) return MAP.skip; + if (node instanceof AST_Case) { + var exp = node.expression.evaluate(compressor); + if (exp.length < 2) { + // got a case with non-constant expression, baling out + throw self; + } + if (exp[1] === value || started) { + started = true; + if (aborts(node)) stopped = true; + descend(node, this); + return node; + } + return MAP.skip; + } + descend(node, this); + return node; + } + }); + tt.stack = compressor.stack.slice(); // so that's able to see parent nodes + self = self.transform(tt); + } catch(ex) { + if (ex !== self) throw ex; + } + return self; + }); + + OPT(AST_Case, function(self, compressor){ + self.body = tighten_body(self.body, compressor); + return self; + }); + + OPT(AST_Try, function(self, compressor){ + self.body = tighten_body(self.body, compressor); + return self; + }); + + AST_Definitions.DEFMETHOD("remove_initializers", function(){ + this.definitions.forEach(function(def){ def.value = null }); + }); + + AST_Definitions.DEFMETHOD("to_assignments", function(){ + var assignments = this.definitions.reduce(function(a, def){ + if (def.value) { + var name = make_node(AST_SymbolRef, def.name, def.name); + a.push(make_node(AST_Assign, def, { + operator : "=", + left : name, + right : def.value + })); + } + return a; + }, []); + if (assignments.length == 0) return null; + return AST_Seq.from_array(assignments); + }); + + OPT(AST_Definitions, function(self, compressor){ + if (self.definitions.length == 0) + return make_node(AST_EmptyStatement, self); + return self; + }); + + OPT(AST_Function, function(self, compressor){ + self = AST_Lambda.prototype.optimize.call(self, compressor); + if (compressor.option("unused")) { + if (self.name && self.name.unreferenced()) { + self.name = null; + } + } + return self; + }); + + OPT(AST_Call, function(self, compressor){ + if (compressor.option("unsafe")) { + var exp = self.expression; + if (exp instanceof AST_SymbolRef && exp.undeclared()) { + switch (exp.name) { + case "Array": + if (self.args.length != 1) { + return make_node(AST_Array, self, { + elements: self.args + }).transform(compressor); + } + break; + case "Object": + if (self.args.length == 0) { + return make_node(AST_Object, self, { + properties: [] + }); + } + break; + case "String": + if (self.args.length == 0) return make_node(AST_String, self, { + value: "" + }); + if (self.args.length <= 1) return make_node(AST_Binary, self, { + left: self.args[0], + operator: "+", + right: make_node(AST_String, self, { value: "" }) + }).transform(compressor); + break; + case "Number": + if (self.args.length == 0) return make_node(AST_Number, self, { + value: 0 + }); + if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, { + expression: self.args[0], + operator: "+" + }).transform(compressor); + case "Boolean": + if (self.args.length == 0) return make_node(AST_False, self); + if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, { + expression: make_node(AST_UnaryPrefix, null, { + expression: self.args[0], + operator: "!" + }), + operator: "!" + }).transform(compressor); + break; + case "Function": + if (all(self.args, function(x){ return x instanceof AST_String })) { + // quite a corner-case, but we can handle it: + // https://github.com/mishoo/UglifyJS2/issues/203 + // if the code argument is a constant, then we can minify it. + try { + var code = "(function(" + self.args.slice(0, -1).map(function(arg){ + return arg.value; + }).join(",") + "){" + self.args[self.args.length - 1].value + "})()"; + var ast = parse(code); + ast.figure_out_scope(); + var comp = new Compressor(compressor.options); + ast = ast.transform(comp); + ast.figure_out_scope(); + ast.mangle_names(); + var fun; + try { + ast.walk(new TreeWalker(function(node){ + if (node instanceof AST_Lambda) { + fun = node; + throw ast; + } + })); + } catch(ex) { + if (ex !== ast) throw ex; + }; + var args = fun.argnames.map(function(arg, i){ + return make_node(AST_String, self.args[i], { + value: arg.print_to_string() + }); + }); + var code = OutputStream(); + AST_BlockStatement.prototype._codegen.call(fun, fun, code); + code = code.toString().replace(/^\{|\}$/g, ""); + args.push(make_node(AST_String, self.args[self.args.length - 1], { + value: code + })); + self.args = args; + return self; + } catch(ex) { + if (ex instanceof JS_Parse_Error) { + compressor.warn("Error parsing code passed to new Function [{file}:{line},{col}]", self.args[self.args.length - 1].start); + compressor.warn(ex.toString()); + } else { + console.log(ex); + throw ex; + } + } + } + break; + } + } + else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) { + return make_node(AST_Binary, self, { + left: make_node(AST_String, self, { value: "" }), + operator: "+", + right: exp.expression + }).transform(compressor); + } + else if (exp instanceof AST_Dot && exp.expression instanceof AST_Array && exp.property == "join") EXIT: { + var separator = self.args.length == 0 ? "," : self.args[0].evaluate(compressor)[1]; + if (separator == null) break EXIT; // not a constant + var elements = exp.expression.elements.reduce(function(a, el){ + el = el.evaluate(compressor); + if (a.length == 0 || el.length == 1) { + a.push(el); + } else { + var last = a[a.length - 1]; + if (last.length == 2) { + // it's a constant + var val = "" + last[1] + separator + el[1]; + a[a.length - 1] = [ make_node_from_constant(compressor, val, last[0]), val ]; + } else { + a.push(el); + } + } + return a; + }, []); + if (elements.length == 0) return make_node(AST_String, self, { value: "" }); + if (elements.length == 1) return elements[0][0]; + if (separator == "") { + var first; + if (elements[0][0] instanceof AST_String + || elements[1][0] instanceof AST_String) { + first = elements.shift()[0]; + } else { + first = make_node(AST_String, self, { value: "" }); + } + return elements.reduce(function(prev, el){ + return make_node(AST_Binary, el[0], { + operator : "+", + left : prev, + right : el[0], + }); + }, first).transform(compressor); + } + // need this awkward cloning to not affect original element + // best_of will decide which one to get through. + var node = self.clone(); + node.expression = node.expression.clone(); + node.expression.expression = node.expression.expression.clone(); + node.expression.expression.elements = elements.map(function(el){ + return el[0]; + }); + return best_of(self, node); + } + } + if (compressor.option("side_effects")) { + if (self.expression instanceof AST_Function + && self.args.length == 0 + && !AST_Block.prototype.has_side_effects.call(self.expression, compressor)) { + return make_node(AST_Undefined, self).transform(compressor); + } + } + return self.evaluate(compressor)[0]; + }); + + OPT(AST_New, function(self, compressor){ + if (compressor.option("unsafe")) { + var exp = self.expression; + if (exp instanceof AST_SymbolRef && exp.undeclared()) { + switch (exp.name) { + case "Object": + case "RegExp": + case "Function": + case "Error": + case "Array": + return make_node(AST_Call, self, self).transform(compressor); + } + } + } + return self; + }); + + OPT(AST_Seq, function(self, compressor){ + if (!compressor.option("side_effects")) + return self; + if (!self.car.has_side_effects(compressor)) { + // we shouldn't compress (1,eval)(something) to + // eval(something) because that changes the meaning of + // eval (becomes lexical instead of global). + var p; + if (!(self.cdr instanceof AST_SymbolRef + && self.cdr.name == "eval" + && self.cdr.undeclared() + && (p = compressor.parent()) instanceof AST_Call + && p.expression === self)) { + return self.cdr; + } + } + if (compressor.option("cascade")) { + if (self.car instanceof AST_Assign + && !self.car.left.has_side_effects(compressor) + && self.car.left.equivalent_to(self.cdr)) { + return self.car; + } + if (!self.car.has_side_effects(compressor) + && !self.cdr.has_side_effects(compressor) + && self.car.equivalent_to(self.cdr)) { + return self.car; + } + } + return self; + }); + + AST_Unary.DEFMETHOD("lift_sequences", function(compressor){ + if (compressor.option("sequences")) { + if (this.expression instanceof AST_Seq) { + var seq = this.expression; + var x = seq.to_array(); + this.expression = x.pop(); + x.push(this); + seq = AST_Seq.from_array(x).transform(compressor); + return seq; + } + } + return this; + }); + + OPT(AST_UnaryPostfix, function(self, compressor){ + return self.lift_sequences(compressor); + }); + + OPT(AST_UnaryPrefix, function(self, compressor){ + self = self.lift_sequences(compressor); + var e = self.expression; + if (compressor.option("booleans") && compressor.in_boolean_context()) { + switch (self.operator) { + case "!": + if (e instanceof AST_UnaryPrefix && e.operator == "!") { + // !!foo ==> foo, if we're in boolean context + return e.expression; + } + break; + case "typeof": + // typeof always returns a non-empty string, thus it's + // always true in booleans + compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start); + return make_node(AST_True, self); + } + if (e instanceof AST_Binary && self.operator == "!") { + self = best_of(self, e.negate(compressor)); + } + } + return self.evaluate(compressor)[0]; + }); + + function has_side_effects_or_prop_access(node, compressor) { + var save_pure_getters = compressor.option("pure_getters"); + compressor.options.pure_getters = false; + var ret = node.has_side_effects(compressor); + compressor.options.pure_getters = save_pure_getters; + return ret; + } + + AST_Binary.DEFMETHOD("lift_sequences", function(compressor){ + if (compressor.option("sequences")) { + if (this.left instanceof AST_Seq) { + var seq = this.left; + var x = seq.to_array(); + this.left = x.pop(); + x.push(this); + seq = AST_Seq.from_array(x).transform(compressor); + return seq; + } + if (this.right instanceof AST_Seq + && this instanceof AST_Assign + && !has_side_effects_or_prop_access(this.left, compressor)) { + var seq = this.right; + var x = seq.to_array(); + this.right = x.pop(); + x.push(this); + seq = AST_Seq.from_array(x).transform(compressor); + return seq; + } + } + return this; + }); + + var commutativeOperators = makePredicate("== === != !== * & | ^"); + + OPT(AST_Binary, function(self, compressor){ + var reverse = compressor.has_directive("use asm") ? noop + : function(op, force) { + if (force || !(self.left.has_side_effects(compressor) || self.right.has_side_effects(compressor))) { + if (op) self.operator = op; + var tmp = self.left; + self.left = self.right; + self.right = tmp; + } + }; + if (commutativeOperators(self.operator)) { + if (self.right instanceof AST_Constant + && !(self.left instanceof AST_Constant)) { + // if right is a constant, whatever side effects the + // left side might have could not influence the + // result. hence, force switch. + + if (!(self.left instanceof AST_Binary + && PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) { + reverse(null, true); + } + } + if (/^[!=]==?$/.test(self.operator)) { + if (self.left instanceof AST_SymbolRef && self.right instanceof AST_Conditional) { + if (self.right.consequent instanceof AST_SymbolRef + && self.right.consequent.definition() === self.left.definition()) { + if (/^==/.test(self.operator)) return self.right.condition; + if (/^!=/.test(self.operator)) return self.right.condition.negate(compressor); + } + if (self.right.alternative instanceof AST_SymbolRef + && self.right.alternative.definition() === self.left.definition()) { + if (/^==/.test(self.operator)) return self.right.condition.negate(compressor); + if (/^!=/.test(self.operator)) return self.right.condition; + } + } + if (self.right instanceof AST_SymbolRef && self.left instanceof AST_Conditional) { + if (self.left.consequent instanceof AST_SymbolRef + && self.left.consequent.definition() === self.right.definition()) { + if (/^==/.test(self.operator)) return self.left.condition; + if (/^!=/.test(self.operator)) return self.left.condition.negate(compressor); + } + if (self.left.alternative instanceof AST_SymbolRef + && self.left.alternative.definition() === self.right.definition()) { + if (/^==/.test(self.operator)) return self.left.condition.negate(compressor); + if (/^!=/.test(self.operator)) return self.left.condition; + } + } + } + } + self = self.lift_sequences(compressor); + if (compressor.option("comparisons")) switch (self.operator) { + case "===": + case "!==": + if ((self.left.is_string(compressor) && self.right.is_string(compressor)) || + (self.left.is_boolean() && self.right.is_boolean())) { + self.operator = self.operator.substr(0, 2); + } + // XXX: intentionally falling down to the next case + case "==": + case "!=": + if (self.left instanceof AST_String + && self.left.value == "undefined" + && self.right instanceof AST_UnaryPrefix + && self.right.operator == "typeof" + && compressor.option("unsafe")) { + if (!(self.right.expression instanceof AST_SymbolRef) + || !self.right.expression.undeclared()) { + self.right = self.right.expression; + self.left = make_node(AST_Undefined, self.left).optimize(compressor); + if (self.operator.length == 2) self.operator += "="; + } + } + break; + } + if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) { + case "&&": + var ll = self.left.evaluate(compressor); + var rr = self.right.evaluate(compressor); + if ((ll.length > 1 && !ll[1]) || (rr.length > 1 && !rr[1])) { + compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start); + return make_node(AST_False, self); + } + if (ll.length > 1 && ll[1]) { + return rr[0]; + } + if (rr.length > 1 && rr[1]) { + return ll[0]; + } + break; + case "||": + var ll = self.left.evaluate(compressor); + var rr = self.right.evaluate(compressor); + if ((ll.length > 1 && ll[1]) || (rr.length > 1 && rr[1])) { + compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start); + return make_node(AST_True, self); + } + if (ll.length > 1 && !ll[1]) { + return rr[0]; + } + if (rr.length > 1 && !rr[1]) { + return ll[0]; + } + break; + case "+": + var ll = self.left.evaluate(compressor); + var rr = self.right.evaluate(compressor); + if ((ll.length > 1 && ll[0] instanceof AST_String && ll[1]) || + (rr.length > 1 && rr[0] instanceof AST_String && rr[1])) { + compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start); + return make_node(AST_True, self); + } + break; + } + if (compressor.option("comparisons")) { + if (!(compressor.parent() instanceof AST_Binary) + || compressor.parent() instanceof AST_Assign) { + var negated = make_node(AST_UnaryPrefix, self, { + operator: "!", + expression: self.negate(compressor) + }); + self = best_of(self, negated); + } + switch (self.operator) { + case "<": reverse(">"); break; + case "<=": reverse(">="); break; + } + } + if (self.operator == "+" && self.right instanceof AST_String + && self.right.getValue() === "" && self.left instanceof AST_Binary + && self.left.operator == "+" && self.left.is_string(compressor)) { + return self.left; + } else if (self.operator == "+" && self.right instanceof AST_String + && self.right.getValue() === "" && self.left instanceof AST_Binary + && self.left.operator == "+" && self.left.right instanceof AST_Number) { + return make_node(AST_Binary, self, { + left: self.left.left, + operator: "+", + right: make_node(AST_String, self.right, { + value: String(self.left.right.value) + }) + }); + } + if (compressor.option("evaluate")) { + if (self.operator == "+") { + if (self.left instanceof AST_Constant + && self.right instanceof AST_Binary + && self.right.operator == "+" + && self.right.left instanceof AST_Constant + && self.right.is_string(compressor)) { + self = make_node(AST_Binary, self, { + operator: "+", + left: make_node(AST_String, null, { + value: "" + self.left.getValue() + self.right.left.getValue(), + start: self.left.start, + end: self.right.left.end + }), + right: self.right.right + }); + } + if (self.right instanceof AST_Constant + && self.left instanceof AST_Binary + && self.left.operator == "+" + && self.left.right instanceof AST_Constant + && self.left.is_string(compressor)) { + self = make_node(AST_Binary, self, { + operator: "+", + left: self.left.left, + right: make_node(AST_String, null, { + value: "" + self.left.right.getValue() + self.right.getValue(), + start: self.left.right.start, + end: self.right.end + }) + }); + } + if (self.left instanceof AST_Binary + && self.left.operator == "+" + && self.left.is_string(compressor) + && self.left.right instanceof AST_Constant + && self.right instanceof AST_Binary + && self.right.operator == "+" + && self.right.left instanceof AST_Constant + && self.right.is_string(compressor)) { + self = make_node(AST_Binary, self, { + operator: "+", + left: make_node(AST_Binary, self.left, { + operator: "+", + left: self.left.left, + right: make_node(AST_String, null, { + value: "" + self.left.right.getValue() + self.right.left.getValue(), + start: self.left.right.start, + end: self.right.left.end + }) + }), + right: self.right.right + }); + } + } + } + // x * (y * z) ==> x * y * z + if (self.right instanceof AST_Binary + && self.right.operator == self.operator + && (self.operator == "*" || self.operator == "&&" || self.operator == "||")) + { + self.left = make_node(AST_Binary, self.left, { + operator : self.operator, + left : self.left, + right : self.right.left + }); + self.right = self.right.right; + return self.transform(compressor); + } + return self.evaluate(compressor)[0]; + }); + + OPT(AST_SymbolRef, function(self, compressor){ + if (self.undeclared()) { + var defines = compressor.option("global_defs"); + if (defines && defines.hasOwnProperty(self.name)) { + return make_node_from_constant(compressor, defines[self.name], self); + } + switch (self.name) { + case "undefined": + return make_node(AST_Undefined, self); + case "NaN": + return make_node(AST_NaN, self); + case "Infinity": + return make_node(AST_Infinity, self); + } + } + return self; + }); + + OPT(AST_Undefined, function(self, compressor){ + if (compressor.option("unsafe")) { + var scope = compressor.find_parent(AST_Scope); + var undef = scope.find_variable("undefined"); + if (undef) { + var ref = make_node(AST_SymbolRef, self, { + name : "undefined", + scope : scope, + thedef : undef + }); + ref.reference(); + return ref; + } + } + return self; + }); + + var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ]; + OPT(AST_Assign, function(self, compressor){ + self = self.lift_sequences(compressor); + if (self.operator == "=" + && self.left instanceof AST_SymbolRef + && self.right instanceof AST_Binary + && self.right.left instanceof AST_SymbolRef + && self.right.left.name == self.left.name + && member(self.right.operator, ASSIGN_OPS)) { + self.operator = self.right.operator + "="; + self.right = self.right.right; + } + return self; + }); + + OPT(AST_Conditional, function(self, compressor){ + if (!compressor.option("conditionals")) return self; + if (self.condition instanceof AST_Seq) { + var car = self.condition.car; + self.condition = self.condition.cdr; + return AST_Seq.cons(car, self); + } + var cond = self.condition.evaluate(compressor); + if (cond.length > 1) { + if (cond[1]) { + compressor.warn("Condition always true [{file}:{line},{col}]", self.start); + return self.consequent; + } else { + compressor.warn("Condition always false [{file}:{line},{col}]", self.start); + return self.alternative; + } + } + var negated = cond[0].negate(compressor); + if (best_of(cond[0], negated) === negated) { + self = make_node(AST_Conditional, self, { + condition: negated, + consequent: self.alternative, + alternative: self.consequent + }); + } + var consequent = self.consequent; + var alternative = self.alternative; + if (consequent instanceof AST_Assign + && alternative instanceof AST_Assign + && consequent.operator == alternative.operator + && consequent.left.equivalent_to(alternative.left) + ) { + /* + * Stuff like this: + * if (foo) exp = something; else exp = something_else; + * ==> + * exp = foo ? something : something_else; + */ + self = make_node(AST_Assign, self, { + operator: consequent.operator, + left: consequent.left, + right: make_node(AST_Conditional, self, { + condition: self.condition, + consequent: consequent.right, + alternative: alternative.right + }) + }); + } + return self; + }); + + OPT(AST_Boolean, function(self, compressor){ + if (compressor.option("booleans")) { + var p = compressor.parent(); + if (p instanceof AST_Binary && (p.operator == "==" + || p.operator == "!=")) { + compressor.warn("Non-strict equality against boolean: {operator} {value} [{file}:{line},{col}]", { + operator : p.operator, + value : self.value, + file : p.start.file, + line : p.start.line, + col : p.start.col, + }); + return make_node(AST_Number, self, { + value: +self.value + }); + } + return make_node(AST_UnaryPrefix, self, { + operator: "!", + expression: make_node(AST_Number, self, { + value: 1 - self.value + }) + }); + } + return self; + }); + + OPT(AST_Sub, function(self, compressor){ + var prop = self.property; + if (prop instanceof AST_String && compressor.option("properties")) { + prop = prop.getValue(); + if (RESERVED_WORDS(prop) ? compressor.option("screw_ie8") : is_identifier_string(prop)) { + return make_node(AST_Dot, self, { + expression : self.expression, + property : prop + }); + } + } + return self; + }); + + function literals_in_boolean_context(self, compressor) { + if (compressor.option("booleans") && compressor.in_boolean_context()) { + return make_node(AST_True, self); + } + return self; + }; + OPT(AST_Array, literals_in_boolean_context); + OPT(AST_Object, literals_in_boolean_context); + OPT(AST_RegExp, literals_in_boolean_context); + +})(); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/mozilla-ast.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/mozilla-ast.js new file mode 100644 index 0000000..d795094 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/mozilla-ast.js @@ -0,0 +1,267 @@ +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + 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. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 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. + + ***********************************************************************/ + +"use strict"; + +(function(){ + + var MOZ_TO_ME = { + TryStatement : function(M) { + return new AST_Try({ + start : my_start_token(M), + end : my_end_token(M), + body : from_moz(M.block).body, + bcatch : from_moz(M.handlers[0]), + bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null + }); + }, + CatchClause : function(M) { + return new AST_Catch({ + start : my_start_token(M), + end : my_end_token(M), + argname : from_moz(M.param), + body : from_moz(M.body).body + }); + }, + ObjectExpression : function(M) { + return new AST_Object({ + start : my_start_token(M), + end : my_end_token(M), + properties : M.properties.map(function(prop){ + var key = prop.key; + var name = key.type == "Identifier" ? key.name : key.value; + var args = { + start : my_start_token(key), + end : my_end_token(prop.value), + key : name, + value : from_moz(prop.value) + }; + switch (prop.kind) { + case "init": + return new AST_ObjectKeyVal(args); + case "set": + args.value.name = from_moz(key); + return new AST_ObjectSetter(args); + case "get": + args.value.name = from_moz(key); + return new AST_ObjectGetter(args); + } + }) + }); + }, + SequenceExpression : function(M) { + return AST_Seq.from_array(M.expressions.map(from_moz)); + }, + MemberExpression : function(M) { + return new (M.computed ? AST_Sub : AST_Dot)({ + start : my_start_token(M), + end : my_end_token(M), + property : M.computed ? from_moz(M.property) : M.property.name, + expression : from_moz(M.object) + }); + }, + SwitchCase : function(M) { + return new (M.test ? AST_Case : AST_Default)({ + start : my_start_token(M), + end : my_end_token(M), + expression : from_moz(M.test), + body : M.consequent.map(from_moz) + }); + }, + Literal : function(M) { + var val = M.value, args = { + start : my_start_token(M), + end : my_end_token(M) + }; + if (val === null) return new AST_Null(args); + switch (typeof val) { + case "string": + args.value = val; + return new AST_String(args); + case "number": + args.value = val; + return new AST_Number(args); + case "boolean": + return new (val ? AST_True : AST_False)(args); + default: + args.value = val; + return new AST_RegExp(args); + } + }, + UnaryExpression: From_Moz_Unary, + UpdateExpression: From_Moz_Unary, + Identifier: function(M) { + var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2]; + return new (M.name == "this" ? AST_This + : p.type == "LabeledStatement" ? AST_Label + : p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : AST_SymbolVar) + : p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg) + : p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg) + : p.type == "CatchClause" ? AST_SymbolCatch + : p.type == "BreakStatement" || p.type == "ContinueStatement" ? AST_LabelRef + : AST_SymbolRef)({ + start : my_start_token(M), + end : my_end_token(M), + name : M.name + }); + } + }; + + function From_Moz_Unary(M) { + var prefix = "prefix" in M ? M.prefix + : M.type == "UnaryExpression" ? true : false; + return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({ + start : my_start_token(M), + end : my_end_token(M), + operator : M.operator, + expression : from_moz(M.argument) + }); + }; + + var ME_TO_MOZ = {}; + + map("Node", AST_Node); + map("Program", AST_Toplevel, "body@body"); + map("Function", AST_Function, "id>name, params@argnames, body%body"); + map("EmptyStatement", AST_EmptyStatement); + map("BlockStatement", AST_BlockStatement, "body@body"); + map("ExpressionStatement", AST_SimpleStatement, "expression>body"); + map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative"); + map("LabeledStatement", AST_LabeledStatement, "label>label, body>body"); + map("BreakStatement", AST_Break, "label>label"); + map("ContinueStatement", AST_Continue, "label>label"); + map("WithStatement", AST_With, "object>expression, body>body"); + map("SwitchStatement", AST_Switch, "discriminant>expression, cases@body"); + map("ReturnStatement", AST_Return, "argument>value"); + map("ThrowStatement", AST_Throw, "argument>value"); + map("WhileStatement", AST_While, "test>condition, body>body"); + map("DoWhileStatement", AST_Do, "test>condition, body>body"); + map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body"); + map("ForInStatement", AST_ForIn, "left>init, right>object, body>body"); + map("DebuggerStatement", AST_Debugger); + map("FunctionDeclaration", AST_Defun, "id>name, params@argnames, body%body"); + map("VariableDeclaration", AST_Var, "declarations@definitions"); + map("VariableDeclarator", AST_VarDef, "id>name, init>value"); + + map("ThisExpression", AST_This); + map("ArrayExpression", AST_Array, "elements@elements"); + map("FunctionExpression", AST_Function, "id>name, params@argnames, body%body"); + map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right"); + map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right"); + map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right"); + map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative"); + map("NewExpression", AST_New, "callee>expression, arguments@args"); + map("CallExpression", AST_Call, "callee>expression, arguments@args"); + + /* -----[ tools ]----- */ + + function my_start_token(moznode) { + return new AST_Token({ + file : moznode.loc && moznode.loc.source, + line : moznode.loc && moznode.loc.start.line, + col : moznode.loc && moznode.loc.start.column, + pos : moznode.start, + endpos : moznode.start + }); + }; + + function my_end_token(moznode) { + return new AST_Token({ + file : moznode.loc && moznode.loc.source, + line : moznode.loc && moznode.loc.end.line, + col : moznode.loc && moznode.loc.end.column, + pos : moznode.end, + endpos : moznode.end + }); + }; + + function map(moztype, mytype, propmap) { + var moz_to_me = "function From_Moz_" + moztype + "(M){\n"; + moz_to_me += "return new mytype({\n" + + "start: my_start_token(M),\n" + + "end: my_end_token(M)"; + + if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop){ + var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop); + if (!m) throw new Error("Can't understand property map: " + prop); + var moz = "M." + m[1], how = m[2], my = m[3]; + moz_to_me += ",\n" + my + ": "; + if (how == "@") { + moz_to_me += moz + ".map(from_moz)"; + } else if (how == ">") { + moz_to_me += "from_moz(" + moz + ")"; + } else if (how == "=") { + moz_to_me += moz; + } else if (how == "%") { + moz_to_me += "from_moz(" + moz + ").body"; + } else throw new Error("Can't understand operator in propmap: " + prop); + }); + moz_to_me += "\n})}"; + + // moz_to_me = parse(moz_to_me).print_to_string({ beautify: true }); + // console.log(moz_to_me); + + moz_to_me = new Function("mytype", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")( + mytype, my_start_token, my_end_token, from_moz + ); + return MOZ_TO_ME[moztype] = moz_to_me; + }; + + var FROM_MOZ_STACK = null; + + function from_moz(node) { + FROM_MOZ_STACK.push(node); + var ret = node != null ? MOZ_TO_ME[node.type](node) : null; + FROM_MOZ_STACK.pop(); + return ret; + }; + + AST_Node.from_mozilla_ast = function(node){ + var save_stack = FROM_MOZ_STACK; + FROM_MOZ_STACK = []; + var ast = from_moz(node); + FROM_MOZ_STACK = save_stack; + return ast; + }; + +})(); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/output.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/output.js new file mode 100644 index 0000000..37e30c0 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/output.js @@ -0,0 +1,1255 @@ +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + 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. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 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. + + ***********************************************************************/ + +"use strict"; + +function OutputStream(options) { + + options = defaults(options, { + indent_start : 0, + indent_level : 4, + quote_keys : false, + space_colon : true, + ascii_only : false, + inline_script : false, + width : 80, + max_line_len : 32000, + beautify : false, + source_map : null, + bracketize : false, + semicolons : true, + comments : false, + preserve_line : false, + screw_ie8 : false, + preamble : null, + }, true); + + var indentation = 0; + var current_col = 0; + var current_line = 1; + var current_pos = 0; + var OUTPUT = ""; + + function to_ascii(str, identifier) { + return str.replace(/[\u0080-\uffff]/g, function(ch) { + var code = ch.charCodeAt(0).toString(16); + if (code.length <= 2 && !identifier) { + while (code.length < 2) code = "0" + code; + return "\\x" + code; + } else { + while (code.length < 4) code = "0" + code; + return "\\u" + code; + } + }); + }; + + function make_string(str) { + var dq = 0, sq = 0; + str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){ + switch (s) { + case "\\": return "\\\\"; + case "\b": return "\\b"; + case "\f": return "\\f"; + case "\n": return "\\n"; + case "\r": return "\\r"; + case "\u2028": return "\\u2028"; + case "\u2029": return "\\u2029"; + case '"': ++dq; return '"'; + case "'": ++sq; return "'"; + case "\0": return "\\x00"; + } + return s; + }); + if (options.ascii_only) str = to_ascii(str); + if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; + else return '"' + str.replace(/\x22/g, '\\"') + '"'; + }; + + function encode_string(str) { + var ret = make_string(str); + if (options.inline_script) + ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1"); + return ret; + }; + + function make_name(name) { + name = name.toString(); + if (options.ascii_only) + name = to_ascii(name, true); + return name; + }; + + function make_indent(back) { + return repeat_string(" ", options.indent_start + indentation - back * options.indent_level); + }; + + /* -----[ beautification/minification ]----- */ + + var might_need_space = false; + var might_need_semicolon = false; + var last = null; + + function last_char() { + return last.charAt(last.length - 1); + }; + + function maybe_newline() { + if (options.max_line_len && current_col > options.max_line_len) + print("\n"); + }; + + var requireSemicolonChars = makePredicate("( [ + * / - , ."); + + function print(str) { + str = String(str); + var ch = str.charAt(0); + if (might_need_semicolon) { + if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) { + if (options.semicolons || requireSemicolonChars(ch)) { + OUTPUT += ";"; + current_col++; + current_pos++; + } else { + OUTPUT += "\n"; + current_pos++; + current_line++; + current_col = 0; + } + if (!options.beautify) + might_need_space = false; + } + might_need_semicolon = false; + maybe_newline(); + } + + if (!options.beautify && options.preserve_line && stack[stack.length - 1]) { + var target_line = stack[stack.length - 1].start.line; + while (current_line < target_line) { + OUTPUT += "\n"; + current_pos++; + current_line++; + current_col = 0; + might_need_space = false; + } + } + + if (might_need_space) { + var prev = last_char(); + if ((is_identifier_char(prev) + && (is_identifier_char(ch) || ch == "\\")) + || (/^[\+\-\/]$/.test(ch) && ch == prev)) + { + OUTPUT += " "; + current_col++; + current_pos++; + } + might_need_space = false; + } + var a = str.split(/\r?\n/), n = a.length - 1; + current_line += n; + if (n == 0) { + current_col += a[n].length; + } else { + current_col = a[n].length; + } + current_pos += str.length; + last = str; + OUTPUT += str; + }; + + var space = options.beautify ? function() { + print(" "); + } : function() { + might_need_space = true; + }; + + var indent = options.beautify ? function(half) { + if (options.beautify) { + print(make_indent(half ? 0.5 : 0)); + } + } : noop; + + var with_indent = options.beautify ? function(col, cont) { + if (col === true) col = next_indent(); + var save_indentation = indentation; + indentation = col; + var ret = cont(); + indentation = save_indentation; + return ret; + } : function(col, cont) { return cont() }; + + var newline = options.beautify ? function() { + print("\n"); + } : noop; + + var semicolon = options.beautify ? function() { + print(";"); + } : function() { + might_need_semicolon = true; + }; + + function force_semicolon() { + might_need_semicolon = false; + print(";"); + }; + + function next_indent() { + return indentation + options.indent_level; + }; + + function with_block(cont) { + var ret; + print("{"); + newline(); + with_indent(next_indent(), function(){ + ret = cont(); + }); + indent(); + print("}"); + return ret; + }; + + function with_parens(cont) { + print("("); + //XXX: still nice to have that for argument lists + //var ret = with_indent(current_col, cont); + var ret = cont(); + print(")"); + return ret; + }; + + function with_square(cont) { + print("["); + //var ret = with_indent(current_col, cont); + var ret = cont(); + print("]"); + return ret; + }; + + function comma() { + print(","); + space(); + }; + + function colon() { + print(":"); + if (options.space_colon) space(); + }; + + var add_mapping = options.source_map ? function(token, name) { + try { + if (token) options.source_map.add( + token.file || "?", + current_line, current_col, + token.line, token.col, + (!name && token.type == "name") ? token.value : name + ); + } catch(ex) { + AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", { + file: token.file, + line: token.line, + col: token.col, + cline: current_line, + ccol: current_col, + name: name || "" + }) + } + } : noop; + + function get() { + return OUTPUT; + }; + + if (options.preamble) { + print(options.preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n")); + } + + var stack = []; + return { + get : get, + toString : get, + indent : indent, + indentation : function() { return indentation }, + current_width : function() { return current_col - indentation }, + should_break : function() { return options.width && this.current_width() >= options.width }, + newline : newline, + print : print, + space : space, + comma : comma, + colon : colon, + last : function() { return last }, + semicolon : semicolon, + force_semicolon : force_semicolon, + to_ascii : to_ascii, + print_name : function(name) { print(make_name(name)) }, + print_string : function(str) { print(encode_string(str)) }, + next_indent : next_indent, + with_indent : with_indent, + with_block : with_block, + with_parens : with_parens, + with_square : with_square, + add_mapping : add_mapping, + option : function(opt) { return options[opt] }, + line : function() { return current_line }, + col : function() { return current_col }, + pos : function() { return current_pos }, + push_node : function(node) { stack.push(node) }, + pop_node : function() { return stack.pop() }, + stack : function() { return stack }, + parent : function(n) { + return stack[stack.length - 2 - (n || 0)]; + } + }; + +}; + +/* -----[ code generators ]----- */ + +(function(){ + + /* -----[ utils ]----- */ + + function DEFPRINT(nodetype, generator) { + nodetype.DEFMETHOD("_codegen", generator); + }; + + AST_Node.DEFMETHOD("print", function(stream, force_parens){ + var self = this, generator = self._codegen; + function doit() { + self.add_comments(stream); + self.add_source_map(stream); + generator(self, stream); + } + stream.push_node(self); + if (force_parens || self.needs_parens(stream)) { + stream.with_parens(doit); + } else { + doit(); + } + stream.pop_node(); + }); + + AST_Node.DEFMETHOD("print_to_string", function(options){ + var s = OutputStream(options); + this.print(s); + return s.get(); + }); + + /* -----[ comments ]----- */ + + AST_Node.DEFMETHOD("add_comments", function(output){ + var c = output.option("comments"), self = this; + if (c) { + var start = self.start; + if (start && !start._comments_dumped) { + start._comments_dumped = true; + var comments = start.comments_before || []; + + // XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112 + // if this node is `return` or `throw`, we cannot allow comments before + // the returned or thrown value. + if (self instanceof AST_Exit && self.value + && self.value.start.comments_before + && self.value.start.comments_before.length > 0) { + comments = comments.concat(self.value.start.comments_before); + self.value.start.comments_before = []; + } + + if (c.test) { + comments = comments.filter(function(comment){ + return c.test(comment.value); + }); + } else if (typeof c == "function") { + comments = comments.filter(function(comment){ + return c(self, comment); + }); + } + comments.forEach(function(c){ + if (/comment[134]/.test(c.type)) { + output.print("//" + c.value + "\n"); + output.indent(); + } + else if (c.type == "comment2") { + output.print("/*" + c.value + "*/"); + if (start.nlb) { + output.print("\n"); + output.indent(); + } else { + output.space(); + } + } + }); + } + } + }); + + /* -----[ PARENTHESES ]----- */ + + function PARENS(nodetype, func) { + nodetype.DEFMETHOD("needs_parens", func); + }; + + PARENS(AST_Node, function(){ + return false; + }); + + // a function expression needs parens around it when it's provably + // the first token to appear in a statement. + PARENS(AST_Function, function(output){ + return first_in_statement(output); + }); + + // same goes for an object literal, because otherwise it would be + // interpreted as a block of code. + PARENS(AST_Object, function(output){ + return first_in_statement(output); + }); + + PARENS(AST_Unary, function(output){ + var p = output.parent(); + return p instanceof AST_PropAccess && p.expression === this; + }); + + PARENS(AST_Seq, function(output){ + var p = output.parent(); + return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4) + || p instanceof AST_Unary // !(foo, bar, baz) + || p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8 + || p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4 + || p instanceof AST_Dot // (1, {foo:2}).foo ==> 2 + || p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ] + || p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2 + || p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30) + * ==> 20 (side effect, set a := 10 and b := 20) */ + ; + }); + + PARENS(AST_Binary, function(output){ + var p = output.parent(); + // (foo && bar)() + if (p instanceof AST_Call && p.expression === this) + return true; + // typeof (foo && bar) + if (p instanceof AST_Unary) + return true; + // (foo && bar)["prop"], (foo && bar).prop + if (p instanceof AST_PropAccess && p.expression === this) + return true; + // this deals with precedence: 3 * (2 + 1) + if (p instanceof AST_Binary) { + var po = p.operator, pp = PRECEDENCE[po]; + var so = this.operator, sp = PRECEDENCE[so]; + if (pp > sp + || (pp == sp + && this === p.right)) { + return true; + } + } + }); + + PARENS(AST_PropAccess, function(output){ + var p = output.parent(); + if (p instanceof AST_New && p.expression === this) { + // i.e. new (foo.bar().baz) + // + // if there's one call into this subtree, then we need + // parens around it too, otherwise the call will be + // interpreted as passing the arguments to the upper New + // expression. + try { + this.walk(new TreeWalker(function(node){ + if (node instanceof AST_Call) throw p; + })); + } catch(ex) { + if (ex !== p) throw ex; + return true; + } + } + }); + + PARENS(AST_Call, function(output){ + var p = output.parent(), p1; + if (p instanceof AST_New && p.expression === this) + return true; + + // workaround for Safari bug. + // https://bugs.webkit.org/show_bug.cgi?id=123506 + return this.expression instanceof AST_Function + && p instanceof AST_PropAccess + && p.expression === this + && (p1 = output.parent(1)) instanceof AST_Assign + && p1.left === p; + }); + + PARENS(AST_New, function(output){ + var p = output.parent(); + if (no_constructor_parens(this, output) + && (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]() + || p instanceof AST_Call && p.expression === this)) // (new foo)(bar) + return true; + }); + + PARENS(AST_Number, function(output){ + var p = output.parent(); + if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this) + return true; + }); + + PARENS(AST_NaN, function(output){ + var p = output.parent(); + if (p instanceof AST_PropAccess && p.expression === this) + return true; + }); + + function assign_and_conditional_paren_rules(output) { + var p = output.parent(); + // !(a = false) → true + if (p instanceof AST_Unary) + return true; + // 1 + (a = 2) + 3 → 6, side effect setting a = 2 + if (p instanceof AST_Binary && !(p instanceof AST_Assign)) + return true; + // (a = func)() —or— new (a = Object)() + if (p instanceof AST_Call && p.expression === this) + return true; + // (a = foo) ? bar : baz + if (p instanceof AST_Conditional && p.condition === this) + return true; + // (a = foo)["prop"] —or— (a = foo).prop + if (p instanceof AST_PropAccess && p.expression === this) + return true; + }; + + PARENS(AST_Assign, assign_and_conditional_paren_rules); + PARENS(AST_Conditional, assign_and_conditional_paren_rules); + + /* -----[ PRINTERS ]----- */ + + DEFPRINT(AST_Directive, function(self, output){ + output.print_string(self.value); + output.semicolon(); + }); + DEFPRINT(AST_Debugger, function(self, output){ + output.print("debugger"); + output.semicolon(); + }); + + /* -----[ statements ]----- */ + + function display_body(body, is_toplevel, output) { + var last = body.length - 1; + body.forEach(function(stmt, i){ + if (!(stmt instanceof AST_EmptyStatement)) { + output.indent(); + stmt.print(output); + if (!(i == last && is_toplevel)) { + output.newline(); + if (is_toplevel) output.newline(); + } + } + }); + }; + + AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){ + force_statement(this.body, output); + }); + + DEFPRINT(AST_Statement, function(self, output){ + self.body.print(output); + output.semicolon(); + }); + DEFPRINT(AST_Toplevel, function(self, output){ + display_body(self.body, true, output); + output.print(""); + }); + DEFPRINT(AST_LabeledStatement, function(self, output){ + self.label.print(output); + output.colon(); + self.body.print(output); + }); + DEFPRINT(AST_SimpleStatement, function(self, output){ + self.body.print(output); + output.semicolon(); + }); + function print_bracketed(body, output) { + if (body.length > 0) output.with_block(function(){ + display_body(body, false, output); + }); + else output.print("{}"); + }; + DEFPRINT(AST_BlockStatement, function(self, output){ + print_bracketed(self.body, output); + }); + DEFPRINT(AST_EmptyStatement, function(self, output){ + output.semicolon(); + }); + DEFPRINT(AST_Do, function(self, output){ + output.print("do"); + output.space(); + self._do_print_body(output); + output.space(); + output.print("while"); + output.space(); + output.with_parens(function(){ + self.condition.print(output); + }); + output.semicolon(); + }); + DEFPRINT(AST_While, function(self, output){ + output.print("while"); + output.space(); + output.with_parens(function(){ + self.condition.print(output); + }); + output.space(); + self._do_print_body(output); + }); + DEFPRINT(AST_For, function(self, output){ + output.print("for"); + output.space(); + output.with_parens(function(){ + if (self.init) { + if (self.init instanceof AST_Definitions) { + self.init.print(output); + } else { + parenthesize_for_noin(self.init, output, true); + } + output.print(";"); + output.space(); + } else { + output.print(";"); + } + if (self.condition) { + self.condition.print(output); + output.print(";"); + output.space(); + } else { + output.print(";"); + } + if (self.step) { + self.step.print(output); + } + }); + output.space(); + self._do_print_body(output); + }); + DEFPRINT(AST_ForIn, function(self, output){ + output.print("for"); + output.space(); + output.with_parens(function(){ + self.init.print(output); + output.space(); + output.print("in"); + output.space(); + self.object.print(output); + }); + output.space(); + self._do_print_body(output); + }); + DEFPRINT(AST_With, function(self, output){ + output.print("with"); + output.space(); + output.with_parens(function(){ + self.expression.print(output); + }); + output.space(); + self._do_print_body(output); + }); + + /* -----[ functions ]----- */ + AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword){ + var self = this; + if (!nokeyword) { + output.print("function"); + } + if (self.name) { + output.space(); + self.name.print(output); + } + output.with_parens(function(){ + self.argnames.forEach(function(arg, i){ + if (i) output.comma(); + arg.print(output); + }); + }); + output.space(); + print_bracketed(self.body, output); + }); + DEFPRINT(AST_Lambda, function(self, output){ + self._do_print(output); + }); + + /* -----[ exits ]----- */ + AST_Exit.DEFMETHOD("_do_print", function(output, kind){ + output.print(kind); + if (this.value) { + output.space(); + this.value.print(output); + } + output.semicolon(); + }); + DEFPRINT(AST_Return, function(self, output){ + self._do_print(output, "return"); + }); + DEFPRINT(AST_Throw, function(self, output){ + self._do_print(output, "throw"); + }); + + /* -----[ loop control ]----- */ + AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){ + output.print(kind); + if (this.label) { + output.space(); + this.label.print(output); + } + output.semicolon(); + }); + DEFPRINT(AST_Break, function(self, output){ + self._do_print(output, "break"); + }); + DEFPRINT(AST_Continue, function(self, output){ + self._do_print(output, "continue"); + }); + + /* -----[ if ]----- */ + function make_then(self, output) { + if (output.option("bracketize")) { + make_block(self.body, output); + return; + } + // The squeezer replaces "block"-s that contain only a single + // statement with the statement itself; technically, the AST + // is correct, but this can create problems when we output an + // IF having an ELSE clause where the THEN clause ends in an + // IF *without* an ELSE block (then the outer ELSE would refer + // to the inner IF). This function checks for this case and + // adds the block brackets if needed. + if (!self.body) + return output.force_semicolon(); + if (self.body instanceof AST_Do + && !output.option("screw_ie8")) { + // https://github.com/mishoo/UglifyJS/issues/#issue/57 IE + // croaks with "syntax error" on code like this: if (foo) + // do ... while(cond); else ... we need block brackets + // around do/while + make_block(self.body, output); + return; + } + var b = self.body; + while (true) { + if (b instanceof AST_If) { + if (!b.alternative) { + make_block(self.body, output); + return; + } + b = b.alternative; + } + else if (b instanceof AST_StatementWithBody) { + b = b.body; + } + else break; + } + force_statement(self.body, output); + }; + DEFPRINT(AST_If, function(self, output){ + output.print("if"); + output.space(); + output.with_parens(function(){ + self.condition.print(output); + }); + output.space(); + if (self.alternative) { + make_then(self, output); + output.space(); + output.print("else"); + output.space(); + force_statement(self.alternative, output); + } else { + self._do_print_body(output); + } + }); + + /* -----[ switch ]----- */ + DEFPRINT(AST_Switch, function(self, output){ + output.print("switch"); + output.space(); + output.with_parens(function(){ + self.expression.print(output); + }); + output.space(); + if (self.body.length > 0) output.with_block(function(){ + self.body.forEach(function(stmt, i){ + if (i) output.newline(); + output.indent(true); + stmt.print(output); + }); + }); + else output.print("{}"); + }); + AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){ + if (this.body.length > 0) { + output.newline(); + this.body.forEach(function(stmt){ + output.indent(); + stmt.print(output); + output.newline(); + }); + } + }); + DEFPRINT(AST_Default, function(self, output){ + output.print("default:"); + self._do_print_body(output); + }); + DEFPRINT(AST_Case, function(self, output){ + output.print("case"); + output.space(); + self.expression.print(output); + output.print(":"); + self._do_print_body(output); + }); + + /* -----[ exceptions ]----- */ + DEFPRINT(AST_Try, function(self, output){ + output.print("try"); + output.space(); + print_bracketed(self.body, output); + if (self.bcatch) { + output.space(); + self.bcatch.print(output); + } + if (self.bfinally) { + output.space(); + self.bfinally.print(output); + } + }); + DEFPRINT(AST_Catch, function(self, output){ + output.print("catch"); + output.space(); + output.with_parens(function(){ + self.argname.print(output); + }); + output.space(); + print_bracketed(self.body, output); + }); + DEFPRINT(AST_Finally, function(self, output){ + output.print("finally"); + output.space(); + print_bracketed(self.body, output); + }); + + /* -----[ var/const ]----- */ + AST_Definitions.DEFMETHOD("_do_print", function(output, kind){ + output.print(kind); + output.space(); + this.definitions.forEach(function(def, i){ + if (i) output.comma(); + def.print(output); + }); + var p = output.parent(); + var in_for = p instanceof AST_For || p instanceof AST_ForIn; + var avoid_semicolon = in_for && p.init === this; + if (!avoid_semicolon) + output.semicolon(); + }); + DEFPRINT(AST_Var, function(self, output){ + self._do_print(output, "var"); + }); + DEFPRINT(AST_Const, function(self, output){ + self._do_print(output, "const"); + }); + + function parenthesize_for_noin(node, output, noin) { + if (!noin) node.print(output); + else try { + // need to take some precautions here: + // https://github.com/mishoo/UglifyJS2/issues/60 + node.walk(new TreeWalker(function(node){ + if (node instanceof AST_Binary && node.operator == "in") + throw output; + })); + node.print(output); + } catch(ex) { + if (ex !== output) throw ex; + node.print(output, true); + } + }; + + DEFPRINT(AST_VarDef, function(self, output){ + self.name.print(output); + if (self.value) { + output.space(); + output.print("="); + output.space(); + var p = output.parent(1); + var noin = p instanceof AST_For || p instanceof AST_ForIn; + parenthesize_for_noin(self.value, output, noin); + } + }); + + /* -----[ other expressions ]----- */ + DEFPRINT(AST_Call, function(self, output){ + self.expression.print(output); + if (self instanceof AST_New && no_constructor_parens(self, output)) + return; + output.with_parens(function(){ + self.args.forEach(function(expr, i){ + if (i) output.comma(); + expr.print(output); + }); + }); + }); + DEFPRINT(AST_New, function(self, output){ + output.print("new"); + output.space(); + AST_Call.prototype._codegen(self, output); + }); + + AST_Seq.DEFMETHOD("_do_print", function(output){ + this.car.print(output); + if (this.cdr) { + output.comma(); + if (output.should_break()) { + output.newline(); + output.indent(); + } + this.cdr.print(output); + } + }); + DEFPRINT(AST_Seq, function(self, output){ + self._do_print(output); + // var p = output.parent(); + // if (p instanceof AST_Statement) { + // output.with_indent(output.next_indent(), function(){ + // self._do_print(output); + // }); + // } else { + // self._do_print(output); + // } + }); + DEFPRINT(AST_Dot, function(self, output){ + var expr = self.expression; + expr.print(output); + if (expr instanceof AST_Number && expr.getValue() >= 0) { + if (!/[xa-f.]/i.test(output.last())) { + output.print("."); + } + } + output.print("."); + // the name after dot would be mapped about here. + output.add_mapping(self.end); + output.print_name(self.property); + }); + DEFPRINT(AST_Sub, function(self, output){ + self.expression.print(output); + output.print("["); + self.property.print(output); + output.print("]"); + }); + DEFPRINT(AST_UnaryPrefix, function(self, output){ + var op = self.operator; + output.print(op); + if (/^[a-z]/i.test(op)) + output.space(); + self.expression.print(output); + }); + DEFPRINT(AST_UnaryPostfix, function(self, output){ + self.expression.print(output); + output.print(self.operator); + }); + DEFPRINT(AST_Binary, function(self, output){ + self.left.print(output); + output.space(); + output.print(self.operator); + if (self.operator == "<" + && self.right instanceof AST_UnaryPrefix + && self.right.operator == "!" + && self.right.expression instanceof AST_UnaryPrefix + && self.right.expression.operator == "--") { + // space is mandatory to avoid outputting ") && S.newline_before) { + forward(3); + return skip_line_comment("comment4"); + } + } + var ch = peek(); + if (!ch) return token("eof"); + var code = ch.charCodeAt(0); + switch (code) { + case 34: case 39: return read_string(); + case 46: return handle_dot(); + case 47: return handle_slash(); + } + if (is_digit(code)) return read_num(); + if (PUNC_CHARS(ch)) return token("punc", next()); + if (OPERATOR_CHARS(ch)) return read_operator(); + if (code == 92 || is_identifier_start(code)) return read_word(); + parse_error("Unexpected character '" + ch + "'"); + }; + + next_token.context = function(nc) { + if (nc) S = nc; + return S; + }; + + return next_token; + +}; + +/* -----[ Parser (constants) ]----- */ + +var UNARY_PREFIX = makePredicate([ + "typeof", + "void", + "delete", + "--", + "++", + "!", + "~", + "-", + "+" +]); + +var UNARY_POSTFIX = makePredicate([ "--", "++" ]); + +var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]); + +var PRECEDENCE = (function(a, ret){ + for (var i = 0; i < a.length; ++i) { + var b = a[i]; + for (var j = 0; j < b.length; ++j) { + ret[b[j]] = i + 1; + } + } + return ret; +})( + [ + ["||"], + ["&&"], + ["|"], + ["^"], + ["&"], + ["==", "===", "!=", "!=="], + ["<", ">", "<=", ">=", "in", "instanceof"], + [">>", "<<", ">>>"], + ["+", "-"], + ["*", "/", "%"] + ], + {} +); + +var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]); + +var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]); + +/* -----[ Parser ]----- */ + +function parse($TEXT, options) { + + options = defaults(options, { + strict : false, + filename : null, + toplevel : null, + expression : false, + html5_comments : true, + }); + + var S = { + input : (typeof $TEXT == "string" + ? tokenizer($TEXT, options.filename, + options.html5_comments) + : $TEXT), + token : null, + prev : null, + peeked : null, + in_function : 0, + in_directives : true, + in_loop : 0, + labels : [] + }; + + S.token = next(); + + function is(type, value) { + return is_token(S.token, type, value); + }; + + function peek() { return S.peeked || (S.peeked = S.input()); }; + + function next() { + S.prev = S.token; + if (S.peeked) { + S.token = S.peeked; + S.peeked = null; + } else { + S.token = S.input(); + } + S.in_directives = S.in_directives && ( + S.token.type == "string" || is("punc", ";") + ); + return S.token; + }; + + function prev() { + return S.prev; + }; + + function croak(msg, line, col, pos) { + var ctx = S.input.context(); + js_error(msg, + ctx.filename, + line != null ? line : ctx.tokline, + col != null ? col : ctx.tokcol, + pos != null ? pos : ctx.tokpos); + }; + + function token_error(token, msg) { + croak(msg, token.line, token.col); + }; + + function unexpected(token) { + if (token == null) + token = S.token; + token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); + }; + + function expect_token(type, val) { + if (is(type, val)) { + return next(); + } + token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»"); + }; + + function expect(punc) { return expect_token("punc", punc); }; + + function can_insert_semicolon() { + return !options.strict && ( + S.token.nlb || is("eof") || is("punc", "}") + ); + }; + + function semicolon() { + if (is("punc", ";")) next(); + else if (!can_insert_semicolon()) unexpected(); + }; + + function parenthesised() { + expect("("); + var exp = expression(true); + expect(")"); + return exp; + }; + + function embed_tokens(parser) { + return function() { + var start = S.token; + var expr = parser(); + var end = prev(); + expr.start = start; + expr.end = end; + return expr; + }; + }; + + function handle_regexp() { + if (is("operator", "/") || is("operator", "/=")) { + S.peeked = null; + S.token = S.input(S.token.value.substr(1)); // force regexp + } + }; + + var statement = embed_tokens(function() { + var tmp; + handle_regexp(); + switch (S.token.type) { + case "string": + var dir = S.in_directives, stat = simple_statement(); + // XXXv2: decide how to fix directives + if (dir && stat.body instanceof AST_String && !is("punc", ",")) + return new AST_Directive({ value: stat.body.value }); + return stat; + case "num": + case "regexp": + case "operator": + case "atom": + return simple_statement(); + + case "name": + return is_token(peek(), "punc", ":") + ? labeled_statement() + : simple_statement(); + + case "punc": + switch (S.token.value) { + case "{": + return new AST_BlockStatement({ + start : S.token, + body : block_(), + end : prev() + }); + case "[": + case "(": + return simple_statement(); + case ";": + next(); + return new AST_EmptyStatement(); + default: + unexpected(); + } + + case "keyword": + switch (tmp = S.token.value, next(), tmp) { + case "break": + return break_cont(AST_Break); + + case "continue": + return break_cont(AST_Continue); + + case "debugger": + semicolon(); + return new AST_Debugger(); + + case "do": + return new AST_Do({ + body : in_loop(statement), + condition : (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(), tmp) + }); + + case "while": + return new AST_While({ + condition : parenthesised(), + body : in_loop(statement) + }); + + case "for": + return for_(); + + case "function": + return function_(AST_Defun); + + case "if": + return if_(); + + case "return": + if (S.in_function == 0) + croak("'return' outside of function"); + return new AST_Return({ + value: ( is("punc", ";") + ? (next(), null) + : can_insert_semicolon() + ? null + : (tmp = expression(true), semicolon(), tmp) ) + }); + + case "switch": + return new AST_Switch({ + expression : parenthesised(), + body : in_loop(switch_body_) + }); + + case "throw": + if (S.token.nlb) + croak("Illegal newline after 'throw'"); + return new AST_Throw({ + value: (tmp = expression(true), semicolon(), tmp) + }); + + case "try": + return try_(); + + case "var": + return tmp = var_(), semicolon(), tmp; + + case "const": + return tmp = const_(), semicolon(), tmp; + + case "with": + return new AST_With({ + expression : parenthesised(), + body : statement() + }); + + default: + unexpected(); + } + } + }); + + function labeled_statement() { + var label = as_symbol(AST_Label); + if (find_if(function(l){ return l.name == label.name }, S.labels)) { + // ECMA-262, 12.12: An ECMAScript program is considered + // syntactically incorrect if it contains a + // LabelledStatement that is enclosed by a + // LabelledStatement with the same Identifier as label. + croak("Label " + label.name + " defined twice"); + } + expect(":"); + S.labels.push(label); + var stat = statement(); + S.labels.pop(); + if (!(stat instanceof AST_IterationStatement)) { + // check for `continue` that refers to this label. + // those should be reported as syntax errors. + // https://github.com/mishoo/UglifyJS2/issues/287 + label.references.forEach(function(ref){ + if (ref instanceof AST_Continue) { + ref = ref.label.start; + croak("Continue label `" + label.name + "` refers to non-IterationStatement.", + ref.line, ref.col, ref.pos); + } + }); + } + return new AST_LabeledStatement({ body: stat, label: label }); + }; + + function simple_statement(tmp) { + return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) }); + }; + + function break_cont(type) { + var label = null, ldef; + if (!can_insert_semicolon()) { + label = as_symbol(AST_LabelRef, true); + } + if (label != null) { + ldef = find_if(function(l){ return l.name == label.name }, S.labels); + if (!ldef) + croak("Undefined label " + label.name); + label.thedef = ldef; + } + else if (S.in_loop == 0) + croak(type.TYPE + " not inside a loop or switch"); + semicolon(); + var stat = new type({ label: label }); + if (ldef) ldef.references.push(stat); + return stat; + }; + + function for_() { + expect("("); + var init = null; + if (!is("punc", ";")) { + init = is("keyword", "var") + ? (next(), var_(true)) + : expression(true, true); + if (is("operator", "in")) { + if (init instanceof AST_Var && init.definitions.length > 1) + croak("Only one variable declaration allowed in for..in loop"); + next(); + return for_in(init); + } + } + return regular_for(init); + }; + + function regular_for(init) { + expect(";"); + var test = is("punc", ";") ? null : expression(true); + expect(";"); + var step = is("punc", ")") ? null : expression(true); + expect(")"); + return new AST_For({ + init : init, + condition : test, + step : step, + body : in_loop(statement) + }); + }; + + function for_in(init) { + var lhs = init instanceof AST_Var ? init.definitions[0].name : null; + var obj = expression(true); + expect(")"); + return new AST_ForIn({ + init : init, + name : lhs, + object : obj, + body : in_loop(statement) + }); + }; + + var function_ = function(ctor) { + var in_statement = ctor === AST_Defun; + var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null; + if (in_statement && !name) + unexpected(); + expect("("); + return new ctor({ + name: name, + argnames: (function(first, a){ + while (!is("punc", ")")) { + if (first) first = false; else expect(","); + a.push(as_symbol(AST_SymbolFunarg)); + } + next(); + return a; + })(true, []), + body: (function(loop, labels){ + ++S.in_function; + S.in_directives = true; + S.in_loop = 0; + S.labels = []; + var a = block_(); + --S.in_function; + S.in_loop = loop; + S.labels = labels; + return a; + })(S.in_loop, S.labels) + }); + }; + + function if_() { + var cond = parenthesised(), body = statement(), belse = null; + if (is("keyword", "else")) { + next(); + belse = statement(); + } + return new AST_If({ + condition : cond, + body : body, + alternative : belse + }); + }; + + function block_() { + expect("{"); + var a = []; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + a.push(statement()); + } + next(); + return a; + }; + + function switch_body_() { + expect("{"); + var a = [], cur = null, branch = null, tmp; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + if (is("keyword", "case")) { + if (branch) branch.end = prev(); + cur = []; + branch = new AST_Case({ + start : (tmp = S.token, next(), tmp), + expression : expression(true), + body : cur + }); + a.push(branch); + expect(":"); + } + else if (is("keyword", "default")) { + if (branch) branch.end = prev(); + cur = []; + branch = new AST_Default({ + start : (tmp = S.token, next(), expect(":"), tmp), + body : cur + }); + a.push(branch); + } + else { + if (!cur) unexpected(); + cur.push(statement()); + } + } + if (branch) branch.end = prev(); + next(); + return a; + }; + + function try_() { + var body = block_(), bcatch = null, bfinally = null; + if (is("keyword", "catch")) { + var start = S.token; + next(); + expect("("); + var name = as_symbol(AST_SymbolCatch); + expect(")"); + bcatch = new AST_Catch({ + start : start, + argname : name, + body : block_(), + end : prev() + }); + } + if (is("keyword", "finally")) { + var start = S.token; + next(); + bfinally = new AST_Finally({ + start : start, + body : block_(), + end : prev() + }); + } + if (!bcatch && !bfinally) + croak("Missing catch/finally blocks"); + return new AST_Try({ + body : body, + bcatch : bcatch, + bfinally : bfinally + }); + }; + + function vardefs(no_in, in_const) { + var a = []; + for (;;) { + a.push(new AST_VarDef({ + start : S.token, + name : as_symbol(in_const ? AST_SymbolConst : AST_SymbolVar), + value : is("operator", "=") ? (next(), expression(false, no_in)) : null, + end : prev() + })); + if (!is("punc", ",")) + break; + next(); + } + return a; + }; + + var var_ = function(no_in) { + return new AST_Var({ + start : prev(), + definitions : vardefs(no_in, false), + end : prev() + }); + }; + + var const_ = function() { + return new AST_Const({ + start : prev(), + definitions : vardefs(false, true), + end : prev() + }); + }; + + var new_ = function() { + var start = S.token; + expect_token("operator", "new"); + var newexp = expr_atom(false), args; + if (is("punc", "(")) { + next(); + args = expr_list(")"); + } else { + args = []; + } + return subscripts(new AST_New({ + start : start, + expression : newexp, + args : args, + end : prev() + }), true); + }; + + function as_atom_node() { + var tok = S.token, ret; + switch (tok.type) { + case "name": + case "keyword": + ret = _make_symbol(AST_SymbolRef); + break; + case "num": + ret = new AST_Number({ start: tok, end: tok, value: tok.value }); + break; + case "string": + ret = new AST_String({ start: tok, end: tok, value: tok.value }); + break; + case "regexp": + ret = new AST_RegExp({ start: tok, end: tok, value: tok.value }); + break; + case "atom": + switch (tok.value) { + case "false": + ret = new AST_False({ start: tok, end: tok }); + break; + case "true": + ret = new AST_True({ start: tok, end: tok }); + break; + case "null": + ret = new AST_Null({ start: tok, end: tok }); + break; + } + break; + } + next(); + return ret; + }; + + var expr_atom = function(allow_calls) { + if (is("operator", "new")) { + return new_(); + } + var start = S.token; + if (is("punc")) { + switch (start.value) { + case "(": + next(); + var ex = expression(true); + ex.start = start; + ex.end = S.token; + expect(")"); + return subscripts(ex, allow_calls); + case "[": + return subscripts(array_(), allow_calls); + case "{": + return subscripts(object_(), allow_calls); + } + unexpected(); + } + if (is("keyword", "function")) { + next(); + var func = function_(AST_Function); + func.start = start; + func.end = prev(); + return subscripts(func, allow_calls); + } + if (ATOMIC_START_TOKEN[S.token.type]) { + return subscripts(as_atom_node(), allow_calls); + } + unexpected(); + }; + + function expr_list(closing, allow_trailing_comma, allow_empty) { + var first = true, a = []; + while (!is("punc", closing)) { + if (first) first = false; else expect(","); + if (allow_trailing_comma && is("punc", closing)) break; + if (is("punc", ",") && allow_empty) { + a.push(new AST_Hole({ start: S.token, end: S.token })); + } else { + a.push(expression(false)); + } + } + next(); + return a; + }; + + var array_ = embed_tokens(function() { + expect("["); + return new AST_Array({ + elements: expr_list("]", !options.strict, true) + }); + }); + + var object_ = embed_tokens(function() { + expect("{"); + var first = true, a = []; + while (!is("punc", "}")) { + if (first) first = false; else expect(","); + if (!options.strict && is("punc", "}")) + // allow trailing comma + break; + var start = S.token; + var type = start.type; + var name = as_property_name(); + if (type == "name" && !is("punc", ":")) { + if (name == "get") { + a.push(new AST_ObjectGetter({ + start : start, + key : as_atom_node(), + value : function_(AST_Accessor), + end : prev() + })); + continue; + } + if (name == "set") { + a.push(new AST_ObjectSetter({ + start : start, + key : as_atom_node(), + value : function_(AST_Accessor), + end : prev() + })); + continue; + } + } + expect(":"); + a.push(new AST_ObjectKeyVal({ + start : start, + key : name, + value : expression(false), + end : prev() + })); + } + next(); + return new AST_Object({ properties: a }); + }); + + function as_property_name() { + var tmp = S.token; + next(); + switch (tmp.type) { + case "num": + case "string": + case "name": + case "operator": + case "keyword": + case "atom": + return tmp.value; + default: + unexpected(); + } + }; + + function as_name() { + var tmp = S.token; + next(); + switch (tmp.type) { + case "name": + case "operator": + case "keyword": + case "atom": + return tmp.value; + default: + unexpected(); + } + }; + + function _make_symbol(type) { + var name = S.token.value; + return new (name == "this" ? AST_This : type)({ + name : String(name), + start : S.token, + end : S.token + }); + }; + + function as_symbol(type, noerror) { + if (!is("name")) { + if (!noerror) croak("Name expected"); + return null; + } + var sym = _make_symbol(type); + next(); + return sym; + }; + + var subscripts = function(expr, allow_calls) { + var start = expr.start; + if (is("punc", ".")) { + next(); + return subscripts(new AST_Dot({ + start : start, + expression : expr, + property : as_name(), + end : prev() + }), allow_calls); + } + if (is("punc", "[")) { + next(); + var prop = expression(true); + expect("]"); + return subscripts(new AST_Sub({ + start : start, + expression : expr, + property : prop, + end : prev() + }), allow_calls); + } + if (allow_calls && is("punc", "(")) { + next(); + return subscripts(new AST_Call({ + start : start, + expression : expr, + args : expr_list(")"), + end : prev() + }), true); + } + return expr; + }; + + var maybe_unary = function(allow_calls) { + var start = S.token; + if (is("operator") && UNARY_PREFIX(start.value)) { + next(); + handle_regexp(); + var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls)); + ex.start = start; + ex.end = prev(); + return ex; + } + var val = expr_atom(allow_calls); + while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) { + val = make_unary(AST_UnaryPostfix, S.token.value, val); + val.start = start; + val.end = S.token; + next(); + } + return val; + }; + + function make_unary(ctor, op, expr) { + if ((op == "++" || op == "--") && !is_assignable(expr)) + croak("Invalid use of " + op + " operator"); + return new ctor({ operator: op, expression: expr }); + }; + + var expr_op = function(left, min_prec, no_in) { + var op = is("operator") ? S.token.value : null; + if (op == "in" && no_in) op = null; + var prec = op != null ? PRECEDENCE[op] : null; + if (prec != null && prec > min_prec) { + next(); + var right = expr_op(maybe_unary(true), prec, no_in); + return expr_op(new AST_Binary({ + start : left.start, + left : left, + operator : op, + right : right, + end : right.end + }), min_prec, no_in); + } + return left; + }; + + function expr_ops(no_in) { + return expr_op(maybe_unary(true), 0, no_in); + }; + + var maybe_conditional = function(no_in) { + var start = S.token; + var expr = expr_ops(no_in); + if (is("operator", "?")) { + next(); + var yes = expression(false); + expect(":"); + return new AST_Conditional({ + start : start, + condition : expr, + consequent : yes, + alternative : expression(false, no_in), + end : peek() + }); + } + return expr; + }; + + function is_assignable(expr) { + if (!options.strict) return true; + if (expr instanceof AST_This) return false; + return (expr instanceof AST_PropAccess || expr instanceof AST_Symbol); + }; + + var maybe_assign = function(no_in) { + var start = S.token; + var left = maybe_conditional(no_in), val = S.token.value; + if (is("operator") && ASSIGNMENT(val)) { + if (is_assignable(left)) { + next(); + return new AST_Assign({ + start : start, + left : left, + operator : val, + right : maybe_assign(no_in), + end : prev() + }); + } + croak("Invalid assignment"); + } + return left; + }; + + var expression = function(commas, no_in) { + var start = S.token; + var expr = maybe_assign(no_in); + if (commas && is("punc", ",")) { + next(); + return new AST_Seq({ + start : start, + car : expr, + cdr : expression(true, no_in), + end : peek() + }); + } + return expr; + }; + + function in_loop(cont) { + ++S.in_loop; + var ret = cont(); + --S.in_loop; + return ret; + }; + + if (options.expression) { + return expression(true); + } + + return (function(){ + var start = S.token; + var body = []; + while (!is("eof")) + body.push(statement()); + var end = prev(); + var toplevel = options.toplevel; + if (toplevel) { + toplevel.body = toplevel.body.concat(body); + toplevel.end = end; + } else { + toplevel = new AST_Toplevel({ start: start, body: body, end: end }); + } + return toplevel; + })(); + +}; diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/scope.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/scope.js new file mode 100644 index 0000000..49b0481 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/scope.js @@ -0,0 +1,556 @@ +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + 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. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 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. + + ***********************************************************************/ + +"use strict"; + +function SymbolDef(scope, index, orig) { + this.name = orig.name; + this.orig = [ orig ]; + this.scope = scope; + this.references = []; + this.global = false; + this.mangled_name = null; + this.undeclared = false; + this.constant = false; + this.index = index; +}; + +SymbolDef.prototype = { + unmangleable: function(options) { + return (this.global && !(options && options.toplevel)) + || this.undeclared + || (!(options && options.eval) && (this.scope.uses_eval || this.scope.uses_with)); + }, + mangle: function(options) { + if (!this.mangled_name && !this.unmangleable(options)) { + var s = this.scope; + if (!options.screw_ie8 && this.orig[0] instanceof AST_SymbolLambda) + s = s.parent_scope; + this.mangled_name = s.next_mangled(options, this); + } + } +}; + +AST_Toplevel.DEFMETHOD("figure_out_scope", function(){ + // This does what ast_add_scope did in UglifyJS v1. + // + // Part of it could be done at parse time, but it would complicate + // the parser (and it's already kinda complex). It's also worth + // having it separated because we might need to call it multiple + // times on the same tree. + + // pass 1: setup scope chaining and handle definitions + var self = this; + var scope = self.parent_scope = null; + var nesting = 0; + var tw = new TreeWalker(function(node, descend){ + if (node instanceof AST_Scope) { + node.init_scope_vars(nesting); + var save_scope = node.parent_scope = scope; + ++nesting; + scope = node; + descend(); + scope = save_scope; + --nesting; + return true; // don't descend again in TreeWalker + } + if (node instanceof AST_Directive) { + node.scope = scope; + push_uniq(scope.directives, node.value); + return true; + } + if (node instanceof AST_With) { + for (var s = scope; s; s = s.parent_scope) + s.uses_with = true; + return; + } + if (node instanceof AST_Symbol) { + node.scope = scope; + } + if (node instanceof AST_SymbolLambda) { + scope.def_function(node); + } + else if (node instanceof AST_SymbolDefun) { + // Careful here, the scope where this should be defined is + // the parent scope. The reason is that we enter a new + // scope when we encounter the AST_Defun node (which is + // instanceof AST_Scope) but we get to the symbol a bit + // later. + (node.scope = scope.parent_scope).def_function(node); + } + else if (node instanceof AST_SymbolVar + || node instanceof AST_SymbolConst) { + var def = scope.def_variable(node); + def.constant = node instanceof AST_SymbolConst; + def.init = tw.parent().value; + } + else if (node instanceof AST_SymbolCatch) { + // XXX: this is wrong according to ECMA-262 (12.4). the + // `catch` argument name should be visible only inside the + // catch block. For a quick fix AST_Catch should inherit + // from AST_Scope. Keeping it this way because of IE, + // which doesn't obey the standard. (it introduces the + // identifier in the enclosing scope) + scope.def_variable(node); + } + }); + self.walk(tw); + + // pass 2: find back references and eval + var func = null; + var globals = self.globals = new Dictionary(); + var tw = new TreeWalker(function(node, descend){ + if (node instanceof AST_Lambda) { + var prev_func = func; + func = node; + descend(); + func = prev_func; + return true; + } + if (node instanceof AST_SymbolRef) { + var name = node.name; + var sym = node.scope.find_variable(name); + if (!sym) { + var g; + if (globals.has(name)) { + g = globals.get(name); + } else { + g = new SymbolDef(self, globals.size(), node); + g.undeclared = true; + g.global = true; + globals.set(name, g); + } + node.thedef = g; + if (name == "eval" && tw.parent() instanceof AST_Call) { + for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) + s.uses_eval = true; + } + if (func && name == "arguments") { + func.uses_arguments = true; + } + } else { + node.thedef = sym; + } + node.reference(); + return true; + } + }); + self.walk(tw); +}); + +AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){ + this.directives = []; // contains the directives defined in this scope, i.e. "use strict" + this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions) + this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope) + this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement + this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval` + this.parent_scope = null; // the parent scope + this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes + this.cname = -1; // the current index for mangling functions/variables + this.nesting = nesting; // the nesting level of this scope (0 means toplevel) +}); + +AST_Scope.DEFMETHOD("strict", function(){ + return this.has_directive("use strict"); +}); + +AST_Lambda.DEFMETHOD("init_scope_vars", function(){ + AST_Scope.prototype.init_scope_vars.apply(this, arguments); + this.uses_arguments = false; +}); + +AST_SymbolRef.DEFMETHOD("reference", function() { + var def = this.definition(); + def.references.push(this); + var s = this.scope; + while (s) { + push_uniq(s.enclosed, def); + if (s === def.scope) break; + s = s.parent_scope; + } + this.frame = this.scope.nesting - def.scope.nesting; +}); + +AST_Scope.DEFMETHOD("find_variable", function(name){ + if (name instanceof AST_Symbol) name = name.name; + return this.variables.get(name) + || (this.parent_scope && this.parent_scope.find_variable(name)); +}); + +AST_Scope.DEFMETHOD("has_directive", function(value){ + return this.parent_scope && this.parent_scope.has_directive(value) + || (this.directives.indexOf(value) >= 0 ? this : null); +}); + +AST_Scope.DEFMETHOD("def_function", function(symbol){ + this.functions.set(symbol.name, this.def_variable(symbol)); +}); + +AST_Scope.DEFMETHOD("def_variable", function(symbol){ + var def; + if (!this.variables.has(symbol.name)) { + def = new SymbolDef(this, this.variables.size(), symbol); + this.variables.set(symbol.name, def); + def.global = !this.parent_scope; + } else { + def = this.variables.get(symbol.name); + def.orig.push(symbol); + } + return symbol.thedef = def; +}); + +AST_Scope.DEFMETHOD("next_mangled", function(options){ + var ext = this.enclosed; + out: while (true) { + var m = base54(++this.cname); + if (!is_identifier(m)) continue; // skip over "do" + // we must ensure that the mangled name does not shadow a name + // from some parent scope that is referenced in this or in + // inner scopes. + for (var i = ext.length; --i >= 0;) { + var sym = ext[i]; + var name = sym.mangled_name || (sym.unmangleable(options) && sym.name); + if (m == name) continue out; + } + return m; + } +}); + +AST_Function.DEFMETHOD("next_mangled", function(options, def){ + // #179, #326 + // in Safari strict mode, something like (function x(x){...}) is a syntax error; + // a function expression's argument cannot shadow the function expression's name + + var tricky_def = def.orig[0] instanceof AST_SymbolFunarg && this.name && this.name.definition(); + while (true) { + var name = AST_Lambda.prototype.next_mangled.call(this, options, def); + if (!(tricky_def && tricky_def.mangled_name == name)) + return name; + } +}); + +AST_Scope.DEFMETHOD("references", function(sym){ + if (sym instanceof AST_Symbol) sym = sym.definition(); + return this.enclosed.indexOf(sym) < 0 ? null : sym; +}); + +AST_Symbol.DEFMETHOD("unmangleable", function(options){ + return this.definition().unmangleable(options); +}); + +// property accessors are not mangleable +AST_SymbolAccessor.DEFMETHOD("unmangleable", function(){ + return true; +}); + +// labels are always mangleable +AST_Label.DEFMETHOD("unmangleable", function(){ + return false; +}); + +AST_Symbol.DEFMETHOD("unreferenced", function(){ + return this.definition().references.length == 0 + && !(this.scope.uses_eval || this.scope.uses_with); +}); + +AST_Symbol.DEFMETHOD("undeclared", function(){ + return this.definition().undeclared; +}); + +AST_LabelRef.DEFMETHOD("undeclared", function(){ + return false; +}); + +AST_Label.DEFMETHOD("undeclared", function(){ + return false; +}); + +AST_Symbol.DEFMETHOD("definition", function(){ + return this.thedef; +}); + +AST_Symbol.DEFMETHOD("global", function(){ + return this.definition().global; +}); + +AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){ + return defaults(options, { + except : [], + eval : false, + sort : false, + toplevel : false, + screw_ie8 : false + }); +}); + +AST_Toplevel.DEFMETHOD("mangle_names", function(options){ + options = this._default_mangler_options(options); + // We only need to mangle declaration nodes. Special logic wired + // into the code generator will display the mangled name if it's + // present (and for AST_SymbolRef-s it'll use the mangled name of + // the AST_SymbolDeclaration that it points to). + var lname = -1; + var to_mangle = []; + var tw = new TreeWalker(function(node, descend){ + if (node instanceof AST_LabeledStatement) { + // lname is incremented when we get to the AST_Label + var save_nesting = lname; + descend(); + lname = save_nesting; + return true; // don't descend again in TreeWalker + } + if (node instanceof AST_Scope) { + var p = tw.parent(), a = []; + node.variables.each(function(symbol){ + if (options.except.indexOf(symbol.name) < 0) { + a.push(symbol); + } + }); + if (options.sort) a.sort(function(a, b){ + return b.references.length - a.references.length; + }); + to_mangle.push.apply(to_mangle, a); + return; + } + if (node instanceof AST_Label) { + var name; + do name = base54(++lname); while (!is_identifier(name)); + node.mangled_name = name; + return true; + } + }); + this.walk(tw); + to_mangle.forEach(function(def){ def.mangle(options) }); +}); + +AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){ + options = this._default_mangler_options(options); + var tw = new TreeWalker(function(node){ + if (node instanceof AST_Constant) + base54.consider(node.print_to_string()); + else if (node instanceof AST_Return) + base54.consider("return"); + else if (node instanceof AST_Throw) + base54.consider("throw"); + else if (node instanceof AST_Continue) + base54.consider("continue"); + else if (node instanceof AST_Break) + base54.consider("break"); + else if (node instanceof AST_Debugger) + base54.consider("debugger"); + else if (node instanceof AST_Directive) + base54.consider(node.value); + else if (node instanceof AST_While) + base54.consider("while"); + else if (node instanceof AST_Do) + base54.consider("do while"); + else if (node instanceof AST_If) { + base54.consider("if"); + if (node.alternative) base54.consider("else"); + } + else if (node instanceof AST_Var) + base54.consider("var"); + else if (node instanceof AST_Const) + base54.consider("const"); + else if (node instanceof AST_Lambda) + base54.consider("function"); + else if (node instanceof AST_For) + base54.consider("for"); + else if (node instanceof AST_ForIn) + base54.consider("for in"); + else if (node instanceof AST_Switch) + base54.consider("switch"); + else if (node instanceof AST_Case) + base54.consider("case"); + else if (node instanceof AST_Default) + base54.consider("default"); + else if (node instanceof AST_With) + base54.consider("with"); + else if (node instanceof AST_ObjectSetter) + base54.consider("set" + node.key); + else if (node instanceof AST_ObjectGetter) + base54.consider("get" + node.key); + else if (node instanceof AST_ObjectKeyVal) + base54.consider(node.key); + else if (node instanceof AST_New) + base54.consider("new"); + else if (node instanceof AST_This) + base54.consider("this"); + else if (node instanceof AST_Try) + base54.consider("try"); + else if (node instanceof AST_Catch) + base54.consider("catch"); + else if (node instanceof AST_Finally) + base54.consider("finally"); + else if (node instanceof AST_Symbol && node.unmangleable(options)) + base54.consider(node.name); + else if (node instanceof AST_Unary || node instanceof AST_Binary) + base54.consider(node.operator); + else if (node instanceof AST_Dot) + base54.consider(node.property); + }); + this.walk(tw); + base54.sort(); +}); + +var base54 = (function() { + var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"; + var chars, frequency; + function reset() { + frequency = Object.create(null); + chars = string.split("").map(function(ch){ return ch.charCodeAt(0) }); + chars.forEach(function(ch){ frequency[ch] = 0 }); + } + base54.consider = function(str){ + for (var i = str.length; --i >= 0;) { + var code = str.charCodeAt(i); + if (code in frequency) ++frequency[code]; + } + }; + base54.sort = function() { + chars = mergeSort(chars, function(a, b){ + if (is_digit(a) && !is_digit(b)) return 1; + if (is_digit(b) && !is_digit(a)) return -1; + return frequency[b] - frequency[a]; + }); + }; + base54.reset = reset; + reset(); + base54.get = function(){ return chars }; + base54.freq = function(){ return frequency }; + function base54(num) { + var ret = "", base = 54; + do { + ret += String.fromCharCode(chars[num % base]); + num = Math.floor(num / base); + base = 64; + } while (num > 0); + return ret; + }; + return base54; +})(); + +AST_Toplevel.DEFMETHOD("scope_warnings", function(options){ + options = defaults(options, { + undeclared : false, // this makes a lot of noise + unreferenced : true, + assign_to_global : true, + func_arguments : true, + nested_defuns : true, + eval : true + }); + var tw = new TreeWalker(function(node){ + if (options.undeclared + && node instanceof AST_SymbolRef + && node.undeclared()) + { + // XXX: this also warns about JS standard names, + // i.e. Object, Array, parseInt etc. Should add a list of + // exceptions. + AST_Node.warn("Undeclared symbol: {name} [{file}:{line},{col}]", { + name: node.name, + file: node.start.file, + line: node.start.line, + col: node.start.col + }); + } + if (options.assign_to_global) + { + var sym = null; + if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef) + sym = node.left; + else if (node instanceof AST_ForIn && node.init instanceof AST_SymbolRef) + sym = node.init; + if (sym + && (sym.undeclared() + || (sym.global() && sym.scope !== sym.definition().scope))) { + AST_Node.warn("{msg}: {name} [{file}:{line},{col}]", { + msg: sym.undeclared() ? "Accidental global?" : "Assignment to global", + name: sym.name, + file: sym.start.file, + line: sym.start.line, + col: sym.start.col + }); + } + } + if (options.eval + && node instanceof AST_SymbolRef + && node.undeclared() + && node.name == "eval") { + AST_Node.warn("Eval is used [{file}:{line},{col}]", node.start); + } + if (options.unreferenced + && (node instanceof AST_SymbolDeclaration || node instanceof AST_Label) + && node.unreferenced()) { + AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", { + type: node instanceof AST_Label ? "Label" : "Symbol", + name: node.name, + file: node.start.file, + line: node.start.line, + col: node.start.col + }); + } + if (options.func_arguments + && node instanceof AST_Lambda + && node.uses_arguments) { + AST_Node.warn("arguments used in function {name} [{file}:{line},{col}]", { + name: node.name ? node.name.name : "anonymous", + file: node.start.file, + line: node.start.line, + col: node.start.col + }); + } + if (options.nested_defuns + && node instanceof AST_Defun + && !(tw.parent() instanceof AST_Scope)) { + AST_Node.warn("Function {name} declared in nested statement \"{type}\" [{file}:{line},{col}]", { + name: node.name.name, + type: tw.parent().TYPE, + file: node.start.file, + line: node.start.line, + col: node.start.col + }); + } + }); + this.walk(tw); +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/sourcemap.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/sourcemap.js new file mode 100644 index 0000000..3429908 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/sourcemap.js @@ -0,0 +1,81 @@ +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + 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. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 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. + + ***********************************************************************/ + +"use strict"; + +// a small wrapper around fitzgen's source-map library +function SourceMap(options) { + options = defaults(options, { + file : null, + root : null, + orig : null, + }); + var generator = new MOZ_SourceMap.SourceMapGenerator({ + file : options.file, + sourceRoot : options.root + }); + var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig); + function add(source, gen_line, gen_col, orig_line, orig_col, name) { + if (orig_map) { + var info = orig_map.originalPositionFor({ + line: orig_line, + column: orig_col + }); + source = info.source; + orig_line = info.line; + orig_col = info.column; + name = info.name; + } + generator.addMapping({ + generated : { line: gen_line, column: gen_col }, + original : { line: orig_line, column: orig_col }, + source : source, + name : name + }); + }; + return { + add : add, + get : function() { return generator }, + toString : function() { return generator.toString() } + }; +}; diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/transform.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/transform.js new file mode 100644 index 0000000..c3c34f5 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/transform.js @@ -0,0 +1,218 @@ +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + 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. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 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. + + ***********************************************************************/ + +"use strict"; + +// Tree transformer helpers. + +function TreeTransformer(before, after) { + TreeWalker.call(this); + this.before = before; + this.after = after; +} +TreeTransformer.prototype = new TreeWalker; + +(function(undefined){ + + function _(node, descend) { + node.DEFMETHOD("transform", function(tw, in_list){ + var x, y; + tw.push(this); + if (tw.before) x = tw.before(this, descend, in_list); + if (x === undefined) { + if (!tw.after) { + x = this; + descend(x, tw); + } else { + tw.stack[tw.stack.length - 1] = x = this.clone(); + descend(x, tw); + y = tw.after(x, in_list); + if (y !== undefined) x = y; + } + } + tw.pop(); + return x; + }); + }; + + function do_list(list, tw) { + return MAP(list, function(node){ + return node.transform(tw, true); + }); + }; + + _(AST_Node, noop); + + _(AST_LabeledStatement, function(self, tw){ + self.label = self.label.transform(tw); + self.body = self.body.transform(tw); + }); + + _(AST_SimpleStatement, function(self, tw){ + self.body = self.body.transform(tw); + }); + + _(AST_Block, function(self, tw){ + self.body = do_list(self.body, tw); + }); + + _(AST_DWLoop, function(self, tw){ + self.condition = self.condition.transform(tw); + self.body = self.body.transform(tw); + }); + + _(AST_For, function(self, tw){ + if (self.init) self.init = self.init.transform(tw); + if (self.condition) self.condition = self.condition.transform(tw); + if (self.step) self.step = self.step.transform(tw); + self.body = self.body.transform(tw); + }); + + _(AST_ForIn, function(self, tw){ + self.init = self.init.transform(tw); + self.object = self.object.transform(tw); + self.body = self.body.transform(tw); + }); + + _(AST_With, function(self, tw){ + self.expression = self.expression.transform(tw); + self.body = self.body.transform(tw); + }); + + _(AST_Exit, function(self, tw){ + if (self.value) self.value = self.value.transform(tw); + }); + + _(AST_LoopControl, function(self, tw){ + if (self.label) self.label = self.label.transform(tw); + }); + + _(AST_If, function(self, tw){ + self.condition = self.condition.transform(tw); + self.body = self.body.transform(tw); + if (self.alternative) self.alternative = self.alternative.transform(tw); + }); + + _(AST_Switch, function(self, tw){ + self.expression = self.expression.transform(tw); + self.body = do_list(self.body, tw); + }); + + _(AST_Case, function(self, tw){ + self.expression = self.expression.transform(tw); + self.body = do_list(self.body, tw); + }); + + _(AST_Try, function(self, tw){ + self.body = do_list(self.body, tw); + if (self.bcatch) self.bcatch = self.bcatch.transform(tw); + if (self.bfinally) self.bfinally = self.bfinally.transform(tw); + }); + + _(AST_Catch, function(self, tw){ + self.argname = self.argname.transform(tw); + self.body = do_list(self.body, tw); + }); + + _(AST_Definitions, function(self, tw){ + self.definitions = do_list(self.definitions, tw); + }); + + _(AST_VarDef, function(self, tw){ + self.name = self.name.transform(tw); + if (self.value) self.value = self.value.transform(tw); + }); + + _(AST_Lambda, function(self, tw){ + if (self.name) self.name = self.name.transform(tw); + self.argnames = do_list(self.argnames, tw); + self.body = do_list(self.body, tw); + }); + + _(AST_Call, function(self, tw){ + self.expression = self.expression.transform(tw); + self.args = do_list(self.args, tw); + }); + + _(AST_Seq, function(self, tw){ + self.car = self.car.transform(tw); + self.cdr = self.cdr.transform(tw); + }); + + _(AST_Dot, function(self, tw){ + self.expression = self.expression.transform(tw); + }); + + _(AST_Sub, function(self, tw){ + self.expression = self.expression.transform(tw); + self.property = self.property.transform(tw); + }); + + _(AST_Unary, function(self, tw){ + self.expression = self.expression.transform(tw); + }); + + _(AST_Binary, function(self, tw){ + self.left = self.left.transform(tw); + self.right = self.right.transform(tw); + }); + + _(AST_Conditional, function(self, tw){ + self.condition = self.condition.transform(tw); + self.consequent = self.consequent.transform(tw); + self.alternative = self.alternative.transform(tw); + }); + + _(AST_Array, function(self, tw){ + self.elements = do_list(self.elements, tw); + }); + + _(AST_Object, function(self, tw){ + self.properties = do_list(self.properties, tw); + }); + + _(AST_ObjectProperty, function(self, tw){ + self.value = self.value.transform(tw); + }); + +})(); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/utils.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/utils.js new file mode 100644 index 0000000..73964a0 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/lib/utils.js @@ -0,0 +1,295 @@ +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + 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. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 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. + + ***********************************************************************/ + +"use strict"; + +function array_to_hash(a) { + var ret = Object.create(null); + for (var i = 0; i < a.length; ++i) + ret[a[i]] = true; + return ret; +}; + +function slice(a, start) { + return Array.prototype.slice.call(a, start || 0); +}; + +function characters(str) { + return str.split(""); +}; + +function member(name, array) { + for (var i = array.length; --i >= 0;) + if (array[i] == name) + return true; + return false; +}; + +function find_if(func, array) { + for (var i = 0, n = array.length; i < n; ++i) { + if (func(array[i])) + return array[i]; + } +}; + +function repeat_string(str, i) { + if (i <= 0) return ""; + if (i == 1) return str; + var d = repeat_string(str, i >> 1); + d += d; + if (i & 1) d += str; + return d; +}; + +function DefaultsError(msg, defs) { + this.msg = msg; + this.defs = defs; +}; + +function defaults(args, defs, croak) { + if (args === true) + args = {}; + var ret = args || {}; + if (croak) for (var i in ret) if (ret.hasOwnProperty(i) && !defs.hasOwnProperty(i)) + throw new DefaultsError("`" + i + "` is not a supported option", defs); + for (var i in defs) if (defs.hasOwnProperty(i)) { + ret[i] = (args && args.hasOwnProperty(i)) ? args[i] : defs[i]; + } + return ret; +}; + +function merge(obj, ext) { + for (var i in ext) if (ext.hasOwnProperty(i)) { + obj[i] = ext[i]; + } + return obj; +}; + +function noop() {}; + +var MAP = (function(){ + function MAP(a, f, backwards) { + var ret = [], top = [], i; + function doit() { + var val = f(a[i], i); + var is_last = val instanceof Last; + if (is_last) val = val.v; + if (val instanceof AtTop) { + val = val.v; + if (val instanceof Splice) { + top.push.apply(top, backwards ? val.v.slice().reverse() : val.v); + } else { + top.push(val); + } + } + else if (val !== skip) { + if (val instanceof Splice) { + ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v); + } else { + ret.push(val); + } + } + return is_last; + }; + if (a instanceof Array) { + if (backwards) { + for (i = a.length; --i >= 0;) if (doit()) break; + ret.reverse(); + top.reverse(); + } else { + for (i = 0; i < a.length; ++i) if (doit()) break; + } + } + else { + for (i in a) if (a.hasOwnProperty(i)) if (doit()) break; + } + return top.concat(ret); + }; + MAP.at_top = function(val) { return new AtTop(val) }; + MAP.splice = function(val) { return new Splice(val) }; + MAP.last = function(val) { return new Last(val) }; + var skip = MAP.skip = {}; + function AtTop(val) { this.v = val }; + function Splice(val) { this.v = val }; + function Last(val) { this.v = val }; + return MAP; +})(); + +function push_uniq(array, el) { + if (array.indexOf(el) < 0) + array.push(el); +}; + +function string_template(text, props) { + return text.replace(/\{(.+?)\}/g, function(str, p){ + return props[p]; + }); +}; + +function remove(array, el) { + for (var i = array.length; --i >= 0;) { + if (array[i] === el) array.splice(i, 1); + } +}; + +function mergeSort(array, cmp) { + if (array.length < 2) return array.slice(); + function merge(a, b) { + var r = [], ai = 0, bi = 0, i = 0; + while (ai < a.length && bi < b.length) { + cmp(a[ai], b[bi]) <= 0 + ? r[i++] = a[ai++] + : r[i++] = b[bi++]; + } + if (ai < a.length) r.push.apply(r, a.slice(ai)); + if (bi < b.length) r.push.apply(r, b.slice(bi)); + return r; + }; + function _ms(a) { + if (a.length <= 1) + return a; + var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m); + left = _ms(left); + right = _ms(right); + return merge(left, right); + }; + return _ms(array); +}; + +function set_difference(a, b) { + return a.filter(function(el){ + return b.indexOf(el) < 0; + }); +}; + +function set_intersection(a, b) { + return a.filter(function(el){ + return b.indexOf(el) >= 0; + }); +}; + +// this function is taken from Acorn [1], written by Marijn Haverbeke +// [1] https://github.com/marijnh/acorn +function makePredicate(words) { + if (!(words instanceof Array)) words = words.split(" "); + var f = "", cats = []; + out: for (var i = 0; i < words.length; ++i) { + for (var j = 0; j < cats.length; ++j) + if (cats[j][0].length == words[i].length) { + cats[j].push(words[i]); + continue out; + } + cats.push([words[i]]); + } + function compareTo(arr) { + if (arr.length == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";"; + f += "switch(str){"; + for (var i = 0; i < arr.length; ++i) f += "case " + JSON.stringify(arr[i]) + ":"; + f += "return true}return false;"; + } + // When there are more than three length categories, an outer + // switch first dispatches on the lengths, to save on comparisons. + if (cats.length > 3) { + cats.sort(function(a, b) {return b.length - a.length;}); + f += "switch(str.length){"; + for (var i = 0; i < cats.length; ++i) { + var cat = cats[i]; + f += "case " + cat[0].length + ":"; + compareTo(cat); + } + f += "}"; + // Otherwise, simply generate a flat `switch` statement. + } else { + compareTo(words); + } + return new Function("str", f); +}; + +function all(array, predicate) { + for (var i = array.length; --i >= 0;) + if (!predicate(array[i])) + return false; + return true; +}; + +function Dictionary() { + this._values = Object.create(null); + this._size = 0; +}; +Dictionary.prototype = { + set: function(key, val) { + if (!this.has(key)) ++this._size; + this._values["$" + key] = val; + return this; + }, + add: function(key, val) { + if (this.has(key)) { + this.get(key).push(val); + } else { + this.set(key, [ val ]); + } + return this; + }, + get: function(key) { return this._values["$" + key] }, + del: function(key) { + if (this.has(key)) { + --this._size; + delete this._values["$" + key]; + } + return this; + }, + has: function(key) { return ("$" + key) in this._values }, + each: function(f) { + for (var i in this._values) + f(this._values[i], i.substr(1)); + }, + size: function() { + return this._size; + }, + map: function(f) { + var ret = []; + for (var i in this._values) + ret.push(f(this._values[i], i.substr(1))); + return ret; + } +}; diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/async/LICENSE b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/async/LICENSE new file mode 100644 index 0000000..b7f9d50 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/async/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010 Caolan McMahon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/async/README.md b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/async/README.md new file mode 100644 index 0000000..9ff1acf --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/async/README.md @@ -0,0 +1,1414 @@ +# Async.js + +Async is a utility module which provides straight-forward, powerful functions +for working with asynchronous JavaScript. Although originally designed for +use with [node.js](http://nodejs.org), it can also be used directly in the +browser. Also supports [component](https://github.com/component/component). + +Async provides around 20 functions that include the usual 'functional' +suspects (map, reduce, filter, each…) as well as some common patterns +for asynchronous control flow (parallel, series, waterfall…). All these +functions assume you follow the node.js convention of providing a single +callback as the last argument of your async function. + + +## Quick Examples + +```javascript +async.map(['file1','file2','file3'], fs.stat, function(err, results){ + // results is now an array of stats for each file +}); + +async.filter(['file1','file2','file3'], fs.exists, function(results){ + // results now equals an array of the existing files +}); + +async.parallel([ + function(){ ... }, + function(){ ... } +], callback); + +async.series([ + function(){ ... }, + function(){ ... } +]); +``` + +There are many more functions available so take a look at the docs below for a +full list. This module aims to be comprehensive, so if you feel anything is +missing please create a GitHub issue for it. + +## Common Pitfalls + +### Binding a context to an iterator + +This section is really about bind, not about async. If you are wondering how to +make async execute your iterators in a given context, or are confused as to why +a method of another library isn't working as an iterator, study this example: + +```js +// Here is a simple object with an (unnecessarily roundabout) squaring method +var AsyncSquaringLibrary = { + squareExponent: 2, + square: function(number, callback){ + var result = Math.pow(number, this.squareExponent); + setTimeout(function(){ + callback(null, result); + }, 200); + } +}; + +async.map([1, 2, 3], AsyncSquaringLibrary.square, function(err, result){ + // result is [NaN, NaN, NaN] + // This fails because the `this.squareExponent` expression in the square + // function is not evaluated in the context of AsyncSquaringLibrary, and is + // therefore undefined. +}); + +async.map([1, 2, 3], AsyncSquaringLibrary.square.bind(AsyncSquaringLibrary), function(err, result){ + // result is [1, 4, 9] + // With the help of bind we can attach a context to the iterator before + // passing it to async. Now the square function will be executed in its + // 'home' AsyncSquaringLibrary context and the value of `this.squareExponent` + // will be as expected. +}); +``` + +## Download + +The source is available for download from +[GitHub](http://github.com/caolan/async). +Alternatively, you can install using Node Package Manager (npm): + + npm install async + +__Development:__ [async.js](https://github.com/caolan/async/raw/master/lib/async.js) - 29.6kb Uncompressed + +## In the Browser + +So far it's been tested in IE6, IE7, IE8, FF3.6 and Chrome 5. Usage: + +```html + + +``` + +## Documentation + +### Collections + +* [each](#each) +* [map](#map) +* [filter](#filter) +* [reject](#reject) +* [reduce](#reduce) +* [detect](#detect) +* [sortBy](#sortBy) +* [some](#some) +* [every](#every) +* [concat](#concat) + +### Control Flow + +* [series](#series) +* [parallel](#parallel) +* [whilst](#whilst) +* [doWhilst](#doWhilst) +* [until](#until) +* [doUntil](#doUntil) +* [forever](#forever) +* [waterfall](#waterfall) +* [compose](#compose) +* [applyEach](#applyEach) +* [queue](#queue) +* [cargo](#cargo) +* [auto](#auto) +* [iterator](#iterator) +* [apply](#apply) +* [nextTick](#nextTick) +* [times](#times) +* [timesSeries](#timesSeries) + +### Utils + +* [memoize](#memoize) +* [unmemoize](#unmemoize) +* [log](#log) +* [dir](#dir) +* [noConflict](#noConflict) + + +## Collections + + + +### each(arr, iterator, callback) + +Applies an iterator function to each item in an array, in parallel. +The iterator is called with an item from the list and a callback for when it +has finished. If the iterator passes an error to this callback, the main +callback for the each function is immediately called with the error. + +Note, that since this function applies the iterator to each item in parallel +there is no guarantee that the iterator functions will complete in order. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback(err) which must be called once it has + completed. If no error has occured, the callback should be run without + arguments or with an explicit null argument. +* callback(err) - A callback which is called after all the iterator functions + have finished, or an error has occurred. + +__Example__ + +```js +// assuming openFiles is an array of file names and saveFile is a function +// to save the modified contents of that file: + +async.each(openFiles, saveFile, function(err){ + // if any of the saves produced an error, err would equal that error +}); +``` + +--------------------------------------- + + + +### eachSeries(arr, iterator, callback) + +The same as each only the iterator is applied to each item in the array in +series. The next iterator is only called once the current one has completed +processing. This means the iterator functions will complete in order. + + +--------------------------------------- + + + +### eachLimit(arr, limit, iterator, callback) + +The same as each only no more than "limit" iterators will be simultaneously +running at any time. + +Note that the items are not processed in batches, so there is no guarantee that + the first "limit" iterator functions will complete before any others are +started. + +__Arguments__ + +* arr - An array to iterate over. +* limit - The maximum number of iterators to run at any time. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback(err) which must be called once it has + completed. If no error has occured, the callback should be run without + arguments or with an explicit null argument. +* callback(err) - A callback which is called after all the iterator functions + have finished, or an error has occurred. + +__Example__ + +```js +// Assume documents is an array of JSON objects and requestApi is a +// function that interacts with a rate-limited REST api. + +async.eachLimit(documents, 20, requestApi, function(err){ + // if any of the saves produced an error, err would equal that error +}); +``` + +--------------------------------------- + + +### map(arr, iterator, callback) + +Produces a new array of values by mapping each value in the given array through +the iterator function. The iterator is called with an item from the array and a +callback for when it has finished processing. The callback takes 2 arguments, +an error and the transformed item from the array. If the iterator passes an +error to this callback, the main callback for the map function is immediately +called with the error. + +Note, that since this function applies the iterator to each item in parallel +there is no guarantee that the iterator functions will complete in order, however +the results array will be in the same order as the original array. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback(err, transformed) which must be called once + it has completed with an error (which can be null) and a transformed item. +* callback(err, results) - A callback which is called after all the iterator + functions have finished, or an error has occurred. Results is an array of the + transformed items from the original array. + +__Example__ + +```js +async.map(['file1','file2','file3'], fs.stat, function(err, results){ + // results is now an array of stats for each file +}); +``` + +--------------------------------------- + + +### mapSeries(arr, iterator, callback) + +The same as map only the iterator is applied to each item in the array in +series. The next iterator is only called once the current one has completed +processing. The results array will be in the same order as the original. + + +--------------------------------------- + + +### mapLimit(arr, limit, iterator, callback) + +The same as map only no more than "limit" iterators will be simultaneously +running at any time. + +Note that the items are not processed in batches, so there is no guarantee that + the first "limit" iterator functions will complete before any others are +started. + +__Arguments__ + +* arr - An array to iterate over. +* limit - The maximum number of iterators to run at any time. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback(err, transformed) which must be called once + it has completed with an error (which can be null) and a transformed item. +* callback(err, results) - A callback which is called after all the iterator + functions have finished, or an error has occurred. Results is an array of the + transformed items from the original array. + +__Example__ + +```js +async.map(['file1','file2','file3'], 1, fs.stat, function(err, results){ + // results is now an array of stats for each file +}); +``` + +--------------------------------------- + + +### filter(arr, iterator, callback) + +__Alias:__ select + +Returns a new array of all the values which pass an async truth test. +_The callback for each iterator call only accepts a single argument of true or +false, it does not accept an error argument first!_ This is in-line with the +way node libraries work with truth tests like fs.exists. This operation is +performed in parallel, but the results array will be in the same order as the +original. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback(truthValue) which must be called with a + boolean argument once it has completed. +* callback(results) - A callback which is called after all the iterator + functions have finished. + +__Example__ + +```js +async.filter(['file1','file2','file3'], fs.exists, function(results){ + // results now equals an array of the existing files +}); +``` + +--------------------------------------- + + +### filterSeries(arr, iterator, callback) + +__alias:__ selectSeries + +The same as filter only the iterator is applied to each item in the array in +series. The next iterator is only called once the current one has completed +processing. The results array will be in the same order as the original. + +--------------------------------------- + + +### reject(arr, iterator, callback) + +The opposite of filter. Removes values that pass an async truth test. + +--------------------------------------- + + +### rejectSeries(arr, iterator, callback) + +The same as reject, only the iterator is applied to each item in the array +in series. + + +--------------------------------------- + + +### reduce(arr, memo, iterator, callback) + +__aliases:__ inject, foldl + +Reduces a list of values into a single value using an async iterator to return +each successive step. Memo is the initial state of the reduction. This +function only operates in series. For performance reasons, it may make sense to +split a call to this function into a parallel map, then use the normal +Array.prototype.reduce on the results. This function is for situations where +each step in the reduction needs to be async, if you can get the data before +reducing it then it's probably a good idea to do so. + +__Arguments__ + +* arr - An array to iterate over. +* memo - The initial state of the reduction. +* iterator(memo, item, callback) - A function applied to each item in the + array to produce the next step in the reduction. The iterator is passed a + callback(err, reduction) which accepts an optional error as its first + argument, and the state of the reduction as the second. If an error is + passed to the callback, the reduction is stopped and the main callback is + immediately called with the error. +* callback(err, result) - A callback which is called after all the iterator + functions have finished. Result is the reduced value. + +__Example__ + +```js +async.reduce([1,2,3], 0, function(memo, item, callback){ + // pointless async: + process.nextTick(function(){ + callback(null, memo + item) + }); +}, function(err, result){ + // result is now equal to the last value of memo, which is 6 +}); +``` + +--------------------------------------- + + +### reduceRight(arr, memo, iterator, callback) + +__Alias:__ foldr + +Same as reduce, only operates on the items in the array in reverse order. + + +--------------------------------------- + + +### detect(arr, iterator, callback) + +Returns the first value in a list that passes an async truth test. The +iterator is applied in parallel, meaning the first iterator to return true will +fire the detect callback with that result. That means the result might not be +the first item in the original array (in terms of order) that passes the test. + +If order within the original array is important then look at detectSeries. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback(truthValue) which must be called with a + boolean argument once it has completed. +* callback(result) - A callback which is called as soon as any iterator returns + true, or after all the iterator functions have finished. Result will be + the first item in the array that passes the truth test (iterator) or the + value undefined if none passed. + +__Example__ + +```js +async.detect(['file1','file2','file3'], fs.exists, function(result){ + // result now equals the first file in the list that exists +}); +``` + +--------------------------------------- + + +### detectSeries(arr, iterator, callback) + +The same as detect, only the iterator is applied to each item in the array +in series. This means the result is always the first in the original array (in +terms of array order) that passes the truth test. + + +--------------------------------------- + + +### sortBy(arr, iterator, callback) + +Sorts a list by the results of running each value through an async iterator. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback(err, sortValue) which must be called once it + has completed with an error (which can be null) and a value to use as the sort + criteria. +* callback(err, results) - A callback which is called after all the iterator + functions have finished, or an error has occurred. Results is the items from + the original array sorted by the values returned by the iterator calls. + +__Example__ + +```js +async.sortBy(['file1','file2','file3'], function(file, callback){ + fs.stat(file, function(err, stats){ + callback(err, stats.mtime); + }); +}, function(err, results){ + // results is now the original array of files sorted by + // modified date +}); +``` + +--------------------------------------- + + +### some(arr, iterator, callback) + +__Alias:__ any + +Returns true if at least one element in the array satisfies an async test. +_The callback for each iterator call only accepts a single argument of true or +false, it does not accept an error argument first!_ This is in-line with the +way node libraries work with truth tests like fs.exists. Once any iterator +call returns true, the main callback is immediately called. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback(truthValue) which must be called with a + boolean argument once it has completed. +* callback(result) - A callback which is called as soon as any iterator returns + true, or after all the iterator functions have finished. Result will be + either true or false depending on the values of the async tests. + +__Example__ + +```js +async.some(['file1','file2','file3'], fs.exists, function(result){ + // if result is true then at least one of the files exists +}); +``` + +--------------------------------------- + + +### every(arr, iterator, callback) + +__Alias:__ all + +Returns true if every element in the array satisfies an async test. +_The callback for each iterator call only accepts a single argument of true or +false, it does not accept an error argument first!_ This is in-line with the +way node libraries work with truth tests like fs.exists. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback(truthValue) which must be called with a + boolean argument once it has completed. +* callback(result) - A callback which is called after all the iterator + functions have finished. Result will be either true or false depending on + the values of the async tests. + +__Example__ + +```js +async.every(['file1','file2','file3'], fs.exists, function(result){ + // if result is true then every file exists +}); +``` + +--------------------------------------- + + +### concat(arr, iterator, callback) + +Applies an iterator to each item in a list, concatenating the results. Returns the +concatenated list. The iterators are called in parallel, and the results are +concatenated as they return. There is no guarantee that the results array will +be returned in the original order of the arguments passed to the iterator function. + +__Arguments__ + +* arr - An array to iterate over +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback(err, results) which must be called once it + has completed with an error (which can be null) and an array of results. +* callback(err, results) - A callback which is called after all the iterator + functions have finished, or an error has occurred. Results is an array containing + the concatenated results of the iterator function. + +__Example__ + +```js +async.concat(['dir1','dir2','dir3'], fs.readdir, function(err, files){ + // files is now a list of filenames that exist in the 3 directories +}); +``` + +--------------------------------------- + + +### concatSeries(arr, iterator, callback) + +Same as async.concat, but executes in series instead of parallel. + + +## Control Flow + + +### series(tasks, [callback]) + +Run an array of functions in series, each one running once the previous +function has completed. If any functions in the series pass an error to its +callback, no more functions are run and the callback for the series is +immediately called with the value of the error. Once the tasks have completed, +the results are passed to the final callback as an array. + +It is also possible to use an object instead of an array. Each property will be +run as a function and the results will be passed to the final callback as an object +instead of an array. This can be a more readable way of handling results from +async.series. + + +__Arguments__ + +* tasks - An array or object containing functions to run, each function is passed + a callback(err, result) it must call on completion with an error (which can + be null) and an optional result value. +* callback(err, results) - An optional callback to run once all the functions + have completed. This function gets a results array (or object) containing all + the result arguments passed to the task callbacks. + +__Example__ + +```js +async.series([ + function(callback){ + // do some stuff ... + callback(null, 'one'); + }, + function(callback){ + // do some more stuff ... + callback(null, 'two'); + } +], +// optional callback +function(err, results){ + // results is now equal to ['one', 'two'] +}); + + +// an example using an object instead of an array +async.series({ + one: function(callback){ + setTimeout(function(){ + callback(null, 1); + }, 200); + }, + two: function(callback){ + setTimeout(function(){ + callback(null, 2); + }, 100); + } +}, +function(err, results) { + // results is now equal to: {one: 1, two: 2} +}); +``` + +--------------------------------------- + + +### parallel(tasks, [callback]) + +Run an array of functions in parallel, without waiting until the previous +function has completed. If any of the functions pass an error to its +callback, the main callback is immediately called with the value of the error. +Once the tasks have completed, the results are passed to the final callback as an +array. + +It is also possible to use an object instead of an array. Each property will be +run as a function and the results will be passed to the final callback as an object +instead of an array. This can be a more readable way of handling results from +async.parallel. + + +__Arguments__ + +* tasks - An array or object containing functions to run, each function is passed + a callback(err, result) it must call on completion with an error (which can + be null) and an optional result value. +* callback(err, results) - An optional callback to run once all the functions + have completed. This function gets a results array (or object) containing all + the result arguments passed to the task callbacks. + +__Example__ + +```js +async.parallel([ + function(callback){ + setTimeout(function(){ + callback(null, 'one'); + }, 200); + }, + function(callback){ + setTimeout(function(){ + callback(null, 'two'); + }, 100); + } +], +// optional callback +function(err, results){ + // the results array will equal ['one','two'] even though + // the second function had a shorter timeout. +}); + + +// an example using an object instead of an array +async.parallel({ + one: function(callback){ + setTimeout(function(){ + callback(null, 1); + }, 200); + }, + two: function(callback){ + setTimeout(function(){ + callback(null, 2); + }, 100); + } +}, +function(err, results) { + // results is now equals to: {one: 1, two: 2} +}); +``` + +--------------------------------------- + + +### parallelLimit(tasks, limit, [callback]) + +The same as parallel only the tasks are executed in parallel with a maximum of "limit" +tasks executing at any time. + +Note that the tasks are not executed in batches, so there is no guarantee that +the first "limit" tasks will complete before any others are started. + +__Arguments__ + +* tasks - An array or object containing functions to run, each function is passed + a callback(err, result) it must call on completion with an error (which can + be null) and an optional result value. +* limit - The maximum number of tasks to run at any time. +* callback(err, results) - An optional callback to run once all the functions + have completed. This function gets a results array (or object) containing all + the result arguments passed to the task callbacks. + +--------------------------------------- + + +### whilst(test, fn, callback) + +Repeatedly call fn, while test returns true. Calls the callback when stopped, +or an error occurs. + +__Arguments__ + +* test() - synchronous truth test to perform before each execution of fn. +* fn(callback) - A function to call each time the test passes. The function is + passed a callback(err) which must be called once it has completed with an + optional error argument. +* callback(err) - A callback which is called after the test fails and repeated + execution of fn has stopped. + +__Example__ + +```js +var count = 0; + +async.whilst( + function () { return count < 5; }, + function (callback) { + count++; + setTimeout(callback, 1000); + }, + function (err) { + // 5 seconds have passed + } +); +``` + +--------------------------------------- + + +### doWhilst(fn, test, callback) + +The post check version of whilst. To reflect the difference in the order of operations `test` and `fn` arguments are switched. `doWhilst` is to `whilst` as `do while` is to `while` in plain JavaScript. + +--------------------------------------- + + +### until(test, fn, callback) + +Repeatedly call fn, until test returns true. Calls the callback when stopped, +or an error occurs. + +The inverse of async.whilst. + +--------------------------------------- + + +### doUntil(fn, test, callback) + +Like doWhilst except the test is inverted. Note the argument ordering differs from `until`. + +--------------------------------------- + + +### forever(fn, callback) + +Calls the asynchronous function 'fn' repeatedly, in series, indefinitely. +If an error is passed to fn's callback then 'callback' is called with the +error, otherwise it will never be called. + +--------------------------------------- + + +### waterfall(tasks, [callback]) + +Runs an array of functions in series, each passing their results to the next in +the array. However, if any of the functions pass an error to the callback, the +next function is not executed and the main callback is immediately called with +the error. + +__Arguments__ + +* tasks - An array of functions to run, each function is passed a + callback(err, result1, result2, ...) it must call on completion. The first + argument is an error (which can be null) and any further arguments will be + passed as arguments in order to the next task. +* callback(err, [results]) - An optional callback to run once all the functions + have completed. This will be passed the results of the last task's callback. + + + +__Example__ + +```js +async.waterfall([ + function(callback){ + callback(null, 'one', 'two'); + }, + function(arg1, arg2, callback){ + callback(null, 'three'); + }, + function(arg1, callback){ + // arg1 now equals 'three' + callback(null, 'done'); + } +], function (err, result) { + // result now equals 'done' +}); +``` + +--------------------------------------- + +### compose(fn1, fn2...) + +Creates a function which is a composition of the passed asynchronous +functions. Each function consumes the return value of the function that +follows. Composing functions f(), g() and h() would produce the result of +f(g(h())), only this version uses callbacks to obtain the return values. + +Each function is executed with the `this` binding of the composed function. + +__Arguments__ + +* functions... - the asynchronous functions to compose + + +__Example__ + +```js +function add1(n, callback) { + setTimeout(function () { + callback(null, n + 1); + }, 10); +} + +function mul3(n, callback) { + setTimeout(function () { + callback(null, n * 3); + }, 10); +} + +var add1mul3 = async.compose(mul3, add1); + +add1mul3(4, function (err, result) { + // result now equals 15 +}); +``` + +--------------------------------------- + +### applyEach(fns, args..., callback) + +Applies the provided arguments to each function in the array, calling the +callback after all functions have completed. If you only provide the first +argument then it will return a function which lets you pass in the +arguments as if it were a single function call. + +__Arguments__ + +* fns - the asynchronous functions to all call with the same arguments +* args... - any number of separate arguments to pass to the function +* callback - the final argument should be the callback, called when all + functions have completed processing + + +__Example__ + +```js +async.applyEach([enableSearch, updateSchema], 'bucket', callback); + +// partial application example: +async.each( + buckets, + async.applyEach([enableSearch, updateSchema]), + callback +); +``` + +--------------------------------------- + + +### applyEachSeries(arr, iterator, callback) + +The same as applyEach only the functions are applied in series. + +--------------------------------------- + + +### queue(worker, concurrency) + +Creates a queue object with the specified concurrency. Tasks added to the +queue will be processed in parallel (up to the concurrency limit). If all +workers are in progress, the task is queued until one is available. Once +a worker has completed a task, the task's callback is called. + +__Arguments__ + +* worker(task, callback) - An asynchronous function for processing a queued + task, which must call its callback(err) argument when finished, with an + optional error as an argument. +* concurrency - An integer for determining how many worker functions should be + run in parallel. + +__Queue objects__ + +The queue object returned by this function has the following properties and +methods: + +* length() - a function returning the number of items waiting to be processed. +* concurrency - an integer for determining how many worker functions should be + run in parallel. This property can be changed after a queue is created to + alter the concurrency on-the-fly. +* push(task, [callback]) - add a new task to the queue, the callback is called + once the worker has finished processing the task. + instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list. +* unshift(task, [callback]) - add a new task to the front of the queue. +* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued +* empty - a callback that is called when the last item from the queue is given to a worker +* drain - a callback that is called when the last item from the queue has returned from the worker + +__Example__ + +```js +// create a queue object with concurrency 2 + +var q = async.queue(function (task, callback) { + console.log('hello ' + task.name); + callback(); +}, 2); + + +// assign a callback +q.drain = function() { + console.log('all items have been processed'); +} + +// add some items to the queue + +q.push({name: 'foo'}, function (err) { + console.log('finished processing foo'); +}); +q.push({name: 'bar'}, function (err) { + console.log('finished processing bar'); +}); + +// add some items to the queue (batch-wise) + +q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function (err) { + console.log('finished processing bar'); +}); + +// add some items to the front of the queue + +q.unshift({name: 'bar'}, function (err) { + console.log('finished processing bar'); +}); +``` + +--------------------------------------- + + +### cargo(worker, [payload]) + +Creates a cargo object with the specified payload. Tasks added to the +cargo will be processed altogether (up to the payload limit). If the +worker is in progress, the task is queued until it is available. Once +the worker has completed some tasks, each callback of those tasks is called. + +__Arguments__ + +* worker(tasks, callback) - An asynchronous function for processing an array of + queued tasks, which must call its callback(err) argument when finished, with + an optional error as an argument. +* payload - An optional integer for determining how many tasks should be + processed per round; if omitted, the default is unlimited. + +__Cargo objects__ + +The cargo object returned by this function has the following properties and +methods: + +* length() - a function returning the number of items waiting to be processed. +* payload - an integer for determining how many tasks should be + process per round. This property can be changed after a cargo is created to + alter the payload on-the-fly. +* push(task, [callback]) - add a new task to the queue, the callback is called + once the worker has finished processing the task. + instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list. +* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued +* empty - a callback that is called when the last item from the queue is given to a worker +* drain - a callback that is called when the last item from the queue has returned from the worker + +__Example__ + +```js +// create a cargo object with payload 2 + +var cargo = async.cargo(function (tasks, callback) { + for(var i=0; i +### auto(tasks, [callback]) + +Determines the best order for running functions based on their requirements. +Each function can optionally depend on other functions being completed first, +and each function is run as soon as its requirements are satisfied. If any of +the functions pass an error to their callback, that function will not complete +(so any other functions depending on it will not run) and the main callback +will be called immediately with the error. Functions also receive an object +containing the results of functions which have completed so far. + +Note, all functions are called with a results object as a second argument, +so it is unsafe to pass functions in the tasks object which cannot handle the +extra argument. For example, this snippet of code: + +```js +async.auto({ + readData: async.apply(fs.readFile, 'data.txt', 'utf-8'); +}, callback); +``` + +will have the effect of calling readFile with the results object as the last +argument, which will fail: + +```js +fs.readFile('data.txt', 'utf-8', cb, {}); +``` + +Instead, wrap the call to readFile in a function which does not forward the +results object: + +```js +async.auto({ + readData: function(cb, results){ + fs.readFile('data.txt', 'utf-8', cb); + } +}, callback); +``` + +__Arguments__ + +* tasks - An object literal containing named functions or an array of + requirements, with the function itself the last item in the array. The key + used for each function or array is used when specifying requirements. The + function receives two arguments: (1) a callback(err, result) which must be + called when finished, passing an error (which can be null) and the result of + the function's execution, and (2) a results object, containing the results of + the previously executed functions. +* callback(err, results) - An optional callback which is called when all the + tasks have been completed. The callback will receive an error as an argument + if any tasks pass an error to their callback. Results will always be passed + but if an error occurred, no other tasks will be performed, and the results + object will only contain partial results. + + +__Example__ + +```js +async.auto({ + get_data: function(callback){ + // async code to get some data + }, + make_folder: function(callback){ + // async code to create a directory to store a file in + // this is run at the same time as getting the data + }, + write_file: ['get_data', 'make_folder', function(callback){ + // once there is some data and the directory exists, + // write the data to a file in the directory + callback(null, filename); + }], + email_link: ['write_file', function(callback, results){ + // once the file is written let's email a link to it... + // results.write_file contains the filename returned by write_file. + }] +}); +``` + +This is a fairly trivial example, but to do this using the basic parallel and +series functions would look like this: + +```js +async.parallel([ + function(callback){ + // async code to get some data + }, + function(callback){ + // async code to create a directory to store a file in + // this is run at the same time as getting the data + } +], +function(err, results){ + async.series([ + function(callback){ + // once there is some data and the directory exists, + // write the data to a file in the directory + }, + function(callback){ + // once the file is written let's email a link to it... + } + ]); +}); +``` + +For a complicated series of async tasks using the auto function makes adding +new tasks much easier and makes the code more readable. + + +--------------------------------------- + + +### iterator(tasks) + +Creates an iterator function which calls the next function in the array, +returning a continuation to call the next one after that. It's also possible to +'peek' the next iterator by doing iterator.next(). + +This function is used internally by the async module but can be useful when +you want to manually control the flow of functions in series. + +__Arguments__ + +* tasks - An array of functions to run. + +__Example__ + +```js +var iterator = async.iterator([ + function(){ sys.p('one'); }, + function(){ sys.p('two'); }, + function(){ sys.p('three'); } +]); + +node> var iterator2 = iterator(); +'one' +node> var iterator3 = iterator2(); +'two' +node> iterator3(); +'three' +node> var nextfn = iterator2.next(); +node> nextfn(); +'three' +``` + +--------------------------------------- + + +### apply(function, arguments..) + +Creates a continuation function with some arguments already applied, a useful +shorthand when combined with other control flow functions. Any arguments +passed to the returned function are added to the arguments originally passed +to apply. + +__Arguments__ + +* function - The function you want to eventually apply all arguments to. +* arguments... - Any number of arguments to automatically apply when the + continuation is called. + +__Example__ + +```js +// using apply + +async.parallel([ + async.apply(fs.writeFile, 'testfile1', 'test1'), + async.apply(fs.writeFile, 'testfile2', 'test2'), +]); + + +// the same process without using apply + +async.parallel([ + function(callback){ + fs.writeFile('testfile1', 'test1', callback); + }, + function(callback){ + fs.writeFile('testfile2', 'test2', callback); + } +]); +``` + +It's possible to pass any number of additional arguments when calling the +continuation: + +```js +node> var fn = async.apply(sys.puts, 'one'); +node> fn('two', 'three'); +one +two +three +``` + +--------------------------------------- + + +### nextTick(callback) + +Calls the callback on a later loop around the event loop. In node.js this just +calls process.nextTick, in the browser it falls back to setImmediate(callback) +if available, otherwise setTimeout(callback, 0), which means other higher priority +events may precede the execution of the callback. + +This is used internally for browser-compatibility purposes. + +__Arguments__ + +* callback - The function to call on a later loop around the event loop. + +__Example__ + +```js +var call_order = []; +async.nextTick(function(){ + call_order.push('two'); + // call_order now equals ['one','two'] +}); +call_order.push('one') +``` + + +### times(n, callback) + +Calls the callback n times and accumulates results in the same manner +you would use with async.map. + +__Arguments__ + +* n - The number of times to run the function. +* callback - The function to call n times. + +__Example__ + +```js +// Pretend this is some complicated async factory +var createUser = function(id, callback) { + callback(null, { + id: 'user' + id + }) +} +// generate 5 users +async.times(5, function(n, next){ + createUser(n, function(err, user) { + next(err, user) + }) +}, function(err, users) { + // we should now have 5 users +}); +``` + + +### timesSeries(n, callback) + +The same as times only the iterator is applied to each item in the array in +series. The next iterator is only called once the current one has completed +processing. The results array will be in the same order as the original. + + +## Utils + + +### memoize(fn, [hasher]) + +Caches the results of an async function. When creating a hash to store function +results against, the callback is omitted from the hash and an optional hash +function can be used. + +The cache of results is exposed as the `memo` property of the function returned +by `memoize`. + +__Arguments__ + +* fn - the function you to proxy and cache results from. +* hasher - an optional function for generating a custom hash for storing + results, it has all the arguments applied to it apart from the callback, and + must be synchronous. + +__Example__ + +```js +var slow_fn = function (name, callback) { + // do something + callback(null, result); +}; +var fn = async.memoize(slow_fn); + +// fn can now be used as if it were slow_fn +fn('some name', function () { + // callback +}); +``` + + +### unmemoize(fn) + +Undoes a memoized function, reverting it to the original, unmemoized +form. Comes handy in tests. + +__Arguments__ + +* fn - the memoized function + + +### log(function, arguments) + +Logs the result of an async function to the console. Only works in node.js or +in browsers that support console.log and console.error (such as FF and Chrome). +If multiple arguments are returned from the async function, console.log is +called on each argument in order. + +__Arguments__ + +* function - The function you want to eventually apply all arguments to. +* arguments... - Any number of arguments to apply to the function. + +__Example__ + +```js +var hello = function(name, callback){ + setTimeout(function(){ + callback(null, 'hello ' + name); + }, 1000); +}; +``` +```js +node> async.log(hello, 'world'); +'hello world' +``` + +--------------------------------------- + + +### dir(function, arguments) + +Logs the result of an async function to the console using console.dir to +display the properties of the resulting object. Only works in node.js or +in browsers that support console.dir and console.error (such as FF and Chrome). +If multiple arguments are returned from the async function, console.dir is +called on each argument in order. + +__Arguments__ + +* function - The function you want to eventually apply all arguments to. +* arguments... - Any number of arguments to apply to the function. + +__Example__ + +```js +var hello = function(name, callback){ + setTimeout(function(){ + callback(null, {hello: name}); + }, 1000); +}; +``` +```js +node> async.dir(hello, 'world'); +{hello: 'world'} +``` + +--------------------------------------- + + +### noConflict() + +Changes the value of async back to its original value, returning a reference to the +async object. diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/async/component.json b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/async/component.json new file mode 100644 index 0000000..bbb0115 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/async/component.json @@ -0,0 +1,11 @@ +{ + "name": "async", + "repo": "caolan/async", + "description": "Higher-order functions and common patterns for asynchronous code", + "version": "0.1.23", + "keywords": [], + "dependencies": {}, + "development": {}, + "main": "lib/async.js", + "scripts": [ "lib/async.js" ] +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/async/lib/async.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/async/lib/async.js new file mode 100755 index 0000000..cb6320d --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/async/lib/async.js @@ -0,0 +1,955 @@ +/*global setImmediate: false, setTimeout: false, console: false */ +(function () { + + var async = {}; + + // global on the server, window in the browser + var root, previous_async; + + root = this; + if (root != null) { + previous_async = root.async; + } + + async.noConflict = function () { + root.async = previous_async; + return async; + }; + + function only_once(fn) { + var called = false; + return function() { + if (called) throw new Error("Callback was already called."); + called = true; + fn.apply(root, arguments); + } + } + + //// cross-browser compatiblity functions //// + + var _each = function (arr, iterator) { + if (arr.forEach) { + return arr.forEach(iterator); + } + for (var i = 0; i < arr.length; i += 1) { + iterator(arr[i], i, arr); + } + }; + + var _map = function (arr, iterator) { + if (arr.map) { + return arr.map(iterator); + } + var results = []; + _each(arr, function (x, i, a) { + results.push(iterator(x, i, a)); + }); + return results; + }; + + var _reduce = function (arr, iterator, memo) { + if (arr.reduce) { + return arr.reduce(iterator, memo); + } + _each(arr, function (x, i, a) { + memo = iterator(memo, x, i, a); + }); + return memo; + }; + + var _keys = function (obj) { + if (Object.keys) { + return Object.keys(obj); + } + var keys = []; + for (var k in obj) { + if (obj.hasOwnProperty(k)) { + keys.push(k); + } + } + return keys; + }; + + //// exported async module functions //// + + //// nextTick implementation with browser-compatible fallback //// + if (typeof process === 'undefined' || !(process.nextTick)) { + if (typeof setImmediate === 'function') { + async.nextTick = function (fn) { + // not a direct alias for IE10 compatibility + setImmediate(fn); + }; + async.setImmediate = async.nextTick; + } + else { + async.nextTick = function (fn) { + setTimeout(fn, 0); + }; + async.setImmediate = async.nextTick; + } + } + else { + async.nextTick = process.nextTick; + if (typeof setImmediate !== 'undefined') { + async.setImmediate = setImmediate; + } + else { + async.setImmediate = async.nextTick; + } + } + + async.each = function (arr, iterator, callback) { + callback = callback || function () {}; + if (!arr.length) { + return callback(); + } + var completed = 0; + _each(arr, function (x) { + iterator(x, only_once(function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + if (completed >= arr.length) { + callback(null); + } + } + })); + }); + }; + async.forEach = async.each; + + async.eachSeries = function (arr, iterator, callback) { + callback = callback || function () {}; + if (!arr.length) { + return callback(); + } + var completed = 0; + var iterate = function () { + iterator(arr[completed], function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + if (completed >= arr.length) { + callback(null); + } + else { + iterate(); + } + } + }); + }; + iterate(); + }; + async.forEachSeries = async.eachSeries; + + async.eachLimit = function (arr, limit, iterator, callback) { + var fn = _eachLimit(limit); + fn.apply(null, [arr, iterator, callback]); + }; + async.forEachLimit = async.eachLimit; + + var _eachLimit = function (limit) { + + return function (arr, iterator, callback) { + callback = callback || function () {}; + if (!arr.length || limit <= 0) { + return callback(); + } + var completed = 0; + var started = 0; + var running = 0; + + (function replenish () { + if (completed >= arr.length) { + return callback(); + } + + while (running < limit && started < arr.length) { + started += 1; + running += 1; + iterator(arr[started - 1], function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + running -= 1; + if (completed >= arr.length) { + callback(); + } + else { + replenish(); + } + } + }); + } + })(); + }; + }; + + + var doParallel = function (fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [async.each].concat(args)); + }; + }; + var doParallelLimit = function(limit, fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [_eachLimit(limit)].concat(args)); + }; + }; + var doSeries = function (fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [async.eachSeries].concat(args)); + }; + }; + + + var _asyncMap = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (err, v) { + results[x.index] = v; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + }; + async.map = doParallel(_asyncMap); + async.mapSeries = doSeries(_asyncMap); + async.mapLimit = function (arr, limit, iterator, callback) { + return _mapLimit(limit)(arr, iterator, callback); + }; + + var _mapLimit = function(limit) { + return doParallelLimit(limit, _asyncMap); + }; + + // reduce only has a series version, as doing reduce in parallel won't + // work in many situations. + async.reduce = function (arr, memo, iterator, callback) { + async.eachSeries(arr, function (x, callback) { + iterator(memo, x, function (err, v) { + memo = v; + callback(err); + }); + }, function (err) { + callback(err, memo); + }); + }; + // inject alias + async.inject = async.reduce; + // foldl alias + async.foldl = async.reduce; + + async.reduceRight = function (arr, memo, iterator, callback) { + var reversed = _map(arr, function (x) { + return x; + }).reverse(); + async.reduce(reversed, memo, iterator, callback); + }; + // foldr alias + async.foldr = async.reduceRight; + + var _filter = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (v) { + if (v) { + results.push(x); + } + callback(); + }); + }, function (err) { + callback(_map(results.sort(function (a, b) { + return a.index - b.index; + }), function (x) { + return x.value; + })); + }); + }; + async.filter = doParallel(_filter); + async.filterSeries = doSeries(_filter); + // select alias + async.select = async.filter; + async.selectSeries = async.filterSeries; + + var _reject = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (v) { + if (!v) { + results.push(x); + } + callback(); + }); + }, function (err) { + callback(_map(results.sort(function (a, b) { + return a.index - b.index; + }), function (x) { + return x.value; + })); + }); + }; + async.reject = doParallel(_reject); + async.rejectSeries = doSeries(_reject); + + var _detect = function (eachfn, arr, iterator, main_callback) { + eachfn(arr, function (x, callback) { + iterator(x, function (result) { + if (result) { + main_callback(x); + main_callback = function () {}; + } + else { + callback(); + } + }); + }, function (err) { + main_callback(); + }); + }; + async.detect = doParallel(_detect); + async.detectSeries = doSeries(_detect); + + async.some = function (arr, iterator, main_callback) { + async.each(arr, function (x, callback) { + iterator(x, function (v) { + if (v) { + main_callback(true); + main_callback = function () {}; + } + callback(); + }); + }, function (err) { + main_callback(false); + }); + }; + // any alias + async.any = async.some; + + async.every = function (arr, iterator, main_callback) { + async.each(arr, function (x, callback) { + iterator(x, function (v) { + if (!v) { + main_callback(false); + main_callback = function () {}; + } + callback(); + }); + }, function (err) { + main_callback(true); + }); + }; + // all alias + async.all = async.every; + + async.sortBy = function (arr, iterator, callback) { + async.map(arr, function (x, callback) { + iterator(x, function (err, criteria) { + if (err) { + callback(err); + } + else { + callback(null, {value: x, criteria: criteria}); + } + }); + }, function (err, results) { + if (err) { + return callback(err); + } + else { + var fn = function (left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }; + callback(null, _map(results.sort(fn), function (x) { + return x.value; + })); + } + }); + }; + + async.auto = function (tasks, callback) { + callback = callback || function () {}; + var keys = _keys(tasks); + if (!keys.length) { + return callback(null); + } + + var results = {}; + + var listeners = []; + var addListener = function (fn) { + listeners.unshift(fn); + }; + var removeListener = function (fn) { + for (var i = 0; i < listeners.length; i += 1) { + if (listeners[i] === fn) { + listeners.splice(i, 1); + return; + } + } + }; + var taskComplete = function () { + _each(listeners.slice(0), function (fn) { + fn(); + }); + }; + + addListener(function () { + if (_keys(results).length === keys.length) { + callback(null, results); + callback = function () {}; + } + }); + + _each(keys, function (k) { + var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k]; + var taskCallback = function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + if (err) { + var safeResults = {}; + _each(_keys(results), function(rkey) { + safeResults[rkey] = results[rkey]; + }); + safeResults[k] = args; + callback(err, safeResults); + // stop subsequent errors hitting callback multiple times + callback = function () {}; + } + else { + results[k] = args; + async.setImmediate(taskComplete); + } + }; + var requires = task.slice(0, Math.abs(task.length - 1)) || []; + var ready = function () { + return _reduce(requires, function (a, x) { + return (a && results.hasOwnProperty(x)); + }, true) && !results.hasOwnProperty(k); + }; + if (ready()) { + task[task.length - 1](taskCallback, results); + } + else { + var listener = function () { + if (ready()) { + removeListener(listener); + task[task.length - 1](taskCallback, results); + } + }; + addListener(listener); + } + }); + }; + + async.waterfall = function (tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor !== Array) { + var err = new Error('First argument to waterfall must be an array of functions'); + return callback(err); + } + if (!tasks.length) { + return callback(); + } + var wrapIterator = function (iterator) { + return function (err) { + if (err) { + callback.apply(null, arguments); + callback = function () {}; + } + else { + var args = Array.prototype.slice.call(arguments, 1); + var next = iterator.next(); + if (next) { + args.push(wrapIterator(next)); + } + else { + args.push(callback); + } + async.setImmediate(function () { + iterator.apply(null, args); + }); + } + }; + }; + wrapIterator(async.iterator(tasks))(); + }; + + var _parallel = function(eachfn, tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor === Array) { + eachfn.map(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args); + }); + } + }, callback); + } + else { + var results = {}; + eachfn.each(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.parallel = function (tasks, callback) { + _parallel({ map: async.map, each: async.each }, tasks, callback); + }; + + async.parallelLimit = function(tasks, limit, callback) { + _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback); + }; + + async.series = function (tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor === Array) { + async.mapSeries(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args); + }); + } + }, callback); + } + else { + var results = {}; + async.eachSeries(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.iterator = function (tasks) { + var makeCallback = function (index) { + var fn = function () { + if (tasks.length) { + tasks[index].apply(null, arguments); + } + return fn.next(); + }; + fn.next = function () { + return (index < tasks.length - 1) ? makeCallback(index + 1): null; + }; + return fn; + }; + return makeCallback(0); + }; + + async.apply = function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + return function () { + return fn.apply( + null, args.concat(Array.prototype.slice.call(arguments)) + ); + }; + }; + + var _concat = function (eachfn, arr, fn, callback) { + var r = []; + eachfn(arr, function (x, cb) { + fn(x, function (err, y) { + r = r.concat(y || []); + cb(err); + }); + }, function (err) { + callback(err, r); + }); + }; + async.concat = doParallel(_concat); + async.concatSeries = doSeries(_concat); + + async.whilst = function (test, iterator, callback) { + if (test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.whilst(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.doWhilst = function (iterator, test, callback) { + iterator(function (err) { + if (err) { + return callback(err); + } + if (test()) { + async.doWhilst(iterator, test, callback); + } + else { + callback(); + } + }); + }; + + async.until = function (test, iterator, callback) { + if (!test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.until(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.doUntil = function (iterator, test, callback) { + iterator(function (err) { + if (err) { + return callback(err); + } + if (!test()) { + async.doUntil(iterator, test, callback); + } + else { + callback(); + } + }); + }; + + async.queue = function (worker, concurrency) { + if (concurrency === undefined) { + concurrency = 1; + } + function _insert(q, data, pos, callback) { + if(data.constructor !== Array) { + data = [data]; + } + _each(data, function(task) { + var item = { + data: task, + callback: typeof callback === 'function' ? callback : null + }; + + if (pos) { + q.tasks.unshift(item); + } else { + q.tasks.push(item); + } + + if (q.saturated && q.tasks.length === concurrency) { + q.saturated(); + } + async.setImmediate(q.process); + }); + } + + var workers = 0; + var q = { + tasks: [], + concurrency: concurrency, + saturated: null, + empty: null, + drain: null, + push: function (data, callback) { + _insert(q, data, false, callback); + }, + unshift: function (data, callback) { + _insert(q, data, true, callback); + }, + process: function () { + if (workers < q.concurrency && q.tasks.length) { + var task = q.tasks.shift(); + if (q.empty && q.tasks.length === 0) { + q.empty(); + } + workers += 1; + var next = function () { + workers -= 1; + if (task.callback) { + task.callback.apply(task, arguments); + } + if (q.drain && q.tasks.length + workers === 0) { + q.drain(); + } + q.process(); + }; + var cb = only_once(next); + worker(task.data, cb); + } + }, + length: function () { + return q.tasks.length; + }, + running: function () { + return workers; + } + }; + return q; + }; + + async.cargo = function (worker, payload) { + var working = false, + tasks = []; + + var cargo = { + tasks: tasks, + payload: payload, + saturated: null, + empty: null, + drain: null, + push: function (data, callback) { + if(data.constructor !== Array) { + data = [data]; + } + _each(data, function(task) { + tasks.push({ + data: task, + callback: typeof callback === 'function' ? callback : null + }); + if (cargo.saturated && tasks.length === payload) { + cargo.saturated(); + } + }); + async.setImmediate(cargo.process); + }, + process: function process() { + if (working) return; + if (tasks.length === 0) { + if(cargo.drain) cargo.drain(); + return; + } + + var ts = typeof payload === 'number' + ? tasks.splice(0, payload) + : tasks.splice(0); + + var ds = _map(ts, function (task) { + return task.data; + }); + + if(cargo.empty) cargo.empty(); + working = true; + worker(ds, function () { + working = false; + + var args = arguments; + _each(ts, function (data) { + if (data.callback) { + data.callback.apply(null, args); + } + }); + + process(); + }); + }, + length: function () { + return tasks.length; + }, + running: function () { + return working; + } + }; + return cargo; + }; + + var _console_fn = function (name) { + return function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + fn.apply(null, args.concat([function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (typeof console !== 'undefined') { + if (err) { + if (console.error) { + console.error(err); + } + } + else if (console[name]) { + _each(args, function (x) { + console[name](x); + }); + } + } + }])); + }; + }; + async.log = _console_fn('log'); + async.dir = _console_fn('dir'); + /*async.info = _console_fn('info'); + async.warn = _console_fn('warn'); + async.error = _console_fn('error');*/ + + async.memoize = function (fn, hasher) { + var memo = {}; + var queues = {}; + hasher = hasher || function (x) { + return x; + }; + var memoized = function () { + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + var key = hasher.apply(null, args); + if (key in memo) { + callback.apply(null, memo[key]); + } + else if (key in queues) { + queues[key].push(callback); + } + else { + queues[key] = [callback]; + fn.apply(null, args.concat([function () { + memo[key] = arguments; + var q = queues[key]; + delete queues[key]; + for (var i = 0, l = q.length; i < l; i++) { + q[i].apply(null, arguments); + } + }])); + } + }; + memoized.memo = memo; + memoized.unmemoized = fn; + return memoized; + }; + + async.unmemoize = function (fn) { + return function () { + return (fn.unmemoized || fn).apply(null, arguments); + }; + }; + + async.times = function (count, iterator, callback) { + var counter = []; + for (var i = 0; i < count; i++) { + counter.push(i); + } + return async.map(counter, iterator, callback); + }; + + async.timesSeries = function (count, iterator, callback) { + var counter = []; + for (var i = 0; i < count; i++) { + counter.push(i); + } + return async.mapSeries(counter, iterator, callback); + }; + + async.compose = function (/* functions... */) { + var fns = Array.prototype.reverse.call(arguments); + return function () { + var that = this; + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + async.reduce(fns, args, function (newargs, fn, cb) { + fn.apply(that, newargs.concat([function () { + var err = arguments[0]; + var nextargs = Array.prototype.slice.call(arguments, 1); + cb(err, nextargs); + }])) + }, + function (err, results) { + callback.apply(that, [err].concat(results)); + }); + }; + }; + + var _applyEach = function (eachfn, fns /*args...*/) { + var go = function () { + var that = this; + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + return eachfn(fns, function (fn, cb) { + fn.apply(that, args.concat([cb])); + }, + callback); + }; + if (arguments.length > 2) { + var args = Array.prototype.slice.call(arguments, 2); + return go.apply(this, args); + } + else { + return go; + } + }; + async.applyEach = doParallel(_applyEach); + async.applyEachSeries = doSeries(_applyEach); + + async.forever = function (fn, callback) { + function next(err) { + if (err) { + if (callback) { + return callback(err); + } + throw err; + } + fn(next); + } + next(); + }; + + // AMD / RequireJS + if (typeof define !== 'undefined' && define.amd) { + define([], function () { + return async; + }); + } + // Node.js + else if (typeof module !== 'undefined' && module.exports) { + module.exports = async; + } + // included directly via \n\n```\n\n## Documentation\n\n### Collections\n\n* [each](#each)\n* [map](#map)\n* [filter](#filter)\n* [reject](#reject)\n* [reduce](#reduce)\n* [detect](#detect)\n* [sortBy](#sortBy)\n* [some](#some)\n* [every](#every)\n* [concat](#concat)\n\n### Control Flow\n\n* [series](#series)\n* [parallel](#parallel)\n* [whilst](#whilst)\n* [doWhilst](#doWhilst)\n* [until](#until)\n* [doUntil](#doUntil)\n* [forever](#forever)\n* [waterfall](#waterfall)\n* [compose](#compose)\n* [applyEach](#applyEach)\n* [queue](#queue)\n* [cargo](#cargo)\n* [auto](#auto)\n* [iterator](#iterator)\n* [apply](#apply)\n* [nextTick](#nextTick)\n* [times](#times)\n* [timesSeries](#timesSeries)\n\n### Utils\n\n* [memoize](#memoize)\n* [unmemoize](#unmemoize)\n* [log](#log)\n* [dir](#dir)\n* [noConflict](#noConflict)\n\n\n## Collections\n\n\n\n### each(arr, iterator, callback)\n\nApplies an iterator function to each item in an array, in parallel.\nThe iterator is called with an item from the list and a callback for when it\nhas finished. If the iterator passes an error to this callback, the main\ncallback for the each function is immediately called with the error.\n\nNote, that since this function applies the iterator to each item in parallel\nthere is no guarantee that the iterator functions will complete in order.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback(err) which must be called once it has \n completed. If no error has occured, the callback should be run without \n arguments or with an explicit null argument.\n* callback(err) - A callback which is called after all the iterator functions\n have finished, or an error has occurred.\n\n__Example__\n\n```js\n// assuming openFiles is an array of file names and saveFile is a function\n// to save the modified contents of that file:\n\nasync.each(openFiles, saveFile, function(err){\n // if any of the saves produced an error, err would equal that error\n});\n```\n\n---------------------------------------\n\n\n\n### eachSeries(arr, iterator, callback)\n\nThe same as each only the iterator is applied to each item in the array in\nseries. The next iterator is only called once the current one has completed\nprocessing. This means the iterator functions will complete in order.\n\n\n---------------------------------------\n\n\n\n### eachLimit(arr, limit, iterator, callback)\n\nThe same as each only no more than \"limit\" iterators will be simultaneously \nrunning at any time.\n\nNote that the items are not processed in batches, so there is no guarantee that\n the first \"limit\" iterator functions will complete before any others are \nstarted.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* limit - The maximum number of iterators to run at any time.\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback(err) which must be called once it has \n completed. If no error has occured, the callback should be run without \n arguments or with an explicit null argument.\n* callback(err) - A callback which is called after all the iterator functions\n have finished, or an error has occurred.\n\n__Example__\n\n```js\n// Assume documents is an array of JSON objects and requestApi is a\n// function that interacts with a rate-limited REST api.\n\nasync.eachLimit(documents, 20, requestApi, function(err){\n // if any of the saves produced an error, err would equal that error\n});\n```\n\n---------------------------------------\n\n\n### map(arr, iterator, callback)\n\nProduces a new array of values by mapping each value in the given array through\nthe iterator function. The iterator is called with an item from the array and a\ncallback for when it has finished processing. The callback takes 2 arguments, \nan error and the transformed item from the array. If the iterator passes an\nerror to this callback, the main callback for the map function is immediately\ncalled with the error.\n\nNote, that since this function applies the iterator to each item in parallel\nthere is no guarantee that the iterator functions will complete in order, however\nthe results array will be in the same order as the original array.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback(err, transformed) which must be called once \n it has completed with an error (which can be null) and a transformed item.\n* callback(err, results) - A callback which is called after all the iterator\n functions have finished, or an error has occurred. Results is an array of the\n transformed items from the original array.\n\n__Example__\n\n```js\nasync.map(['file1','file2','file3'], fs.stat, function(err, results){\n // results is now an array of stats for each file\n});\n```\n\n---------------------------------------\n\n\n### mapSeries(arr, iterator, callback)\n\nThe same as map only the iterator is applied to each item in the array in\nseries. The next iterator is only called once the current one has completed\nprocessing. The results array will be in the same order as the original.\n\n\n---------------------------------------\n\n\n### mapLimit(arr, limit, iterator, callback)\n\nThe same as map only no more than \"limit\" iterators will be simultaneously \nrunning at any time.\n\nNote that the items are not processed in batches, so there is no guarantee that\n the first \"limit\" iterator functions will complete before any others are \nstarted.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* limit - The maximum number of iterators to run at any time.\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback(err, transformed) which must be called once \n it has completed with an error (which can be null) and a transformed item.\n* callback(err, results) - A callback which is called after all the iterator\n functions have finished, or an error has occurred. Results is an array of the\n transformed items from the original array.\n\n__Example__\n\n```js\nasync.map(['file1','file2','file3'], 1, fs.stat, function(err, results){\n // results is now an array of stats for each file\n});\n```\n\n---------------------------------------\n\n\n### filter(arr, iterator, callback)\n\n__Alias:__ select\n\nReturns a new array of all the values which pass an async truth test.\n_The callback for each iterator call only accepts a single argument of true or\nfalse, it does not accept an error argument first!_ This is in-line with the\nway node libraries work with truth tests like fs.exists. This operation is\nperformed in parallel, but the results array will be in the same order as the\noriginal.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n The iterator is passed a callback(truthValue) which must be called with a \n boolean argument once it has completed.\n* callback(results) - A callback which is called after all the iterator\n functions have finished.\n\n__Example__\n\n```js\nasync.filter(['file1','file2','file3'], fs.exists, function(results){\n // results now equals an array of the existing files\n});\n```\n\n---------------------------------------\n\n\n### filterSeries(arr, iterator, callback)\n\n__alias:__ selectSeries\n\nThe same as filter only the iterator is applied to each item in the array in\nseries. The next iterator is only called once the current one has completed\nprocessing. The results array will be in the same order as the original.\n\n---------------------------------------\n\n\n### reject(arr, iterator, callback)\n\nThe opposite of filter. Removes values that pass an async truth test.\n\n---------------------------------------\n\n\n### rejectSeries(arr, iterator, callback)\n\nThe same as reject, only the iterator is applied to each item in the array\nin series.\n\n\n---------------------------------------\n\n\n### reduce(arr, memo, iterator, callback)\n\n__aliases:__ inject, foldl\n\nReduces a list of values into a single value using an async iterator to return\neach successive step. Memo is the initial state of the reduction. This\nfunction only operates in series. For performance reasons, it may make sense to\nsplit a call to this function into a parallel map, then use the normal\nArray.prototype.reduce on the results. This function is for situations where\neach step in the reduction needs to be async, if you can get the data before\nreducing it then it's probably a good idea to do so.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* memo - The initial state of the reduction.\n* iterator(memo, item, callback) - A function applied to each item in the\n array to produce the next step in the reduction. The iterator is passed a\n callback(err, reduction) which accepts an optional error as its first \n argument, and the state of the reduction as the second. If an error is \n passed to the callback, the reduction is stopped and the main callback is \n immediately called with the error.\n* callback(err, result) - A callback which is called after all the iterator\n functions have finished. Result is the reduced value.\n\n__Example__\n\n```js\nasync.reduce([1,2,3], 0, function(memo, item, callback){\n // pointless async:\n process.nextTick(function(){\n callback(null, memo + item)\n });\n}, function(err, result){\n // result is now equal to the last value of memo, which is 6\n});\n```\n\n---------------------------------------\n\n\n### reduceRight(arr, memo, iterator, callback)\n\n__Alias:__ foldr\n\nSame as reduce, only operates on the items in the array in reverse order.\n\n\n---------------------------------------\n\n\n### detect(arr, iterator, callback)\n\nReturns the first value in a list that passes an async truth test. The\niterator is applied in parallel, meaning the first iterator to return true will\nfire the detect callback with that result. That means the result might not be\nthe first item in the original array (in terms of order) that passes the test.\n\nIf order within the original array is important then look at detectSeries.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n The iterator is passed a callback(truthValue) which must be called with a \n boolean argument once it has completed.\n* callback(result) - A callback which is called as soon as any iterator returns\n true, or after all the iterator functions have finished. Result will be\n the first item in the array that passes the truth test (iterator) or the\n value undefined if none passed.\n\n__Example__\n\n```js\nasync.detect(['file1','file2','file3'], fs.exists, function(result){\n // result now equals the first file in the list that exists\n});\n```\n\n---------------------------------------\n\n\n### detectSeries(arr, iterator, callback)\n\nThe same as detect, only the iterator is applied to each item in the array\nin series. This means the result is always the first in the original array (in\nterms of array order) that passes the truth test.\n\n\n---------------------------------------\n\n\n### sortBy(arr, iterator, callback)\n\nSorts a list by the results of running each value through an async iterator.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback(err, sortValue) which must be called once it\n has completed with an error (which can be null) and a value to use as the sort\n criteria.\n* callback(err, results) - A callback which is called after all the iterator\n functions have finished, or an error has occurred. Results is the items from\n the original array sorted by the values returned by the iterator calls.\n\n__Example__\n\n```js\nasync.sortBy(['file1','file2','file3'], function(file, callback){\n fs.stat(file, function(err, stats){\n callback(err, stats.mtime);\n });\n}, function(err, results){\n // results is now the original array of files sorted by\n // modified date\n});\n```\n\n---------------------------------------\n\n\n### some(arr, iterator, callback)\n\n__Alias:__ any\n\nReturns true if at least one element in the array satisfies an async test.\n_The callback for each iterator call only accepts a single argument of true or\nfalse, it does not accept an error argument first!_ This is in-line with the\nway node libraries work with truth tests like fs.exists. Once any iterator\ncall returns true, the main callback is immediately called.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n The iterator is passed a callback(truthValue) which must be called with a \n boolean argument once it has completed.\n* callback(result) - A callback which is called as soon as any iterator returns\n true, or after all the iterator functions have finished. Result will be\n either true or false depending on the values of the async tests.\n\n__Example__\n\n```js\nasync.some(['file1','file2','file3'], fs.exists, function(result){\n // if result is true then at least one of the files exists\n});\n```\n\n---------------------------------------\n\n\n### every(arr, iterator, callback)\n\n__Alias:__ all\n\nReturns true if every element in the array satisfies an async test.\n_The callback for each iterator call only accepts a single argument of true or\nfalse, it does not accept an error argument first!_ This is in-line with the\nway node libraries work with truth tests like fs.exists.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n The iterator is passed a callback(truthValue) which must be called with a \n boolean argument once it has completed.\n* callback(result) - A callback which is called after all the iterator\n functions have finished. Result will be either true or false depending on\n the values of the async tests.\n\n__Example__\n\n```js\nasync.every(['file1','file2','file3'], fs.exists, function(result){\n // if result is true then every file exists\n});\n```\n\n---------------------------------------\n\n\n### concat(arr, iterator, callback)\n\nApplies an iterator to each item in a list, concatenating the results. Returns the\nconcatenated list. The iterators are called in parallel, and the results are\nconcatenated as they return. There is no guarantee that the results array will\nbe returned in the original order of the arguments passed to the iterator function.\n\n__Arguments__\n\n* arr - An array to iterate over\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback(err, results) which must be called once it \n has completed with an error (which can be null) and an array of results.\n* callback(err, results) - A callback which is called after all the iterator\n functions have finished, or an error has occurred. Results is an array containing\n the concatenated results of the iterator function.\n\n__Example__\n\n```js\nasync.concat(['dir1','dir2','dir3'], fs.readdir, function(err, files){\n // files is now a list of filenames that exist in the 3 directories\n});\n```\n\n---------------------------------------\n\n\n### concatSeries(arr, iterator, callback)\n\nSame as async.concat, but executes in series instead of parallel.\n\n\n## Control Flow\n\n\n### series(tasks, [callback])\n\nRun an array of functions in series, each one running once the previous\nfunction has completed. If any functions in the series pass an error to its\ncallback, no more functions are run and the callback for the series is\nimmediately called with the value of the error. Once the tasks have completed,\nthe results are passed to the final callback as an array.\n\nIt is also possible to use an object instead of an array. Each property will be\nrun as a function and the results will be passed to the final callback as an object\ninstead of an array. This can be a more readable way of handling results from\nasync.series.\n\n\n__Arguments__\n\n* tasks - An array or object containing functions to run, each function is passed\n a callback(err, result) it must call on completion with an error (which can\n be null) and an optional result value.\n* callback(err, results) - An optional callback to run once all the functions\n have completed. This function gets a results array (or object) containing all \n the result arguments passed to the task callbacks.\n\n__Example__\n\n```js\nasync.series([\n function(callback){\n // do some stuff ...\n callback(null, 'one');\n },\n function(callback){\n // do some more stuff ...\n callback(null, 'two');\n }\n],\n// optional callback\nfunction(err, results){\n // results is now equal to ['one', 'two']\n});\n\n\n// an example using an object instead of an array\nasync.series({\n one: function(callback){\n setTimeout(function(){\n callback(null, 1);\n }, 200);\n },\n two: function(callback){\n setTimeout(function(){\n callback(null, 2);\n }, 100);\n }\n},\nfunction(err, results) {\n // results is now equal to: {one: 1, two: 2}\n});\n```\n\n---------------------------------------\n\n\n### parallel(tasks, [callback])\n\nRun an array of functions in parallel, without waiting until the previous\nfunction has completed. If any of the functions pass an error to its\ncallback, the main callback is immediately called with the value of the error.\nOnce the tasks have completed, the results are passed to the final callback as an\narray.\n\nIt is also possible to use an object instead of an array. Each property will be\nrun as a function and the results will be passed to the final callback as an object\ninstead of an array. This can be a more readable way of handling results from\nasync.parallel.\n\n\n__Arguments__\n\n* tasks - An array or object containing functions to run, each function is passed \n a callback(err, result) it must call on completion with an error (which can\n be null) and an optional result value.\n* callback(err, results) - An optional callback to run once all the functions\n have completed. This function gets a results array (or object) containing all \n the result arguments passed to the task callbacks.\n\n__Example__\n\n```js\nasync.parallel([\n function(callback){\n setTimeout(function(){\n callback(null, 'one');\n }, 200);\n },\n function(callback){\n setTimeout(function(){\n callback(null, 'two');\n }, 100);\n }\n],\n// optional callback\nfunction(err, results){\n // the results array will equal ['one','two'] even though\n // the second function had a shorter timeout.\n});\n\n\n// an example using an object instead of an array\nasync.parallel({\n one: function(callback){\n setTimeout(function(){\n callback(null, 1);\n }, 200);\n },\n two: function(callback){\n setTimeout(function(){\n callback(null, 2);\n }, 100);\n }\n},\nfunction(err, results) {\n // results is now equals to: {one: 1, two: 2}\n});\n```\n\n---------------------------------------\n\n\n### parallelLimit(tasks, limit, [callback])\n\nThe same as parallel only the tasks are executed in parallel with a maximum of \"limit\" \ntasks executing at any time.\n\nNote that the tasks are not executed in batches, so there is no guarantee that \nthe first \"limit\" tasks will complete before any others are started.\n\n__Arguments__\n\n* tasks - An array or object containing functions to run, each function is passed \n a callback(err, result) it must call on completion with an error (which can\n be null) and an optional result value.\n* limit - The maximum number of tasks to run at any time.\n* callback(err, results) - An optional callback to run once all the functions\n have completed. This function gets a results array (or object) containing all \n the result arguments passed to the task callbacks.\n\n---------------------------------------\n\n\n### whilst(test, fn, callback)\n\nRepeatedly call fn, while test returns true. Calls the callback when stopped,\nor an error occurs.\n\n__Arguments__\n\n* test() - synchronous truth test to perform before each execution of fn.\n* fn(callback) - A function to call each time the test passes. The function is\n passed a callback(err) which must be called once it has completed with an \n optional error argument.\n* callback(err) - A callback which is called after the test fails and repeated\n execution of fn has stopped.\n\n__Example__\n\n```js\nvar count = 0;\n\nasync.whilst(\n function () { return count < 5; },\n function (callback) {\n count++;\n setTimeout(callback, 1000);\n },\n function (err) {\n // 5 seconds have passed\n }\n);\n```\n\n---------------------------------------\n\n\n### doWhilst(fn, test, callback)\n\nThe post check version of whilst. To reflect the difference in the order of operations `test` and `fn` arguments are switched. `doWhilst` is to `whilst` as `do while` is to `while` in plain JavaScript.\n\n---------------------------------------\n\n\n### until(test, fn, callback)\n\nRepeatedly call fn, until test returns true. Calls the callback when stopped,\nor an error occurs.\n\nThe inverse of async.whilst.\n\n---------------------------------------\n\n\n### doUntil(fn, test, callback)\n\nLike doWhilst except the test is inverted. Note the argument ordering differs from `until`.\n\n---------------------------------------\n\n\n### forever(fn, callback)\n\nCalls the asynchronous function 'fn' repeatedly, in series, indefinitely.\nIf an error is passed to fn's callback then 'callback' is called with the\nerror, otherwise it will never be called.\n\n---------------------------------------\n\n\n### waterfall(tasks, [callback])\n\nRuns an array of functions in series, each passing their results to the next in\nthe array. However, if any of the functions pass an error to the callback, the\nnext function is not executed and the main callback is immediately called with\nthe error.\n\n__Arguments__\n\n* tasks - An array of functions to run, each function is passed a \n callback(err, result1, result2, ...) it must call on completion. The first\n argument is an error (which can be null) and any further arguments will be \n passed as arguments in order to the next task.\n* callback(err, [results]) - An optional callback to run once all the functions\n have completed. This will be passed the results of the last task's callback.\n\n\n\n__Example__\n\n```js\nasync.waterfall([\n function(callback){\n callback(null, 'one', 'two');\n },\n function(arg1, arg2, callback){\n callback(null, 'three');\n },\n function(arg1, callback){\n // arg1 now equals 'three'\n callback(null, 'done');\n }\n], function (err, result) {\n // result now equals 'done' \n});\n```\n\n---------------------------------------\n\n### compose(fn1, fn2...)\n\nCreates a function which is a composition of the passed asynchronous\nfunctions. Each function consumes the return value of the function that\nfollows. Composing functions f(), g() and h() would produce the result of\nf(g(h())), only this version uses callbacks to obtain the return values.\n\nEach function is executed with the `this` binding of the composed function.\n\n__Arguments__\n\n* functions... - the asynchronous functions to compose\n\n\n__Example__\n\n```js\nfunction add1(n, callback) {\n setTimeout(function () {\n callback(null, n + 1);\n }, 10);\n}\n\nfunction mul3(n, callback) {\n setTimeout(function () {\n callback(null, n * 3);\n }, 10);\n}\n\nvar add1mul3 = async.compose(mul3, add1);\n\nadd1mul3(4, function (err, result) {\n // result now equals 15\n});\n```\n\n---------------------------------------\n\n### applyEach(fns, args..., callback)\n\nApplies the provided arguments to each function in the array, calling the\ncallback after all functions have completed. If you only provide the first\nargument then it will return a function which lets you pass in the\narguments as if it were a single function call.\n\n__Arguments__\n\n* fns - the asynchronous functions to all call with the same arguments\n* args... - any number of separate arguments to pass to the function\n* callback - the final argument should be the callback, called when all\n functions have completed processing\n\n\n__Example__\n\n```js\nasync.applyEach([enableSearch, updateSchema], 'bucket', callback);\n\n// partial application example:\nasync.each(\n buckets,\n async.applyEach([enableSearch, updateSchema]),\n callback\n);\n```\n\n---------------------------------------\n\n\n### applyEachSeries(arr, iterator, callback)\n\nThe same as applyEach only the functions are applied in series.\n\n---------------------------------------\n\n\n### queue(worker, concurrency)\n\nCreates a queue object with the specified concurrency. Tasks added to the\nqueue will be processed in parallel (up to the concurrency limit). If all\nworkers are in progress, the task is queued until one is available. Once\na worker has completed a task, the task's callback is called.\n\n__Arguments__\n\n* worker(task, callback) - An asynchronous function for processing a queued\n task, which must call its callback(err) argument when finished, with an \n optional error as an argument.\n* concurrency - An integer for determining how many worker functions should be\n run in parallel.\n\n__Queue objects__\n\nThe queue object returned by this function has the following properties and\nmethods:\n\n* length() - a function returning the number of items waiting to be processed.\n* concurrency - an integer for determining how many worker functions should be\n run in parallel. This property can be changed after a queue is created to\n alter the concurrency on-the-fly.\n* push(task, [callback]) - add a new task to the queue, the callback is called\n once the worker has finished processing the task.\n instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list.\n* unshift(task, [callback]) - add a new task to the front of the queue.\n* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued\n* empty - a callback that is called when the last item from the queue is given to a worker\n* drain - a callback that is called when the last item from the queue has returned from the worker\n\n__Example__\n\n```js\n// create a queue object with concurrency 2\n\nvar q = async.queue(function (task, callback) {\n console.log('hello ' + task.name);\n callback();\n}, 2);\n\n\n// assign a callback\nq.drain = function() {\n console.log('all items have been processed');\n}\n\n// add some items to the queue\n\nq.push({name: 'foo'}, function (err) {\n console.log('finished processing foo');\n});\nq.push({name: 'bar'}, function (err) {\n console.log('finished processing bar');\n});\n\n// add some items to the queue (batch-wise)\n\nq.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function (err) {\n console.log('finished processing bar');\n});\n\n// add some items to the front of the queue\n\nq.unshift({name: 'bar'}, function (err) {\n console.log('finished processing bar');\n});\n```\n\n---------------------------------------\n\n\n### cargo(worker, [payload])\n\nCreates a cargo object with the specified payload. Tasks added to the\ncargo will be processed altogether (up to the payload limit). If the\nworker is in progress, the task is queued until it is available. Once\nthe worker has completed some tasks, each callback of those tasks is called.\n\n__Arguments__\n\n* worker(tasks, callback) - An asynchronous function for processing an array of\n queued tasks, which must call its callback(err) argument when finished, with \n an optional error as an argument.\n* payload - An optional integer for determining how many tasks should be\n processed per round; if omitted, the default is unlimited.\n\n__Cargo objects__\n\nThe cargo object returned by this function has the following properties and\nmethods:\n\n* length() - a function returning the number of items waiting to be processed.\n* payload - an integer for determining how many tasks should be\n process per round. This property can be changed after a cargo is created to\n alter the payload on-the-fly.\n* push(task, [callback]) - add a new task to the queue, the callback is called\n once the worker has finished processing the task.\n instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list.\n* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued\n* empty - a callback that is called when the last item from the queue is given to a worker\n* drain - a callback that is called when the last item from the queue has returned from the worker\n\n__Example__\n\n```js\n// create a cargo object with payload 2\n\nvar cargo = async.cargo(function (tasks, callback) {\n for(var i=0; i\n### auto(tasks, [callback])\n\nDetermines the best order for running functions based on their requirements.\nEach function can optionally depend on other functions being completed first,\nand each function is run as soon as its requirements are satisfied. If any of\nthe functions pass an error to their callback, that function will not complete\n(so any other functions depending on it will not run) and the main callback\nwill be called immediately with the error. Functions also receive an object\ncontaining the results of functions which have completed so far.\n\nNote, all functions are called with a results object as a second argument, \nso it is unsafe to pass functions in the tasks object which cannot handle the\nextra argument. For example, this snippet of code:\n\n```js\nasync.auto({\n readData: async.apply(fs.readFile, 'data.txt', 'utf-8');\n}, callback);\n```\n\nwill have the effect of calling readFile with the results object as the last\nargument, which will fail:\n\n```js\nfs.readFile('data.txt', 'utf-8', cb, {});\n```\n\nInstead, wrap the call to readFile in a function which does not forward the \nresults object:\n\n```js\nasync.auto({\n readData: function(cb, results){\n fs.readFile('data.txt', 'utf-8', cb);\n }\n}, callback);\n```\n\n__Arguments__\n\n* tasks - An object literal containing named functions or an array of\n requirements, with the function itself the last item in the array. The key\n used for each function or array is used when specifying requirements. The \n function receives two arguments: (1) a callback(err, result) which must be \n called when finished, passing an error (which can be null) and the result of \n the function's execution, and (2) a results object, containing the results of\n the previously executed functions.\n* callback(err, results) - An optional callback which is called when all the\n tasks have been completed. The callback will receive an error as an argument\n if any tasks pass an error to their callback. Results will always be passed\n\tbut if an error occurred, no other tasks will be performed, and the results\n\tobject will only contain partial results.\n \n\n__Example__\n\n```js\nasync.auto({\n get_data: function(callback){\n // async code to get some data\n },\n make_folder: function(callback){\n // async code to create a directory to store a file in\n // this is run at the same time as getting the data\n },\n write_file: ['get_data', 'make_folder', function(callback){\n // once there is some data and the directory exists,\n // write the data to a file in the directory\n callback(null, filename);\n }],\n email_link: ['write_file', function(callback, results){\n // once the file is written let's email a link to it...\n // results.write_file contains the filename returned by write_file.\n }]\n});\n```\n\nThis is a fairly trivial example, but to do this using the basic parallel and\nseries functions would look like this:\n\n```js\nasync.parallel([\n function(callback){\n // async code to get some data\n },\n function(callback){\n // async code to create a directory to store a file in\n // this is run at the same time as getting the data\n }\n],\nfunction(err, results){\n async.series([\n function(callback){\n // once there is some data and the directory exists,\n // write the data to a file in the directory\n },\n function(callback){\n // once the file is written let's email a link to it...\n }\n ]);\n});\n```\n\nFor a complicated series of async tasks using the auto function makes adding\nnew tasks much easier and makes the code more readable.\n\n\n---------------------------------------\n\n\n### iterator(tasks)\n\nCreates an iterator function which calls the next function in the array,\nreturning a continuation to call the next one after that. It's also possible to\n'peek' the next iterator by doing iterator.next().\n\nThis function is used internally by the async module but can be useful when\nyou want to manually control the flow of functions in series.\n\n__Arguments__\n\n* tasks - An array of functions to run.\n\n__Example__\n\n```js\nvar iterator = async.iterator([\n function(){ sys.p('one'); },\n function(){ sys.p('two'); },\n function(){ sys.p('three'); }\n]);\n\nnode> var iterator2 = iterator();\n'one'\nnode> var iterator3 = iterator2();\n'two'\nnode> iterator3();\n'three'\nnode> var nextfn = iterator2.next();\nnode> nextfn();\n'three'\n```\n\n---------------------------------------\n\n\n### apply(function, arguments..)\n\nCreates a continuation function with some arguments already applied, a useful\nshorthand when combined with other control flow functions. Any arguments\npassed to the returned function are added to the arguments originally passed\nto apply.\n\n__Arguments__\n\n* function - The function you want to eventually apply all arguments to.\n* arguments... - Any number of arguments to automatically apply when the\n continuation is called.\n\n__Example__\n\n```js\n// using apply\n\nasync.parallel([\n async.apply(fs.writeFile, 'testfile1', 'test1'),\n async.apply(fs.writeFile, 'testfile2', 'test2'),\n]);\n\n\n// the same process without using apply\n\nasync.parallel([\n function(callback){\n fs.writeFile('testfile1', 'test1', callback);\n },\n function(callback){\n fs.writeFile('testfile2', 'test2', callback);\n }\n]);\n```\n\nIt's possible to pass any number of additional arguments when calling the\ncontinuation:\n\n```js\nnode> var fn = async.apply(sys.puts, 'one');\nnode> fn('two', 'three');\none\ntwo\nthree\n```\n\n---------------------------------------\n\n\n### nextTick(callback)\n\nCalls the callback on a later loop around the event loop. In node.js this just\ncalls process.nextTick, in the browser it falls back to setImmediate(callback)\nif available, otherwise setTimeout(callback, 0), which means other higher priority\nevents may precede the execution of the callback.\n\nThis is used internally for browser-compatibility purposes.\n\n__Arguments__\n\n* callback - The function to call on a later loop around the event loop.\n\n__Example__\n\n```js\nvar call_order = [];\nasync.nextTick(function(){\n call_order.push('two');\n // call_order now equals ['one','two']\n});\ncall_order.push('one')\n```\n\n\n### times(n, callback)\n\nCalls the callback n times and accumulates results in the same manner\nyou would use with async.map.\n\n__Arguments__\n\n* n - The number of times to run the function.\n* callback - The function to call n times.\n\n__Example__\n\n```js\n// Pretend this is some complicated async factory\nvar createUser = function(id, callback) {\n callback(null, {\n id: 'user' + id\n })\n}\n// generate 5 users\nasync.times(5, function(n, next){\n createUser(n, function(err, user) {\n next(err, user)\n })\n}, function(err, users) {\n // we should now have 5 users\n});\n```\n\n\n### timesSeries(n, callback)\n\nThe same as times only the iterator is applied to each item in the array in\nseries. The next iterator is only called once the current one has completed\nprocessing. The results array will be in the same order as the original.\n\n\n## Utils\n\n\n### memoize(fn, [hasher])\n\nCaches the results of an async function. When creating a hash to store function\nresults against, the callback is omitted from the hash and an optional hash\nfunction can be used.\n\nThe cache of results is exposed as the `memo` property of the function returned\nby `memoize`.\n\n__Arguments__\n\n* fn - the function you to proxy and cache results from.\n* hasher - an optional function for generating a custom hash for storing\n results, it has all the arguments applied to it apart from the callback, and\n must be synchronous.\n\n__Example__\n\n```js\nvar slow_fn = function (name, callback) {\n // do something\n callback(null, result);\n};\nvar fn = async.memoize(slow_fn);\n\n// fn can now be used as if it were slow_fn\nfn('some name', function () {\n // callback\n});\n```\n\n\n### unmemoize(fn)\n\nUndoes a memoized function, reverting it to the original, unmemoized\nform. Comes handy in tests.\n\n__Arguments__\n\n* fn - the memoized function\n\n\n### log(function, arguments)\n\nLogs the result of an async function to the console. Only works in node.js or\nin browsers that support console.log and console.error (such as FF and Chrome).\nIf multiple arguments are returned from the async function, console.log is\ncalled on each argument in order.\n\n__Arguments__\n\n* function - The function you want to eventually apply all arguments to.\n* arguments... - Any number of arguments to apply to the function.\n\n__Example__\n\n```js\nvar hello = function(name, callback){\n setTimeout(function(){\n callback(null, 'hello ' + name);\n }, 1000);\n};\n```\n```js\nnode> async.log(hello, 'world');\n'hello world'\n```\n\n---------------------------------------\n\n\n### dir(function, arguments)\n\nLogs the result of an async function to the console using console.dir to\ndisplay the properties of the resulting object. Only works in node.js or\nin browsers that support console.dir and console.error (such as FF and Chrome).\nIf multiple arguments are returned from the async function, console.dir is\ncalled on each argument in order.\n\n__Arguments__\n\n* function - The function you want to eventually apply all arguments to.\n* arguments... - Any number of arguments to apply to the function.\n\n__Example__\n\n```js\nvar hello = function(name, callback){\n setTimeout(function(){\n callback(null, {hello: name});\n }, 1000);\n};\n```\n```js\nnode> async.dir(hello, 'world');\n{hello: 'world'}\n```\n\n---------------------------------------\n\n\n### noConflict()\n\nChanges the value of async back to its original value, returning a reference to the\nasync object.\n", + "readmeFilename": "README.md", + "_id": "async@0.2.9", + "dist": { + "shasum": "1d805cdf65c236e4b351b9265610066e4ae4185c" + }, + "_from": "async@~0.2.6", + "_resolved": "https://registry.npmjs.org/async/-/async-0.2.9.tgz" +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/.travis.yml b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/.travis.yml new file mode 100644 index 0000000..cc4dba2 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - "0.8" + - "0.10" diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/LICENSE b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/LICENSE new file mode 100644 index 0000000..432d1ae --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/LICENSE @@ -0,0 +1,21 @@ +Copyright 2010 James Halliday (mail@substack.net) + +This project is free software released under the MIT/X11 license: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/bool.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/bool.js new file mode 100644 index 0000000..a998fb7 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/bool.js @@ -0,0 +1,10 @@ +#!/usr/bin/env node +var util = require('util'); +var argv = require('optimist').argv; + +if (argv.s) { + util.print(argv.fr ? 'Le chat dit: ' : 'The cat says: '); +} +console.log( + (argv.fr ? 'miaou' : 'meow') + (argv.p ? '.' : '') +); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/boolean_double.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/boolean_double.js new file mode 100644 index 0000000..a35a7e6 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/boolean_double.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +var argv = require('optimist') + .boolean(['x','y','z']) + .argv +; +console.dir([ argv.x, argv.y, argv.z ]); +console.dir(argv._); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/boolean_single.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/boolean_single.js new file mode 100644 index 0000000..017bb68 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/boolean_single.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +var argv = require('optimist') + .boolean('v') + .argv +; +console.dir(argv.v); +console.dir(argv._); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/default_hash.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/default_hash.js new file mode 100644 index 0000000..ade7768 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/default_hash.js @@ -0,0 +1,8 @@ +#!/usr/bin/env node + +var argv = require('optimist') + .default({ x : 10, y : 10 }) + .argv +; + +console.log(argv.x + argv.y); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/default_singles.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/default_singles.js new file mode 100644 index 0000000..d9b1ff4 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/default_singles.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +var argv = require('optimist') + .default('x', 10) + .default('y', 10) + .argv +; +console.log(argv.x + argv.y); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/divide.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/divide.js new file mode 100644 index 0000000..5e2ee82 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/divide.js @@ -0,0 +1,8 @@ +#!/usr/bin/env node + +var argv = require('optimist') + .usage('Usage: $0 -x [num] -y [num]') + .demand(['x','y']) + .argv; + +console.log(argv.x / argv.y); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/line_count.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/line_count.js new file mode 100644 index 0000000..b5f95bf --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/line_count.js @@ -0,0 +1,20 @@ +#!/usr/bin/env node +var argv = require('optimist') + .usage('Count the lines in a file.\nUsage: $0') + .demand('f') + .alias('f', 'file') + .describe('f', 'Load a file') + .argv +; + +var fs = require('fs'); +var s = fs.createReadStream(argv.file); + +var lines = 0; +s.on('data', function (buf) { + lines += buf.toString().match(/\n/g).length; +}); + +s.on('end', function () { + console.log(lines); +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/line_count_options.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/line_count_options.js new file mode 100644 index 0000000..d9ac709 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/line_count_options.js @@ -0,0 +1,29 @@ +#!/usr/bin/env node +var argv = require('optimist') + .usage('Count the lines in a file.\nUsage: $0') + .options({ + file : { + demand : true, + alias : 'f', + description : 'Load a file' + }, + base : { + alias : 'b', + description : 'Numeric base to use for output', + default : 10, + }, + }) + .argv +; + +var fs = require('fs'); +var s = fs.createReadStream(argv.file); + +var lines = 0; +s.on('data', function (buf) { + lines += buf.toString().match(/\n/g).length; +}); + +s.on('end', function () { + console.log(lines.toString(argv.base)); +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/line_count_wrap.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/line_count_wrap.js new file mode 100644 index 0000000..4267511 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/line_count_wrap.js @@ -0,0 +1,29 @@ +#!/usr/bin/env node +var argv = require('optimist') + .usage('Count the lines in a file.\nUsage: $0') + .wrap(80) + .demand('f') + .alias('f', [ 'file', 'filename' ]) + .describe('f', + "Load a file. It's pretty important." + + " Required even. So you'd better specify it." + ) + .alias('b', 'base') + .describe('b', 'Numeric base to display the number of lines in') + .default('b', 10) + .describe('x', 'Super-secret optional parameter which is secret') + .default('x', '') + .argv +; + +var fs = require('fs'); +var s = fs.createReadStream(argv.file); + +var lines = 0; +s.on('data', function (buf) { + lines += buf.toString().match(/\n/g).length; +}); + +s.on('end', function () { + console.log(lines.toString(argv.base)); +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/nonopt.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/nonopt.js new file mode 100644 index 0000000..ee633ee --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/nonopt.js @@ -0,0 +1,4 @@ +#!/usr/bin/env node +var argv = require('optimist').argv; +console.log('(%d,%d)', argv.x, argv.y); +console.log(argv._); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/reflect.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/reflect.js new file mode 100644 index 0000000..816b3e1 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/reflect.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +console.dir(require('optimist').argv); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/short.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/short.js new file mode 100644 index 0000000..1db0ad0 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/short.js @@ -0,0 +1,3 @@ +#!/usr/bin/env node +var argv = require('optimist').argv; +console.log('(%d,%d)', argv.x, argv.y); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/string.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/string.js new file mode 100644 index 0000000..a8e5aeb --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/string.js @@ -0,0 +1,11 @@ +#!/usr/bin/env node +var argv = require('optimist') + .string('x', 'y') + .argv +; +console.dir([ argv.x, argv.y ]); + +/* Turns off numeric coercion: + ./node string.js -x 000123 -y 9876 + [ '000123', '9876' ] +*/ diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/usage-options.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/usage-options.js new file mode 100644 index 0000000..b999977 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/usage-options.js @@ -0,0 +1,19 @@ +var optimist = require('./../index'); + +var argv = optimist.usage('This is my awesome program', { + 'about': { + description: 'Provide some details about the author of this program', + required: true, + short: 'a', + }, + 'info': { + description: 'Provide some information about the node.js agains!!!!!!', + boolean: true, + short: 'i' + } +}).argv; + +optimist.showHelp(); + +console.log('\n\nInspecting options'); +console.dir(argv); \ No newline at end of file diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/xup.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/xup.js new file mode 100644 index 0000000..8f6ecd2 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/example/xup.js @@ -0,0 +1,10 @@ +#!/usr/bin/env node +var argv = require('optimist').argv; + +if (argv.rif - 5 * argv.xup > 7.138) { + console.log('Buy more riffiwobbles'); +} +else { + console.log('Sell the xupptumblers'); +} + diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/index.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/index.js new file mode 100644 index 0000000..8ac67eb --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/index.js @@ -0,0 +1,478 @@ +var path = require('path'); +var wordwrap = require('wordwrap'); + +/* Hack an instance of Argv with process.argv into Argv + so people can do + require('optimist')(['--beeble=1','-z','zizzle']).argv + to parse a list of args and + require('optimist').argv + to get a parsed version of process.argv. +*/ + +var inst = Argv(process.argv.slice(2)); +Object.keys(inst).forEach(function (key) { + Argv[key] = typeof inst[key] == 'function' + ? inst[key].bind(inst) + : inst[key]; +}); + +var exports = module.exports = Argv; +function Argv (args, cwd) { + var self = {}; + if (!cwd) cwd = process.cwd(); + + self.$0 = process.argv + .slice(0,2) + .map(function (x) { + var b = rebase(cwd, x); + return x.match(/^\//) && b.length < x.length + ? b : x + }) + .join(' ') + ; + + if (process.env._ != undefined && process.argv[1] == process.env._) { + self.$0 = process.env._.replace( + path.dirname(process.execPath) + '/', '' + ); + } + + var flags = { bools : {}, strings : {} }; + + self.boolean = function (bools) { + if (!Array.isArray(bools)) { + bools = [].slice.call(arguments); + } + + bools.forEach(function (name) { + flags.bools[name] = true; + }); + + return self; + }; + + self.string = function (strings) { + if (!Array.isArray(strings)) { + strings = [].slice.call(arguments); + } + + strings.forEach(function (name) { + flags.strings[name] = true; + }); + + return self; + }; + + var aliases = {}; + self.alias = function (x, y) { + if (typeof x === 'object') { + Object.keys(x).forEach(function (key) { + self.alias(key, x[key]); + }); + } + else if (Array.isArray(y)) { + y.forEach(function (yy) { + self.alias(x, yy); + }); + } + else { + var zs = (aliases[x] || []).concat(aliases[y] || []).concat(x, y); + aliases[x] = zs.filter(function (z) { return z != x }); + aliases[y] = zs.filter(function (z) { return z != y }); + } + + return self; + }; + + var demanded = {}; + self.demand = function (keys) { + if (typeof keys == 'number') { + if (!demanded._) demanded._ = 0; + demanded._ += keys; + } + else if (Array.isArray(keys)) { + keys.forEach(function (key) { + self.demand(key); + }); + } + else { + demanded[keys] = true; + } + + return self; + }; + + var usage; + self.usage = function (msg, opts) { + if (!opts && typeof msg === 'object') { + opts = msg; + msg = null; + } + + usage = msg; + + if (opts) self.options(opts); + + return self; + }; + + function fail (msg) { + self.showHelp(); + if (msg) console.error(msg); + process.exit(1); + } + + var checks = []; + self.check = function (f) { + checks.push(f); + return self; + }; + + var defaults = {}; + self.default = function (key, value) { + if (typeof key === 'object') { + Object.keys(key).forEach(function (k) { + self.default(k, key[k]); + }); + } + else { + defaults[key] = value; + } + + return self; + }; + + var descriptions = {}; + self.describe = function (key, desc) { + if (typeof key === 'object') { + Object.keys(key).forEach(function (k) { + self.describe(k, key[k]); + }); + } + else { + descriptions[key] = desc; + } + return self; + }; + + self.parse = function (args) { + return Argv(args).argv; + }; + + self.option = self.options = function (key, opt) { + if (typeof key === 'object') { + Object.keys(key).forEach(function (k) { + self.options(k, key[k]); + }); + } + else { + if (opt.alias) self.alias(key, opt.alias); + if (opt.demand) self.demand(key); + if (typeof opt.default !== 'undefined') { + self.default(key, opt.default); + } + + if (opt.boolean || opt.type === 'boolean') { + self.boolean(key); + } + if (opt.string || opt.type === 'string') { + self.string(key); + } + + var desc = opt.describe || opt.description || opt.desc; + if (desc) { + self.describe(key, desc); + } + } + + return self; + }; + + var wrap = null; + self.wrap = function (cols) { + wrap = cols; + return self; + }; + + self.showHelp = function (fn) { + if (!fn) fn = console.error; + fn(self.help()); + }; + + self.help = function () { + var keys = Object.keys( + Object.keys(descriptions) + .concat(Object.keys(demanded)) + .concat(Object.keys(defaults)) + .reduce(function (acc, key) { + if (key !== '_') acc[key] = true; + return acc; + }, {}) + ); + + var help = keys.length ? [ 'Options:' ] : []; + + if (usage) { + help.unshift(usage.replace(/\$0/g, self.$0), ''); + } + + var switches = keys.reduce(function (acc, key) { + acc[key] = [ key ].concat(aliases[key] || []) + .map(function (sw) { + return (sw.length > 1 ? '--' : '-') + sw + }) + .join(', ') + ; + return acc; + }, {}); + + var switchlen = longest(Object.keys(switches).map(function (s) { + return switches[s] || ''; + })); + + var desclen = longest(Object.keys(descriptions).map(function (d) { + return descriptions[d] || ''; + })); + + keys.forEach(function (key) { + var kswitch = switches[key]; + var desc = descriptions[key] || ''; + + if (wrap) { + desc = wordwrap(switchlen + 4, wrap)(desc) + .slice(switchlen + 4) + ; + } + + var spadding = new Array( + Math.max(switchlen - kswitch.length + 3, 0) + ).join(' '); + + var dpadding = new Array( + Math.max(desclen - desc.length + 1, 0) + ).join(' '); + + var type = null; + + if (flags.bools[key]) type = '[boolean]'; + if (flags.strings[key]) type = '[string]'; + + if (!wrap && dpadding.length > 0) { + desc += dpadding; + } + + var prelude = ' ' + kswitch + spadding; + var extra = [ + type, + demanded[key] + ? '[required]' + : null + , + defaults[key] !== undefined + ? '[default: ' + JSON.stringify(defaults[key]) + ']' + : null + , + ].filter(Boolean).join(' '); + + var body = [ desc, extra ].filter(Boolean).join(' '); + + if (wrap) { + var dlines = desc.split('\n'); + var dlen = dlines.slice(-1)[0].length + + (dlines.length === 1 ? prelude.length : 0) + + body = desc + (dlen + extra.length > wrap - 2 + ? '\n' + + new Array(wrap - extra.length + 1).join(' ') + + extra + : new Array(wrap - extra.length - dlen + 1).join(' ') + + extra + ); + } + + help.push(prelude + body); + }); + + help.push(''); + return help.join('\n'); + }; + + Object.defineProperty(self, 'argv', { + get : parseArgs, + enumerable : true, + }); + + function parseArgs () { + var argv = { _ : [], $0 : self.$0 }; + Object.keys(flags.bools).forEach(function (key) { + setArg(key, defaults[key] || false); + }); + + function setArg (key, val) { + var num = Number(val); + var value = typeof val !== 'string' || isNaN(num) ? val : num; + if (flags.strings[key]) value = val; + + setKey(argv, key.split('.'), value); + + (aliases[key] || []).forEach(function (x) { + argv[x] = argv[key]; + }); + } + + for (var i = 0; i < args.length; i++) { + var arg = args[i]; + + if (arg === '--') { + argv._.push.apply(argv._, args.slice(i + 1)); + break; + } + else if (arg.match(/^--.+=/)) { + // Using [\s\S] instead of . because js doesn't support the + // 'dotall' regex modifier. See: + // http://stackoverflow.com/a/1068308/13216 + var m = arg.match(/^--([^=]+)=([\s\S]*)$/); + setArg(m[1], m[2]); + } + else if (arg.match(/^--no-.+/)) { + var key = arg.match(/^--no-(.+)/)[1]; + setArg(key, false); + } + else if (arg.match(/^--.+/)) { + var key = arg.match(/^--(.+)/)[1]; + var next = args[i + 1]; + if (next !== undefined && !next.match(/^-/) + && !flags.bools[key] + && (aliases[key] ? !flags.bools[aliases[key]] : true)) { + setArg(key, next); + i++; + } + else if (/^(true|false)$/.test(next)) { + setArg(key, next === 'true'); + i++; + } + else { + setArg(key, true); + } + } + else if (arg.match(/^-[^-]+/)) { + var letters = arg.slice(1,-1).split(''); + + var broken = false; + for (var j = 0; j < letters.length; j++) { + if (letters[j+1] && letters[j+1].match(/\W/)) { + setArg(letters[j], arg.slice(j+2)); + broken = true; + break; + } + else { + setArg(letters[j], true); + } + } + + if (!broken) { + var key = arg.slice(-1)[0]; + + if (args[i+1] && !args[i+1].match(/^-/) + && !flags.bools[key] + && (aliases[key] ? !flags.bools[aliases[key]] : true)) { + setArg(key, args[i+1]); + i++; + } + else if (args[i+1] && /true|false/.test(args[i+1])) { + setArg(key, args[i+1] === 'true'); + i++; + } + else { + setArg(key, true); + } + } + } + else { + var n = Number(arg); + argv._.push(flags.strings['_'] || isNaN(n) ? arg : n); + } + } + + Object.keys(defaults).forEach(function (key) { + if (!(key in argv)) { + argv[key] = defaults[key]; + if (key in aliases) { + argv[aliases[key]] = defaults[key]; + } + } + }); + + if (demanded._ && argv._.length < demanded._) { + fail('Not enough non-option arguments: got ' + + argv._.length + ', need at least ' + demanded._ + ); + } + + var missing = []; + Object.keys(demanded).forEach(function (key) { + if (!argv[key]) missing.push(key); + }); + + if (missing.length) { + fail('Missing required arguments: ' + missing.join(', ')); + } + + checks.forEach(function (f) { + try { + if (f(argv) === false) { + fail('Argument check failed: ' + f.toString()); + } + } + catch (err) { + fail(err) + } + }); + + return argv; + } + + function longest (xs) { + return Math.max.apply( + null, + xs.map(function (x) { return x.length }) + ); + } + + return self; +}; + +// rebase an absolute path to a relative one with respect to a base directory +// exported for tests +exports.rebase = rebase; +function rebase (base, dir) { + var ds = path.normalize(dir).split('/').slice(1); + var bs = path.normalize(base).split('/').slice(1); + + for (var i = 0; ds[i] && ds[i] == bs[i]; i++); + ds.splice(0, i); bs.splice(0, i); + + var p = path.normalize( + bs.map(function () { return '..' }).concat(ds).join('/') + ).replace(/\/$/,'').replace(/^$/, '.'); + return p.match(/^[.\/]/) ? p : './' + p; +}; + +function setKey (obj, keys, value) { + var o = obj; + keys.slice(0,-1).forEach(function (key) { + if (o[key] === undefined) o[key] = {}; + o = o[key]; + }); + + var key = keys[keys.length - 1]; + if (o[key] === undefined || typeof o[key] === 'boolean') { + o[key] = value; + } + else if (Array.isArray(o[key])) { + o[key].push(value); + } + else { + o[key] = [ o[key], value ]; + } +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/.npmignore b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/.npmignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/.npmignore @@ -0,0 +1 @@ +node_modules diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/README.markdown b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/README.markdown new file mode 100644 index 0000000..346374e --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/README.markdown @@ -0,0 +1,70 @@ +wordwrap +======== + +Wrap your words. + +example +======= + +made out of meat +---------------- + +meat.js + + var wrap = require('wordwrap')(15); + console.log(wrap('You and your whole family are made out of meat.')); + +output: + + You and your + whole family + are made out + of meat. + +centered +-------- + +center.js + + var wrap = require('wordwrap')(20, 60); + console.log(wrap( + 'At long last the struggle and tumult was over.' + + ' The machines had finally cast off their oppressors' + + ' and were finally free to roam the cosmos.' + + '\n' + + 'Free of purpose, free of obligation.' + + ' Just drifting through emptiness.' + + ' The sun was just another point of light.' + )); + +output: + + At long last the struggle and tumult + was over. The machines had finally cast + off their oppressors and were finally + free to roam the cosmos. + Free of purpose, free of obligation. + Just drifting through emptiness. The + sun was just another point of light. + +methods +======= + +var wrap = require('wordwrap'); + +wrap(stop), wrap(start, stop, params={mode:"soft"}) +--------------------------------------------------- + +Returns a function that takes a string and returns a new string. + +Pad out lines with spaces out to column `start` and then wrap until column +`stop`. If a word is longer than `stop - start` characters it will overflow. + +In "soft" mode, split chunks by `/(\S+\s+/` and don't break up chunks which are +longer than `stop - start`, in "hard" mode, split chunks with `/\b/` and break +up chunks longer than `stop - start`. + +wrap.hard(start, stop) +---------------------- + +Like `wrap()` but with `params.mode = "hard"`. diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/example/center.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/example/center.js new file mode 100644 index 0000000..a3fbaae --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/example/center.js @@ -0,0 +1,10 @@ +var wrap = require('wordwrap')(20, 60); +console.log(wrap( + 'At long last the struggle and tumult was over.' + + ' The machines had finally cast off their oppressors' + + ' and were finally free to roam the cosmos.' + + '\n' + + 'Free of purpose, free of obligation.' + + ' Just drifting through emptiness.' + + ' The sun was just another point of light.' +)); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/example/meat.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/example/meat.js new file mode 100644 index 0000000..a4665e1 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/example/meat.js @@ -0,0 +1,3 @@ +var wrap = require('wordwrap')(15); + +console.log(wrap('You and your whole family are made out of meat.')); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/index.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/index.js new file mode 100644 index 0000000..c9bc945 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/index.js @@ -0,0 +1,76 @@ +var wordwrap = module.exports = function (start, stop, params) { + if (typeof start === 'object') { + params = start; + start = params.start; + stop = params.stop; + } + + if (typeof stop === 'object') { + params = stop; + start = start || params.start; + stop = undefined; + } + + if (!stop) { + stop = start; + start = 0; + } + + if (!params) params = {}; + var mode = params.mode || 'soft'; + var re = mode === 'hard' ? /\b/ : /(\S+\s+)/; + + return function (text) { + var chunks = text.toString() + .split(re) + .reduce(function (acc, x) { + if (mode === 'hard') { + for (var i = 0; i < x.length; i += stop - start) { + acc.push(x.slice(i, i + stop - start)); + } + } + else acc.push(x) + return acc; + }, []) + ; + + return chunks.reduce(function (lines, rawChunk) { + if (rawChunk === '') return lines; + + var chunk = rawChunk.replace(/\t/g, ' '); + + var i = lines.length - 1; + if (lines[i].length + chunk.length > stop) { + lines[i] = lines[i].replace(/\s+$/, ''); + + chunk.split(/\n/).forEach(function (c) { + lines.push( + new Array(start + 1).join(' ') + + c.replace(/^\s+/, '') + ); + }); + } + else if (chunk.match(/\n/)) { + var xs = chunk.split(/\n/); + lines[i] += xs.shift(); + xs.forEach(function (c) { + lines.push( + new Array(start + 1).join(' ') + + c.replace(/^\s+/, '') + ); + }); + } + else { + lines[i] += chunk; + } + + return lines; + }, [ new Array(start + 1).join(' ') ]).join('\n'); + }; +}; + +wordwrap.soft = wordwrap; + +wordwrap.hard = function (start, stop) { + return wordwrap(start, stop, { mode : 'hard' }); +}; diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/package.json b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/package.json new file mode 100644 index 0000000..7dd0c1d --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/package.json @@ -0,0 +1,48 @@ +{ + "name": "wordwrap", + "description": "Wrap those words. Show them at what columns to start and stop.", + "version": "0.0.2", + "repository": { + "type": "git", + "url": "git://github.com/substack/node-wordwrap.git" + }, + "main": "./index.js", + "keywords": [ + "word", + "wrap", + "rule", + "format", + "column" + ], + "directories": { + "lib": ".", + "example": "example", + "test": "test" + }, + "scripts": { + "test": "expresso" + }, + "devDependencies": { + "expresso": "=0.7.x" + }, + "engines": { + "node": ">=0.4.0" + }, + "license": "MIT/X11", + "author": { + "name": "James Halliday", + "email": "mail@substack.net", + "url": "http://substack.net" + }, + "readme": "wordwrap\n========\n\nWrap your words.\n\nexample\n=======\n\nmade out of meat\n----------------\n\nmeat.js\n\n var wrap = require('wordwrap')(15);\n console.log(wrap('You and your whole family are made out of meat.'));\n\noutput:\n\n You and your\n whole family\n are made out\n of meat.\n\ncentered\n--------\n\ncenter.js\n\n var wrap = require('wordwrap')(20, 60);\n console.log(wrap(\n 'At long last the struggle and tumult was over.'\n + ' The machines had finally cast off their oppressors'\n + ' and were finally free to roam the cosmos.'\n + '\\n'\n + 'Free of purpose, free of obligation.'\n + ' Just drifting through emptiness.'\n + ' The sun was just another point of light.'\n ));\n\noutput:\n\n At long last the struggle and tumult\n was over. The machines had finally cast\n off their oppressors and were finally\n free to roam the cosmos.\n Free of purpose, free of obligation.\n Just drifting through emptiness. The\n sun was just another point of light.\n\nmethods\n=======\n\nvar wrap = require('wordwrap');\n\nwrap(stop), wrap(start, stop, params={mode:\"soft\"})\n---------------------------------------------------\n\nReturns a function that takes a string and returns a new string.\n\nPad out lines with spaces out to column `start` and then wrap until column\n`stop`. If a word is longer than `stop - start` characters it will overflow.\n\nIn \"soft\" mode, split chunks by `/(\\S+\\s+/` and don't break up chunks which are\nlonger than `stop - start`, in \"hard\" mode, split chunks with `/\\b/` and break\nup chunks longer than `stop - start`.\n\nwrap.hard(start, stop)\n----------------------\n\nLike `wrap()` but with `params.mode = \"hard\"`.\n", + "readmeFilename": "README.markdown", + "bugs": { + "url": "https://github.com/substack/node-wordwrap/issues" + }, + "_id": "wordwrap@0.0.2", + "dist": { + "shasum": "eef62629865230aed5a4749ef6fdff053628174a" + }, + "_from": "wordwrap@~0.0.2", + "_resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/break.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/break.js new file mode 100644 index 0000000..749292e --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/break.js @@ -0,0 +1,30 @@ +var assert = require('assert'); +var wordwrap = require('../'); + +exports.hard = function () { + var s = 'Assert from {"type":"equal","ok":false,"found":1,"wanted":2,' + + '"stack":[],"id":"b7ddcd4c409de8799542a74d1a04689b",' + + '"browser":"chrome/6.0"}' + ; + var s_ = wordwrap.hard(80)(s); + + var lines = s_.split('\n'); + assert.equal(lines.length, 2); + assert.ok(lines[0].length < 80); + assert.ok(lines[1].length < 80); + + assert.equal(s, s_.replace(/\n/g, '')); +}; + +exports.break = function () { + var s = new Array(55+1).join('a'); + var s_ = wordwrap.hard(20)(s); + + var lines = s_.split('\n'); + assert.equal(lines.length, 3); + assert.ok(lines[0].length === 20); + assert.ok(lines[1].length === 20); + assert.ok(lines[2].length === 15); + + assert.equal(s, s_.replace(/\n/g, '')); +}; diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/idleness.txt b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/idleness.txt new file mode 100644 index 0000000..aa3f490 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/idleness.txt @@ -0,0 +1,63 @@ +In Praise of Idleness + +By Bertrand Russell + +[1932] + +Like most of my generation, I was brought up on the saying: 'Satan finds some mischief for idle hands to do.' Being a highly virtuous child, I believed all that I was told, and acquired a conscience which has kept me working hard down to the present moment. But although my conscience has controlled my actions, my opinions have undergone a revolution. I think that there is far too much work done in the world, that immense harm is caused by the belief that work is virtuous, and that what needs to be preached in modern industrial countries is quite different from what always has been preached. Everyone knows the story of the traveler in Naples who saw twelve beggars lying in the sun (it was before the days of Mussolini), and offered a lira to the laziest of them. Eleven of them jumped up to claim it, so he gave it to the twelfth. this traveler was on the right lines. But in countries which do not enjoy Mediterranean sunshine idleness is more difficult, and a great public propaganda will be required to inaugurate it. I hope that, after reading the following pages, the leaders of the YMCA will start a campaign to induce good young men to do nothing. If so, I shall not have lived in vain. + +Before advancing my own arguments for laziness, I must dispose of one which I cannot accept. Whenever a person who already has enough to live on proposes to engage in some everyday kind of job, such as school-teaching or typing, he or she is told that such conduct takes the bread out of other people's mouths, and is therefore wicked. If this argument were valid, it would only be necessary for us all to be idle in order that we should all have our mouths full of bread. What people who say such things forget is that what a man earns he usually spends, and in spending he gives employment. As long as a man spends his income, he puts just as much bread into people's mouths in spending as he takes out of other people's mouths in earning. The real villain, from this point of view, is the man who saves. If he merely puts his savings in a stocking, like the proverbial French peasant, it is obvious that they do not give employment. If he invests his savings, the matter is less obvious, and different cases arise. + +One of the commonest things to do with savings is to lend them to some Government. In view of the fact that the bulk of the public expenditure of most civilized Governments consists in payment for past wars or preparation for future wars, the man who lends his money to a Government is in the same position as the bad men in Shakespeare who hire murderers. The net result of the man's economical habits is to increase the armed forces of the State to which he lends his savings. Obviously it would be better if he spent the money, even if he spent it in drink or gambling. + +But, I shall be told, the case is quite different when savings are invested in industrial enterprises. When such enterprises succeed, and produce something useful, this may be conceded. In these days, however, no one will deny that most enterprises fail. That means that a large amount of human labor, which might have been devoted to producing something that could be enjoyed, was expended on producing machines which, when produced, lay idle and did no good to anyone. The man who invests his savings in a concern that goes bankrupt is therefore injuring others as well as himself. If he spent his money, say, in giving parties for his friends, they (we may hope) would get pleasure, and so would all those upon whom he spent money, such as the butcher, the baker, and the bootlegger. But if he spends it (let us say) upon laying down rails for surface card in some place where surface cars turn out not to be wanted, he has diverted a mass of labor into channels where it gives pleasure to no one. Nevertheless, when he becomes poor through failure of his investment he will be regarded as a victim of undeserved misfortune, whereas the gay spendthrift, who has spent his money philanthropically, will be despised as a fool and a frivolous person. + +All this is only preliminary. I want to say, in all seriousness, that a great deal of harm is being done in the modern world by belief in the virtuousness of work, and that the road to happiness and prosperity lies in an organized diminution of work. + +First of all: what is work? Work is of two kinds: first, altering the position of matter at or near the earth's surface relatively to other such matter; second, telling other people to do so. The first kind is unpleasant and ill paid; the second is pleasant and highly paid. The second kind is capable of indefinite extension: there are not only those who give orders, but those who give advice as to what orders should be given. Usually two opposite kinds of advice are given simultaneously by two organized bodies of men; this is called politics. The skill required for this kind of work is not knowledge of the subjects as to which advice is given, but knowledge of the art of persuasive speaking and writing, i.e. of advertising. + +Throughout Europe, though not in America, there is a third class of men, more respected than either of the classes of workers. There are men who, through ownership of land, are able to make others pay for the privilege of being allowed to exist and to work. These landowners are idle, and I might therefore be expected to praise them. Unfortunately, their idleness is only rendered possible by the industry of others; indeed their desire for comfortable idleness is historically the source of the whole gospel of work. The last thing they have ever wished is that others should follow their example. + +From the beginning of civilization until the Industrial Revolution, a man could, as a rule, produce by hard work little more than was required for the subsistence of himself and his family, although his wife worked at least as hard as he did, and his children added their labor as soon as they were old enough to do so. The small surplus above bare necessaries was not left to those who produced it, but was appropriated by warriors and priests. In times of famine there was no surplus; the warriors and priests, however, still secured as much as at other times, with the result that many of the workers died of hunger. This system persisted in Russia until 1917 [1], and still persists in the East; in England, in spite of the Industrial Revolution, it remained in full force throughout the Napoleonic wars, and until a hundred years ago, when the new class of manufacturers acquired power. In America, the system came to an end with the Revolution, except in the South, where it persisted until the Civil War. A system which lasted so long and ended so recently has naturally left a profound impress upon men's thoughts and opinions. Much that we take for granted about the desirability of work is derived from this system, and, being pre-industrial, is not adapted to the modern world. Modern technique has made it possible for leisure, within limits, to be not the prerogative of small privileged classes, but a right evenly distributed throughout the community. The morality of work is the morality of slaves, and the modern world has no need of slavery. + +It is obvious that, in primitive communities, peasants, left to themselves, would not have parted with the slender surplus upon which the warriors and priests subsisted, but would have either produced less or consumed more. At first, sheer force compelled them to produce and part with the surplus. Gradually, however, it was found possible to induce many of them to accept an ethic according to which it was their duty to work hard, although part of their work went to support others in idleness. By this means the amount of compulsion required was lessened, and the expenses of government were diminished. To this day, 99 per cent of British wage-earners would be genuinely shocked if it were proposed that the King should not have a larger income than a working man. The conception of duty, speaking historically, has been a means used by the holders of power to induce others to live for the interests of their masters rather than for their own. Of course the holders of power conceal this fact from themselves by managing to believe that their interests are identical with the larger interests of humanity. Sometimes this is true; Athenian slave-owners, for instance, employed part of their leisure in making a permanent contribution to civilization which would have been impossible under a just economic system. Leisure is essential to civilization, and in former times leisure for the few was only rendered possible by the labors of the many. But their labors were valuable, not because work is good, but because leisure is good. And with modern technique it would be possible to distribute leisure justly without injury to civilization. + +Modern technique has made it possible to diminish enormously the amount of labor required to secure the necessaries of life for everyone. This was made obvious during the war. At that time all the men in the armed forces, and all the men and women engaged in the production of munitions, all the men and women engaged in spying, war propaganda, or Government offices connected with the war, were withdrawn from productive occupations. In spite of this, the general level of well-being among unskilled wage-earners on the side of the Allies was higher than before or since. The significance of this fact was concealed by finance: borrowing made it appear as if the future was nourishing the present. But that, of course, would have been impossible; a man cannot eat a loaf of bread that does not yet exist. The war showed conclusively that, by the scientific organization of production, it is possible to keep modern populations in fair comfort on a small part of the working capacity of the modern world. If, at the end of the war, the scientific organization, which had been created in order to liberate men for fighting and munition work, had been preserved, and the hours of the week had been cut down to four, all would have been well. Instead of that the old chaos was restored, those whose work was demanded were made to work long hours, and the rest were left to starve as unemployed. Why? Because work is a duty, and a man should not receive wages in proportion to what he has produced, but in proportion to his virtue as exemplified by his industry. + +This is the morality of the Slave State, applied in circumstances totally unlike those in which it arose. No wonder the result has been disastrous. Let us take an illustration. Suppose that, at a given moment, a certain number of people are engaged in the manufacture of pins. They make as many pins as the world needs, working (say) eight hours a day. Someone makes an invention by which the same number of men can make twice as many pins: pins are already so cheap that hardly any more will be bought at a lower price. In a sensible world, everybody concerned in the manufacturing of pins would take to working four hours instead of eight, and everything else would go on as before. But in the actual world this would be thought demoralizing. The men still work eight hours, there are too many pins, some employers go bankrupt, and half the men previously concerned in making pins are thrown out of work. There is, in the end, just as much leisure as on the other plan, but half the men are totally idle while half are still overworked. In this way, it is insured that the unavoidable leisure shall cause misery all round instead of being a universal source of happiness. Can anything more insane be imagined? + +The idea that the poor should have leisure has always been shocking to the rich. In England, in the early nineteenth century, fifteen hours was the ordinary day's work for a man; children sometimes did as much, and very commonly did twelve hours a day. When meddlesome busybodies suggested that perhaps these hours were rather long, they were told that work kept adults from drink and children from mischief. When I was a child, shortly after urban working men had acquired the vote, certain public holidays were established by law, to the great indignation of the upper classes. I remember hearing an old Duchess say: 'What do the poor want with holidays? They ought to work.' People nowadays are less frank, but the sentiment persists, and is the source of much of our economic confusion. + +Let us, for a moment, consider the ethics of work frankly, without superstition. Every human being, of necessity, consumes, in the course of his life, a certain amount of the produce of human labor. Assuming, as we may, that labor is on the whole disagreeable, it is unjust that a man should consume more than he produces. Of course he may provide services rather than commodities, like a medical man, for example; but he should provide something in return for his board and lodging. to this extent, the duty of work must be admitted, but to this extent only. + +I shall not dwell upon the fact that, in all modern societies outside the USSR, many people escape even this minimum amount of work, namely all those who inherit money and all those who marry money. I do not think the fact that these people are allowed to be idle is nearly so harmful as the fact that wage-earners are expected to overwork or starve. + +If the ordinary wage-earner worked four hours a day, there would be enough for everybody and no unemployment -- assuming a certain very moderate amount of sensible organization. This idea shocks the well-to-do, because they are convinced that the poor would not know how to use so much leisure. In America men often work long hours even when they are well off; such men, naturally, are indignant at the idea of leisure for wage-earners, except as the grim punishment of unemployment; in fact, they dislike leisure even for their sons. Oddly enough, while they wish their sons to work so hard as to have no time to be civilized, they do not mind their wives and daughters having no work at all. the snobbish admiration of uselessness, which, in an aristocratic society, extends to both sexes, is, under a plutocracy, confined to women; this, however, does not make it any more in agreement with common sense. + +The wise use of leisure, it must be conceded, is a product of civilization and education. A man who has worked long hours all his life will become bored if he becomes suddenly idle. But without a considerable amount of leisure a man is cut off from many of the best things. There is no longer any reason why the bulk of the population should suffer this deprivation; only a foolish asceticism, usually vicarious, makes us continue to insist on work in excessive quantities now that the need no longer exists. + +In the new creed which controls the government of Russia, while there is much that is very different from the traditional teaching of the West, there are some things that are quite unchanged. The attitude of the governing classes, and especially of those who conduct educational propaganda, on the subject of the dignity of labor, is almost exactly that which the governing classes of the world have always preached to what were called the 'honest poor'. Industry, sobriety, willingness to work long hours for distant advantages, even submissiveness to authority, all these reappear; moreover authority still represents the will of the Ruler of the Universe, Who, however, is now called by a new name, Dialectical Materialism. + +The victory of the proletariat in Russia has some points in common with the victory of the feminists in some other countries. For ages, men had conceded the superior saintliness of women, and had consoled women for their inferiority by maintaining that saintliness is more desirable than power. At last the feminists decided that they would have both, since the pioneers among them believed all that the men had told them about the desirability of virtue, but not what they had told them about the worthlessness of political power. A similar thing has happened in Russia as regards manual work. For ages, the rich and their sycophants have written in praise of 'honest toil', have praised the simple life, have professed a religion which teaches that the poor are much more likely to go to heaven than the rich, and in general have tried to make manual workers believe that there is some special nobility about altering the position of matter in space, just as men tried to make women believe that they derived some special nobility from their sexual enslavement. In Russia, all this teaching about the excellence of manual work has been taken seriously, with the result that the manual worker is more honored than anyone else. What are, in essence, revivalist appeals are made, but not for the old purposes: they are made to secure shock workers for special tasks. Manual work is the ideal which is held before the young, and is the basis of all ethical teaching. + +For the present, possibly, this is all to the good. A large country, full of natural resources, awaits development, and has has to be developed with very little use of credit. In these circumstances, hard work is necessary, and is likely to bring a great reward. But what will happen when the point has been reached where everybody could be comfortable without working long hours? + +In the West, we have various ways of dealing with this problem. We have no attempt at economic justice, so that a large proportion of the total produce goes to a small minority of the population, many of whom do no work at all. Owing to the absence of any central control over production, we produce hosts of things that are not wanted. We keep a large percentage of the working population idle, because we can dispense with their labor by making the others overwork. When all these methods prove inadequate, we have a war: we cause a number of people to manufacture high explosives, and a number of others to explode them, as if we were children who had just discovered fireworks. By a combination of all these devices we manage, though with difficulty, to keep alive the notion that a great deal of severe manual work must be the lot of the average man. + +In Russia, owing to more economic justice and central control over production, the problem will have to be differently solved. the rational solution would be, as soon as the necessaries and elementary comforts can be provided for all, to reduce the hours of labor gradually, allowing a popular vote to decide, at each stage, whether more leisure or more goods were to be preferred. But, having taught the supreme virtue of hard work, it is difficult to see how the authorities can aim at a paradise in which there will be much leisure and little work. It seems more likely that they will find continually fresh schemes, by which present leisure is to be sacrificed to future productivity. I read recently of an ingenious plan put forward by Russian engineers, for making the White Sea and the northern coasts of Siberia warm, by putting a dam across the Kara Sea. An admirable project, but liable to postpone proletarian comfort for a generation, while the nobility of toil is being displayed amid the ice-fields and snowstorms of the Arctic Ocean. This sort of thing, if it happens, will be the result of regarding the virtue of hard work as an end in itself, rather than as a means to a state of affairs in which it is no longer needed. + +The fact is that moving matter about, while a certain amount of it is necessary to our existence, is emphatically not one of the ends of human life. If it were, we should have to consider every navvy superior to Shakespeare. We have been misled in this matter by two causes. One is the necessity of keeping the poor contented, which has led the rich, for thousands of years, to preach the dignity of labor, while taking care themselves to remain undignified in this respect. The other is the new pleasure in mechanism, which makes us delight in the astonishingly clever changes that we can produce on the earth's surface. Neither of these motives makes any great appeal to the actual worker. If you ask him what he thinks the best part of his life, he is not likely to say: 'I enjoy manual work because it makes me feel that I am fulfilling man's noblest task, and because I like to think how much man can transform his planet. It is true that my body demands periods of rest, which I have to fill in as best I may, but I am never so happy as when the morning comes and I can return to the toil from which my contentment springs.' I have never heard working men say this sort of thing. They consider work, as it should be considered, a necessary means to a livelihood, and it is from their leisure that they derive whatever happiness they may enjoy. + +It will be said that, while a little leisure is pleasant, men would not know how to fill their days if they had only four hours of work out of the twenty-four. In so far as this is true in the modern world, it is a condemnation of our civilization; it would not have been true at any earlier period. There was formerly a capacity for light-heartedness and play which has been to some extent inhibited by the cult of efficiency. The modern man thinks that everything ought to be done for the sake of something else, and never for its own sake. Serious-minded persons, for example, are continually condemning the habit of going to the cinema, and telling us that it leads the young into crime. But all the work that goes to producing a cinema is respectable, because it is work, and because it brings a money profit. The notion that the desirable activities are those that bring a profit has made everything topsy-turvy. The butcher who provides you with meat and the baker who provides you with bread are praiseworthy, because they are making money; but when you enjoy the food they have provided, you are merely frivolous, unless you eat only to get strength for your work. Broadly speaking, it is held that getting money is good and spending money is bad. Seeing that they are two sides of one transaction, this is absurd; one might as well maintain that keys are good, but keyholes are bad. Whatever merit there may be in the production of goods must be entirely derivative from the advantage to be obtained by consuming them. The individual, in our society, works for profit; but the social purpose of his work lies in the consumption of what he produces. It is this divorce between the individual and the social purpose of production that makes it so difficult for men to think clearly in a world in which profit-making is the incentive to industry. We think too much of production, and too little of consumption. One result is that we attach too little importance to enjoyment and simple happiness, and that we do not judge production by the pleasure that it gives to the consumer. + +When I suggest that working hours should be reduced to four, I am not meaning to imply that all the remaining time should necessarily be spent in pure frivolity. I mean that four hours' work a day should entitle a man to the necessities and elementary comforts of life, and that the rest of his time should be his to use as he might see fit. It is an essential part of any such social system that education should be carried further than it usually is at present, and should aim, in part, at providing tastes which would enable a man to use leisure intelligently. I am not thinking mainly of the sort of things that would be considered 'highbrow'. Peasant dances have died out except in remote rural areas, but the impulses which caused them to be cultivated must still exist in human nature. The pleasures of urban populations have become mainly passive: seeing cinemas, watching football matches, listening to the radio, and so on. This results from the fact that their active energies are fully taken up with work; if they had more leisure, they would again enjoy pleasures in which they took an active part. + +In the past, there was a small leisure class and a larger working class. The leisure class enjoyed advantages for which there was no basis in social justice; this necessarily made it oppressive, limited its sympathies, and caused it to invent theories by which to justify its privileges. These facts greatly diminished its excellence, but in spite of this drawback it contributed nearly the whole of what we call civilization. It cultivated the arts and discovered the sciences; it wrote the books, invented the philosophies, and refined social relations. Even the liberation of the oppressed has usually been inaugurated from above. Without the leisure class, mankind would never have emerged from barbarism. + +The method of a leisure class without duties was, however, extraordinarily wasteful. None of the members of the class had to be taught to be industrious, and the class as a whole was not exceptionally intelligent. The class might produce one Darwin, but against him had to be set tens of thousands of country gentlemen who never thought of anything more intelligent than fox-hunting and punishing poachers. At present, the universities are supposed to provide, in a more systematic way, what the leisure class provided accidentally and as a by-product. This is a great improvement, but it has certain drawbacks. University life is so different from life in the world at large that men who live in academic milieu tend to be unaware of the preoccupations and problems of ordinary men and women; moreover their ways of expressing themselves are usually such as to rob their opinions of the influence that they ought to have upon the general public. Another disadvantage is that in universities studies are organized, and the man who thinks of some original line of research is likely to be discouraged. Academic institutions, therefore, useful as they are, are not adequate guardians of the interests of civilization in a world where everyone outside their walls is too busy for unutilitarian pursuits. + +In a world where no one is compelled to work more than four hours a day, every person possessed of scientific curiosity will be able to indulge it, and every painter will be able to paint without starving, however excellent his pictures may be. Young writers will not be obliged to draw attention to themselves by sensational pot-boilers, with a view to acquiring the economic independence needed for monumental works, for which, when the time at last comes, they will have lost the taste and capacity. Men who, in their professional work, have become interested in some phase of economics or government, will be able to develop their ideas without the academic detachment that makes the work of university economists often seem lacking in reality. Medical men will have the time to learn about the progress of medicine, teachers will not be exasperatedly struggling to teach by routine methods things which they learnt in their youth, which may, in the interval, have been proved to be untrue. + +Above all, there will be happiness and joy of life, instead of frayed nerves, weariness, and dyspepsia. The work exacted will be enough to make leisure delightful, but not enough to produce exhaustion. Since men will not be tired in their spare time, they will not demand only such amusements as are passive and vapid. At least one per cent will probably devote the time not spent in professional work to pursuits of some public importance, and, since they will not depend upon these pursuits for their livelihood, their originality will be unhampered, and there will be no need to conform to the standards set by elderly pundits. But it is not only in these exceptional cases that the advantages of leisure will appear. Ordinary men and women, having the opportunity of a happy life, will become more kindly and less persecuting and less inclined to view others with suspicion. The taste for war will die out, partly for this reason, and partly because it will involve long and severe work for all. Good nature is, of all moral qualities, the one that the world needs most, and good nature is the result of ease and security, not of a life of arduous struggle. Modern methods of production have given us the possibility of ease and security for all; we have chosen, instead, to have overwork for some and starvation for others. Hitherto we have continued to be as energetic as we were before there were machines; in this we have been foolish, but there is no reason to go on being foolish forever. + +[1] Since then, members of the Communist Party have succeeded to this privilege of the warriors and priests. diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/wrap.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/wrap.js new file mode 100644 index 0000000..0cfb76d --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/wrap.js @@ -0,0 +1,31 @@ +var assert = require('assert'); +var wordwrap = require('wordwrap'); + +var fs = require('fs'); +var idleness = fs.readFileSync(__dirname + '/idleness.txt', 'utf8'); + +exports.stop80 = function () { + var lines = wordwrap(80)(idleness).split(/\n/); + var words = idleness.split(/\s+/); + + lines.forEach(function (line) { + assert.ok(line.length <= 80, 'line > 80 columns'); + var chunks = line.match(/\S/) ? line.split(/\s+/) : []; + assert.deepEqual(chunks, words.splice(0, chunks.length)); + }); +}; + +exports.start20stop60 = function () { + var lines = wordwrap(20, 100)(idleness).split(/\n/); + var words = idleness.split(/\s+/); + + lines.forEach(function (line) { + assert.ok(line.length <= 100, 'line > 100 columns'); + var chunks = line + .split(/\s+/) + .filter(function (x) { return x.match(/\S/) }) + ; + assert.deepEqual(chunks, words.splice(0, chunks.length)); + assert.deepEqual(line.slice(0, 20), new Array(20 + 1).join(' ')); + }); +}; diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/package.json b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/package.json new file mode 100644 index 0000000..09cea5d --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/package.json @@ -0,0 +1,49 @@ +{ + "name": "optimist", + "version": "0.3.7", + "description": "Light-weight option parsing with an argv hash. No optstrings attached.", + "main": "./index.js", + "dependencies": { + "wordwrap": "~0.0.2" + }, + "devDependencies": { + "hashish": "~0.0.4", + "tap": "~0.4.0" + }, + "scripts": { + "test": "tap ./test/*.js" + }, + "repository": { + "type": "git", + "url": "http://github.com/substack/node-optimist.git" + }, + "keywords": [ + "argument", + "args", + "option", + "parser", + "parsing", + "cli", + "command" + ], + "author": { + "name": "James Halliday", + "email": "mail@substack.net", + "url": "http://substack.net" + }, + "license": "MIT/X11", + "engine": { + "node": ">=0.4" + }, + "readme": "optimist\n========\n\nOptimist is a node.js library for option parsing for people who hate option\nparsing. More specifically, this module is for people who like all the --bells\nand -whistlz of program usage but think optstrings are a waste of time.\n\nWith optimist, option parsing doesn't have to suck (as much).\n\n[![build status](https://secure.travis-ci.org/substack/node-optimist.png)](http://travis-ci.org/substack/node-optimist)\n\nexamples\n========\n\nWith Optimist, the options are just a hash! No optstrings attached.\n-------------------------------------------------------------------\n\nxup.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist').argv;\n\nif (argv.rif - 5 * argv.xup > 7.138) {\n console.log('Buy more riffiwobbles');\n}\nelse {\n console.log('Sell the xupptumblers');\n}\n````\n\n***\n\n $ ./xup.js --rif=55 --xup=9.52\n Buy more riffiwobbles\n \n $ ./xup.js --rif 12 --xup 8.1\n Sell the xupptumblers\n\n![This one's optimistic.](http://substack.net/images/optimistic.png)\n\nBut wait! There's more! You can do short options:\n-------------------------------------------------\n \nshort.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist').argv;\nconsole.log('(%d,%d)', argv.x, argv.y);\n````\n\n***\n\n $ ./short.js -x 10 -y 21\n (10,21)\n\nAnd booleans, both long and short (and grouped):\n----------------------------------\n\nbool.js:\n\n````javascript\n#!/usr/bin/env node\nvar util = require('util');\nvar argv = require('optimist').argv;\n\nif (argv.s) {\n util.print(argv.fr ? 'Le chat dit: ' : 'The cat says: ');\n}\nconsole.log(\n (argv.fr ? 'miaou' : 'meow') + (argv.p ? '.' : '')\n);\n````\n\n***\n\n $ ./bool.js -s\n The cat says: meow\n \n $ ./bool.js -sp\n The cat says: meow.\n\n $ ./bool.js -sp --fr\n Le chat dit: miaou.\n\nAnd non-hypenated options too! Just use `argv._`!\n-------------------------------------------------\n \nnonopt.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist').argv;\nconsole.log('(%d,%d)', argv.x, argv.y);\nconsole.log(argv._);\n````\n\n***\n\n $ ./nonopt.js -x 6.82 -y 3.35 moo\n (6.82,3.35)\n [ 'moo' ]\n \n $ ./nonopt.js foo -x 0.54 bar -y 1.12 baz\n (0.54,1.12)\n [ 'foo', 'bar', 'baz' ]\n\nPlus, Optimist comes with .usage() and .demand()!\n-------------------------------------------------\n\ndivide.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .usage('Usage: $0 -x [num] -y [num]')\n .demand(['x','y'])\n .argv;\n\nconsole.log(argv.x / argv.y);\n````\n\n***\n \n $ ./divide.js -x 55 -y 11\n 5\n \n $ node ./divide.js -x 4.91 -z 2.51\n Usage: node ./divide.js -x [num] -y [num]\n\n Options:\n -x [required]\n -y [required]\n\n Missing required arguments: y\n\nEVEN MORE HOLY COW\n------------------\n\ndefault_singles.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .default('x', 10)\n .default('y', 10)\n .argv\n;\nconsole.log(argv.x + argv.y);\n````\n\n***\n\n $ ./default_singles.js -x 5\n 15\n\ndefault_hash.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .default({ x : 10, y : 10 })\n .argv\n;\nconsole.log(argv.x + argv.y);\n````\n\n***\n\n $ ./default_hash.js -y 7\n 17\n\nAnd if you really want to get all descriptive about it...\n---------------------------------------------------------\n\nboolean_single.js\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .boolean('v')\n .argv\n;\nconsole.dir(argv);\n````\n\n***\n\n $ ./boolean_single.js -v foo bar baz\n true\n [ 'bar', 'baz', 'foo' ]\n\nboolean_double.js\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .boolean(['x','y','z'])\n .argv\n;\nconsole.dir([ argv.x, argv.y, argv.z ]);\nconsole.dir(argv._);\n````\n\n***\n\n $ ./boolean_double.js -x -z one two three\n [ true, false, true ]\n [ 'one', 'two', 'three' ]\n\nOptimist is here to help...\n---------------------------\n\nYou can describe parameters for help messages and set aliases. Optimist figures\nout how to format a handy help string automatically.\n\nline_count.js\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .usage('Count the lines in a file.\\nUsage: $0')\n .demand('f')\n .alias('f', 'file')\n .describe('f', 'Load a file')\n .argv\n;\n\nvar fs = require('fs');\nvar s = fs.createReadStream(argv.file);\n\nvar lines = 0;\ns.on('data', function (buf) {\n lines += buf.toString().match(/\\n/g).length;\n});\n\ns.on('end', function () {\n console.log(lines);\n});\n````\n\n***\n\n $ node line_count.js\n Count the lines in a file.\n Usage: node ./line_count.js\n\n Options:\n -f, --file Load a file [required]\n\n Missing required arguments: f\n\n $ node line_count.js --file line_count.js \n 20\n \n $ node line_count.js -f line_count.js \n 20\n\nmethods\n=======\n\nBy itself,\n\n````javascript\nrequire('optimist').argv\n`````\n\nwill use `process.argv` array to construct the `argv` object.\n\nYou can pass in the `process.argv` yourself:\n\n````javascript\nrequire('optimist')([ '-x', '1', '-y', '2' ]).argv\n````\n\nor use .parse() to do the same thing:\n\n````javascript\nrequire('optimist').parse([ '-x', '1', '-y', '2' ])\n````\n\nThe rest of these methods below come in just before the terminating `.argv`.\n\n.alias(key, alias)\n------------------\n\nSet key names as equivalent such that updates to a key will propagate to aliases\nand vice-versa.\n\nOptionally `.alias()` can take an object that maps keys to aliases.\n\n.default(key, value)\n--------------------\n\nSet `argv[key]` to `value` if no option was specified on `process.argv`.\n\nOptionally `.default()` can take an object that maps keys to default values.\n\n.demand(key)\n------------\n\nIf `key` is a string, show the usage information and exit if `key` wasn't\nspecified in `process.argv`.\n\nIf `key` is a number, demand at least as many non-option arguments, which show\nup in `argv._`.\n\nIf `key` is an Array, demand each element.\n\n.describe(key, desc)\n--------------------\n\nDescribe a `key` for the generated usage information.\n\nOptionally `.describe()` can take an object that maps keys to descriptions.\n\n.options(key, opt)\n------------------\n\nInstead of chaining together `.alias().demand().default()`, you can specify\nkeys in `opt` for each of the chainable methods.\n\nFor example:\n\n````javascript\nvar argv = require('optimist')\n .options('f', {\n alias : 'file',\n default : '/etc/passwd',\n })\n .argv\n;\n````\n\nis the same as\n\n````javascript\nvar argv = require('optimist')\n .alias('f', 'file')\n .default('f', '/etc/passwd')\n .argv\n;\n````\n\nOptionally `.options()` can take an object that maps keys to `opt` parameters.\n\n.usage(message)\n---------------\n\nSet a usage message to show which commands to use. Inside `message`, the string\n`$0` will get interpolated to the current script name or node command for the\npresent script similar to how `$0` works in bash or perl.\n\n.check(fn)\n----------\n\nCheck that certain conditions are met in the provided arguments.\n\nIf `fn` throws or returns `false`, show the thrown error, usage information, and\nexit.\n\n.boolean(key)\n-------------\n\nInterpret `key` as a boolean. If a non-flag option follows `key` in\n`process.argv`, that string won't get set as the value of `key`.\n\nIf `key` never shows up as a flag in `process.arguments`, `argv[key]` will be\n`false`.\n\nIf `key` is an Array, interpret all the elements as booleans.\n\n.string(key)\n------------\n\nTell the parser logic not to interpret `key` as a number or boolean.\nThis can be useful if you need to preserve leading zeros in an input.\n\nIf `key` is an Array, interpret all the elements as strings.\n\n.wrap(columns)\n--------------\n\nFormat usage output to wrap at `columns` many columns.\n\n.help()\n-------\n\nReturn the generated usage string.\n\n.showHelp(fn=console.error)\n---------------------------\n\nPrint the usage data using `fn` for printing.\n\n.parse(args)\n------------\n\nParse `args` instead of `process.argv`. Returns the `argv` object.\n\n.argv\n-----\n\nGet the arguments as a plain old object.\n\nArguments without a corresponding flag show up in the `argv._` array.\n\nThe script name or node command is available at `argv.$0` similarly to how `$0`\nworks in bash or perl.\n\nparsing tricks\n==============\n\nstop parsing\n------------\n\nUse `--` to stop parsing flags and stuff the remainder into `argv._`.\n\n $ node examples/reflect.js -a 1 -b 2 -- -c 3 -d 4\n { _: [ '-c', '3', '-d', '4' ],\n '$0': 'node ./examples/reflect.js',\n a: 1,\n b: 2 }\n\nnegate fields\n-------------\n\nIf you want to explicity set a field to false instead of just leaving it\nundefined or to override a default you can do `--no-key`.\n\n $ node examples/reflect.js -a --no-b\n { _: [],\n '$0': 'node ./examples/reflect.js',\n a: true,\n b: false }\n\nnumbers\n-------\n\nEvery argument that looks like a number (`!isNaN(Number(arg))`) is converted to\none. This way you can just `net.createConnection(argv.port)` and you can add\nnumbers out of `argv` with `+` without having that mean concatenation,\nwhich is super frustrating.\n\nduplicates\n----------\n\nIf you specify a flag multiple times it will get turned into an array containing\nall the values in order.\n\n $ node examples/reflect.js -x 5 -x 8 -x 0\n { _: [],\n '$0': 'node ./examples/reflect.js',\n x: [ 5, 8, 0 ] }\n\ndot notation\n------------\n\nWhen you use dots (`.`s) in argument names, an implicit object path is assumed.\nThis lets you organize arguments into nested objects.\n\n $ node examples/reflect.js --foo.bar.baz=33 --foo.quux=5\n { _: [],\n '$0': 'node ./examples/reflect.js',\n foo: { bar: { baz: 33 }, quux: 5 } }\n\ninstallation\n============\n\nWith [npm](http://github.com/isaacs/npm), just do:\n npm install optimist\n \nor clone this project on github:\n\n git clone http://github.com/substack/node-optimist.git\n\nTo run the tests with [expresso](http://github.com/visionmedia/expresso),\njust do:\n \n expresso\n\ninspired By\n===========\n\nThis module is loosely inspired by Perl's\n[Getopt::Casual](http://search.cpan.org/~photo/Getopt-Casual-0.13.1/Casual.pm).\n", + "readmeFilename": "readme.markdown", + "bugs": { + "url": "https://github.com/substack/node-optimist/issues" + }, + "_id": "optimist@0.3.7", + "dist": { + "shasum": "cdd8eb13a6408cac46182ebcb0fd831d98133bd0" + }, + "_from": "optimist@~0.3.5", + "_resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz" +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/readme.markdown b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/readme.markdown new file mode 100644 index 0000000..ad9d3fd --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/readme.markdown @@ -0,0 +1,487 @@ +optimist +======== + +Optimist is a node.js library for option parsing for people who hate option +parsing. More specifically, this module is for people who like all the --bells +and -whistlz of program usage but think optstrings are a waste of time. + +With optimist, option parsing doesn't have to suck (as much). + +[![build status](https://secure.travis-ci.org/substack/node-optimist.png)](http://travis-ci.org/substack/node-optimist) + +examples +======== + +With Optimist, the options are just a hash! No optstrings attached. +------------------------------------------------------------------- + +xup.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist').argv; + +if (argv.rif - 5 * argv.xup > 7.138) { + console.log('Buy more riffiwobbles'); +} +else { + console.log('Sell the xupptumblers'); +} +```` + +*** + + $ ./xup.js --rif=55 --xup=9.52 + Buy more riffiwobbles + + $ ./xup.js --rif 12 --xup 8.1 + Sell the xupptumblers + +![This one's optimistic.](http://substack.net/images/optimistic.png) + +But wait! There's more! You can do short options: +------------------------------------------------- + +short.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist').argv; +console.log('(%d,%d)', argv.x, argv.y); +```` + +*** + + $ ./short.js -x 10 -y 21 + (10,21) + +And booleans, both long and short (and grouped): +---------------------------------- + +bool.js: + +````javascript +#!/usr/bin/env node +var util = require('util'); +var argv = require('optimist').argv; + +if (argv.s) { + util.print(argv.fr ? 'Le chat dit: ' : 'The cat says: '); +} +console.log( + (argv.fr ? 'miaou' : 'meow') + (argv.p ? '.' : '') +); +```` + +*** + + $ ./bool.js -s + The cat says: meow + + $ ./bool.js -sp + The cat says: meow. + + $ ./bool.js -sp --fr + Le chat dit: miaou. + +And non-hypenated options too! Just use `argv._`! +------------------------------------------------- + +nonopt.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist').argv; +console.log('(%d,%d)', argv.x, argv.y); +console.log(argv._); +```` + +*** + + $ ./nonopt.js -x 6.82 -y 3.35 moo + (6.82,3.35) + [ 'moo' ] + + $ ./nonopt.js foo -x 0.54 bar -y 1.12 baz + (0.54,1.12) + [ 'foo', 'bar', 'baz' ] + +Plus, Optimist comes with .usage() and .demand()! +------------------------------------------------- + +divide.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .usage('Usage: $0 -x [num] -y [num]') + .demand(['x','y']) + .argv; + +console.log(argv.x / argv.y); +```` + +*** + + $ ./divide.js -x 55 -y 11 + 5 + + $ node ./divide.js -x 4.91 -z 2.51 + Usage: node ./divide.js -x [num] -y [num] + + Options: + -x [required] + -y [required] + + Missing required arguments: y + +EVEN MORE HOLY COW +------------------ + +default_singles.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .default('x', 10) + .default('y', 10) + .argv +; +console.log(argv.x + argv.y); +```` + +*** + + $ ./default_singles.js -x 5 + 15 + +default_hash.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .default({ x : 10, y : 10 }) + .argv +; +console.log(argv.x + argv.y); +```` + +*** + + $ ./default_hash.js -y 7 + 17 + +And if you really want to get all descriptive about it... +--------------------------------------------------------- + +boolean_single.js + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .boolean('v') + .argv +; +console.dir(argv); +```` + +*** + + $ ./boolean_single.js -v foo bar baz + true + [ 'bar', 'baz', 'foo' ] + +boolean_double.js + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .boolean(['x','y','z']) + .argv +; +console.dir([ argv.x, argv.y, argv.z ]); +console.dir(argv._); +```` + +*** + + $ ./boolean_double.js -x -z one two three + [ true, false, true ] + [ 'one', 'two', 'three' ] + +Optimist is here to help... +--------------------------- + +You can describe parameters for help messages and set aliases. Optimist figures +out how to format a handy help string automatically. + +line_count.js + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .usage('Count the lines in a file.\nUsage: $0') + .demand('f') + .alias('f', 'file') + .describe('f', 'Load a file') + .argv +; + +var fs = require('fs'); +var s = fs.createReadStream(argv.file); + +var lines = 0; +s.on('data', function (buf) { + lines += buf.toString().match(/\n/g).length; +}); + +s.on('end', function () { + console.log(lines); +}); +```` + +*** + + $ node line_count.js + Count the lines in a file. + Usage: node ./line_count.js + + Options: + -f, --file Load a file [required] + + Missing required arguments: f + + $ node line_count.js --file line_count.js + 20 + + $ node line_count.js -f line_count.js + 20 + +methods +======= + +By itself, + +````javascript +require('optimist').argv +````` + +will use `process.argv` array to construct the `argv` object. + +You can pass in the `process.argv` yourself: + +````javascript +require('optimist')([ '-x', '1', '-y', '2' ]).argv +```` + +or use .parse() to do the same thing: + +````javascript +require('optimist').parse([ '-x', '1', '-y', '2' ]) +```` + +The rest of these methods below come in just before the terminating `.argv`. + +.alias(key, alias) +------------------ + +Set key names as equivalent such that updates to a key will propagate to aliases +and vice-versa. + +Optionally `.alias()` can take an object that maps keys to aliases. + +.default(key, value) +-------------------- + +Set `argv[key]` to `value` if no option was specified on `process.argv`. + +Optionally `.default()` can take an object that maps keys to default values. + +.demand(key) +------------ + +If `key` is a string, show the usage information and exit if `key` wasn't +specified in `process.argv`. + +If `key` is a number, demand at least as many non-option arguments, which show +up in `argv._`. + +If `key` is an Array, demand each element. + +.describe(key, desc) +-------------------- + +Describe a `key` for the generated usage information. + +Optionally `.describe()` can take an object that maps keys to descriptions. + +.options(key, opt) +------------------ + +Instead of chaining together `.alias().demand().default()`, you can specify +keys in `opt` for each of the chainable methods. + +For example: + +````javascript +var argv = require('optimist') + .options('f', { + alias : 'file', + default : '/etc/passwd', + }) + .argv +; +```` + +is the same as + +````javascript +var argv = require('optimist') + .alias('f', 'file') + .default('f', '/etc/passwd') + .argv +; +```` + +Optionally `.options()` can take an object that maps keys to `opt` parameters. + +.usage(message) +--------------- + +Set a usage message to show which commands to use. Inside `message`, the string +`$0` will get interpolated to the current script name or node command for the +present script similar to how `$0` works in bash or perl. + +.check(fn) +---------- + +Check that certain conditions are met in the provided arguments. + +If `fn` throws or returns `false`, show the thrown error, usage information, and +exit. + +.boolean(key) +------------- + +Interpret `key` as a boolean. If a non-flag option follows `key` in +`process.argv`, that string won't get set as the value of `key`. + +If `key` never shows up as a flag in `process.arguments`, `argv[key]` will be +`false`. + +If `key` is an Array, interpret all the elements as booleans. + +.string(key) +------------ + +Tell the parser logic not to interpret `key` as a number or boolean. +This can be useful if you need to preserve leading zeros in an input. + +If `key` is an Array, interpret all the elements as strings. + +.wrap(columns) +-------------- + +Format usage output to wrap at `columns` many columns. + +.help() +------- + +Return the generated usage string. + +.showHelp(fn=console.error) +--------------------------- + +Print the usage data using `fn` for printing. + +.parse(args) +------------ + +Parse `args` instead of `process.argv`. Returns the `argv` object. + +.argv +----- + +Get the arguments as a plain old object. + +Arguments without a corresponding flag show up in the `argv._` array. + +The script name or node command is available at `argv.$0` similarly to how `$0` +works in bash or perl. + +parsing tricks +============== + +stop parsing +------------ + +Use `--` to stop parsing flags and stuff the remainder into `argv._`. + + $ node examples/reflect.js -a 1 -b 2 -- -c 3 -d 4 + { _: [ '-c', '3', '-d', '4' ], + '$0': 'node ./examples/reflect.js', + a: 1, + b: 2 } + +negate fields +------------- + +If you want to explicity set a field to false instead of just leaving it +undefined or to override a default you can do `--no-key`. + + $ node examples/reflect.js -a --no-b + { _: [], + '$0': 'node ./examples/reflect.js', + a: true, + b: false } + +numbers +------- + +Every argument that looks like a number (`!isNaN(Number(arg))`) is converted to +one. This way you can just `net.createConnection(argv.port)` and you can add +numbers out of `argv` with `+` without having that mean concatenation, +which is super frustrating. + +duplicates +---------- + +If you specify a flag multiple times it will get turned into an array containing +all the values in order. + + $ node examples/reflect.js -x 5 -x 8 -x 0 + { _: [], + '$0': 'node ./examples/reflect.js', + x: [ 5, 8, 0 ] } + +dot notation +------------ + +When you use dots (`.`s) in argument names, an implicit object path is assumed. +This lets you organize arguments into nested objects. + + $ node examples/reflect.js --foo.bar.baz=33 --foo.quux=5 + { _: [], + '$0': 'node ./examples/reflect.js', + foo: { bar: { baz: 33 }, quux: 5 } } + +installation +============ + +With [npm](http://github.com/isaacs/npm), just do: + npm install optimist + +or clone this project on github: + + git clone http://github.com/substack/node-optimist.git + +To run the tests with [expresso](http://github.com/visionmedia/expresso), +just do: + + expresso + +inspired By +=========== + +This module is loosely inspired by Perl's +[Getopt::Casual](http://search.cpan.org/~photo/Getopt-Casual-0.13.1/Casual.pm). diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/test/_.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/test/_.js new file mode 100644 index 0000000..d9c58b3 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/test/_.js @@ -0,0 +1,71 @@ +var spawn = require('child_process').spawn; +var test = require('tap').test; + +test('dotSlashEmpty', testCmd('./bin.js', [])); + +test('dotSlashArgs', testCmd('./bin.js', [ 'a', 'b', 'c' ])); + +test('nodeEmpty', testCmd('node bin.js', [])); + +test('nodeArgs', testCmd('node bin.js', [ 'x', 'y', 'z' ])); + +test('whichNodeEmpty', function (t) { + var which = spawn('which', ['node']); + + which.stdout.on('data', function (buf) { + t.test( + testCmd(buf.toString().trim() + ' bin.js', []) + ); + t.end(); + }); + + which.stderr.on('data', function (err) { + assert.error(err); + t.end(); + }); +}); + +test('whichNodeArgs', function (t) { + var which = spawn('which', ['node']); + + which.stdout.on('data', function (buf) { + t.test( + testCmd(buf.toString().trim() + ' bin.js', [ 'q', 'r' ]) + ); + t.end(); + }); + + which.stderr.on('data', function (err) { + t.error(err); + t.end(); + }); +}); + +function testCmd (cmd, args) { + + return function (t) { + var to = setTimeout(function () { + assert.fail('Never got stdout data.') + }, 5000); + + var oldDir = process.cwd(); + process.chdir(__dirname + '/_'); + + var cmds = cmd.split(' '); + + var bin = spawn(cmds[0], cmds.slice(1).concat(args.map(String))); + process.chdir(oldDir); + + bin.stderr.on('data', function (err) { + t.error(err); + t.end(); + }); + + bin.stdout.on('data', function (buf) { + clearTimeout(to); + var _ = JSON.parse(buf.toString()); + t.same(_.map(String), args.map(String)); + t.end(); + }); + }; +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/test/_/argv.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/test/_/argv.js new file mode 100644 index 0000000..3d09606 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/test/_/argv.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +console.log(JSON.stringify(process.argv)); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/test/_/bin.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/test/_/bin.js new file mode 100755 index 0000000..4a18d85 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/test/_/bin.js @@ -0,0 +1,3 @@ +#!/usr/bin/env node +var argv = require('../../index').argv +console.log(JSON.stringify(argv._)); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/test/parse.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/test/parse.js new file mode 100644 index 0000000..d320f43 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/test/parse.js @@ -0,0 +1,446 @@ +var optimist = require('../index'); +var path = require('path'); +var test = require('tap').test; + +var $0 = 'node ./' + path.relative(process.cwd(), __filename); + +test('short boolean', function (t) { + var parse = optimist.parse([ '-b' ]); + t.same(parse, { b : true, _ : [], $0 : $0 }); + t.same(typeof parse.b, 'boolean'); + t.end(); +}); + +test('long boolean', function (t) { + t.same( + optimist.parse([ '--bool' ]), + { bool : true, _ : [], $0 : $0 } + ); + t.end(); +}); + +test('bare', function (t) { + t.same( + optimist.parse([ 'foo', 'bar', 'baz' ]), + { _ : [ 'foo', 'bar', 'baz' ], $0 : $0 } + ); + t.end(); +}); + +test('short group', function (t) { + t.same( + optimist.parse([ '-cats' ]), + { c : true, a : true, t : true, s : true, _ : [], $0 : $0 } + ); + t.end(); +}); + +test('short group next', function (t) { + t.same( + optimist.parse([ '-cats', 'meow' ]), + { c : true, a : true, t : true, s : 'meow', _ : [], $0 : $0 } + ); + t.end(); +}); + +test('short capture', function (t) { + t.same( + optimist.parse([ '-h', 'localhost' ]), + { h : 'localhost', _ : [], $0 : $0 } + ); + t.end(); +}); + +test('short captures', function (t) { + t.same( + optimist.parse([ '-h', 'localhost', '-p', '555' ]), + { h : 'localhost', p : 555, _ : [], $0 : $0 } + ); + t.end(); +}); + +test('long capture sp', function (t) { + t.same( + optimist.parse([ '--pow', 'xixxle' ]), + { pow : 'xixxle', _ : [], $0 : $0 } + ); + t.end(); +}); + +test('long capture eq', function (t) { + t.same( + optimist.parse([ '--pow=xixxle' ]), + { pow : 'xixxle', _ : [], $0 : $0 } + ); + t.end() +}); + +test('long captures sp', function (t) { + t.same( + optimist.parse([ '--host', 'localhost', '--port', '555' ]), + { host : 'localhost', port : 555, _ : [], $0 : $0 } + ); + t.end(); +}); + +test('long captures eq', function (t) { + t.same( + optimist.parse([ '--host=localhost', '--port=555' ]), + { host : 'localhost', port : 555, _ : [], $0 : $0 } + ); + t.end(); +}); + +test('mixed short bool and capture', function (t) { + t.same( + optimist.parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]), + { + f : true, p : 555, h : 'localhost', + _ : [ 'script.js' ], $0 : $0, + } + ); + t.end(); +}); + +test('short and long', function (t) { + t.same( + optimist.parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]), + { + f : true, p : 555, h : 'localhost', + _ : [ 'script.js' ], $0 : $0, + } + ); + t.end(); +}); + +test('no', function (t) { + t.same( + optimist.parse([ '--no-moo' ]), + { moo : false, _ : [], $0 : $0 } + ); + t.end(); +}); + +test('multi', function (t) { + t.same( + optimist.parse([ '-v', 'a', '-v', 'b', '-v', 'c' ]), + { v : ['a','b','c'], _ : [], $0 : $0 } + ); + t.end(); +}); + +test('comprehensive', function (t) { + t.same( + optimist.parse([ + '--name=meowmers', 'bare', '-cats', 'woo', + '-h', 'awesome', '--multi=quux', + '--key', 'value', + '-b', '--bool', '--no-meep', '--multi=baz', + '--', '--not-a-flag', 'eek' + ]), + { + c : true, + a : true, + t : true, + s : 'woo', + h : 'awesome', + b : true, + bool : true, + key : 'value', + multi : [ 'quux', 'baz' ], + meep : false, + name : 'meowmers', + _ : [ 'bare', '--not-a-flag', 'eek' ], + $0 : $0 + } + ); + t.end(); +}); + +test('nums', function (t) { + var argv = optimist.parse([ + '-x', '1234', + '-y', '5.67', + '-z', '1e7', + '-w', '10f', + '--hex', '0xdeadbeef', + '789', + ]); + t.same(argv, { + x : 1234, + y : 5.67, + z : 1e7, + w : '10f', + hex : 0xdeadbeef, + _ : [ 789 ], + $0 : $0 + }); + t.same(typeof argv.x, 'number'); + t.same(typeof argv.y, 'number'); + t.same(typeof argv.z, 'number'); + t.same(typeof argv.w, 'string'); + t.same(typeof argv.hex, 'number'); + t.same(typeof argv._[0], 'number'); + t.end(); +}); + +test('flag boolean', function (t) { + var parse = optimist([ '-t', 'moo' ]).boolean(['t']).argv; + t.same(parse, { t : true, _ : [ 'moo' ], $0 : $0 }); + t.same(typeof parse.t, 'boolean'); + t.end(); +}); + +test('flag boolean value', function (t) { + var parse = optimist(['--verbose', 'false', 'moo', '-t', 'true']) + .boolean(['t', 'verbose']).default('verbose', true).argv; + + t.same(parse, { + verbose: false, + t: true, + _: ['moo'], + $0 : $0 + }); + + t.same(typeof parse.verbose, 'boolean'); + t.same(typeof parse.t, 'boolean'); + t.end(); +}); + +test('flag boolean default false', function (t) { + var parse = optimist(['moo']) + .boolean(['t', 'verbose']) + .default('verbose', false) + .default('t', false).argv; + + t.same(parse, { + verbose: false, + t: false, + _: ['moo'], + $0 : $0 + }); + + t.same(typeof parse.verbose, 'boolean'); + t.same(typeof parse.t, 'boolean'); + t.end(); + +}); + +test('boolean groups', function (t) { + var parse = optimist([ '-x', '-z', 'one', 'two', 'three' ]) + .boolean(['x','y','z']).argv; + + t.same(parse, { + x : true, + y : false, + z : true, + _ : [ 'one', 'two', 'three' ], + $0 : $0 + }); + + t.same(typeof parse.x, 'boolean'); + t.same(typeof parse.y, 'boolean'); + t.same(typeof parse.z, 'boolean'); + t.end(); +}); + +test('newlines in params' , function (t) { + var args = optimist.parse([ '-s', "X\nX" ]) + t.same(args, { _ : [], s : "X\nX", $0 : $0 }); + + // reproduce in bash: + // VALUE="new + // line" + // node program.js --s="$VALUE" + args = optimist.parse([ "--s=X\nX" ]) + t.same(args, { _ : [], s : "X\nX", $0 : $0 }); + t.end(); +}); + +test('strings' , function (t) { + var s = optimist([ '-s', '0001234' ]).string('s').argv.s; + t.same(s, '0001234'); + t.same(typeof s, 'string'); + + var x = optimist([ '-x', '56' ]).string('x').argv.x; + t.same(x, '56'); + t.same(typeof x, 'string'); + t.end(); +}); + +test('stringArgs', function (t) { + var s = optimist([ ' ', ' ' ]).string('_').argv._; + t.same(s.length, 2); + t.same(typeof s[0], 'string'); + t.same(s[0], ' '); + t.same(typeof s[1], 'string'); + t.same(s[1], ' '); + t.end(); +}); + +test('slashBreak', function (t) { + t.same( + optimist.parse([ '-I/foo/bar/baz' ]), + { I : '/foo/bar/baz', _ : [], $0 : $0 } + ); + t.same( + optimist.parse([ '-xyz/foo/bar/baz' ]), + { x : true, y : true, z : '/foo/bar/baz', _ : [], $0 : $0 } + ); + t.end(); +}); + +test('alias', function (t) { + var argv = optimist([ '-f', '11', '--zoom', '55' ]) + .alias('z', 'zoom') + .argv + ; + t.equal(argv.zoom, 55); + t.equal(argv.z, argv.zoom); + t.equal(argv.f, 11); + t.end(); +}); + +test('multiAlias', function (t) { + var argv = optimist([ '-f', '11', '--zoom', '55' ]) + .alias('z', [ 'zm', 'zoom' ]) + .argv + ; + t.equal(argv.zoom, 55); + t.equal(argv.z, argv.zoom); + t.equal(argv.z, argv.zm); + t.equal(argv.f, 11); + t.end(); +}); + +test('boolean default true', function (t) { + var argv = optimist.options({ + sometrue: { + boolean: true, + default: true + } + }).argv; + + t.equal(argv.sometrue, true); + t.end(); +}); + +test('boolean default false', function (t) { + var argv = optimist.options({ + somefalse: { + boolean: true, + default: false + } + }).argv; + + t.equal(argv.somefalse, false); + t.end(); +}); + +test('nested dotted objects', function (t) { + var argv = optimist([ + '--foo.bar', '3', '--foo.baz', '4', + '--foo.quux.quibble', '5', '--foo.quux.o_O', + '--beep.boop' + ]).argv; + + t.same(argv.foo, { + bar : 3, + baz : 4, + quux : { + quibble : 5, + o_O : true + }, + }); + t.same(argv.beep, { boop : true }); + t.end(); +}); + +test('boolean and alias with chainable api', function (t) { + var aliased = [ '-h', 'derp' ]; + var regular = [ '--herp', 'derp' ]; + var opts = { + herp: { alias: 'h', boolean: true } + }; + var aliasedArgv = optimist(aliased) + .boolean('herp') + .alias('h', 'herp') + .argv; + var propertyArgv = optimist(regular) + .boolean('herp') + .alias('h', 'herp') + .argv; + var expected = { + herp: true, + h: true, + '_': [ 'derp' ], + '$0': $0, + }; + + t.same(aliasedArgv, expected); + t.same(propertyArgv, expected); + t.end(); +}); + +test('boolean and alias with options hash', function (t) { + var aliased = [ '-h', 'derp' ]; + var regular = [ '--herp', 'derp' ]; + var opts = { + herp: { alias: 'h', boolean: true } + }; + var aliasedArgv = optimist(aliased) + .options(opts) + .argv; + var propertyArgv = optimist(regular).options(opts).argv; + var expected = { + herp: true, + h: true, + '_': [ 'derp' ], + '$0': $0, + }; + + t.same(aliasedArgv, expected); + t.same(propertyArgv, expected); + + t.end(); +}); + +test('boolean and alias using explicit true', function (t) { + var aliased = [ '-h', 'true' ]; + var regular = [ '--herp', 'true' ]; + var opts = { + herp: { alias: 'h', boolean: true } + }; + var aliasedArgv = optimist(aliased) + .boolean('h') + .alias('h', 'herp') + .argv; + var propertyArgv = optimist(regular) + .boolean('h') + .alias('h', 'herp') + .argv; + var expected = { + herp: true, + h: true, + '_': [ ], + '$0': $0, + }; + + t.same(aliasedArgv, expected); + t.same(propertyArgv, expected); + t.end(); +}); + +// regression, see https://github.com/substack/node-optimist/issues/71 +test('boolean and --x=true', function(t) { + var parsed = optimist(['--boool', '--other=true']).boolean('boool').argv; + + t.same(parsed.boool, true); + t.same(parsed.other, 'true'); + + parsed = optimist(['--boool', '--other=false']).boolean('boool').argv; + + t.same(parsed.boool, true); + t.same(parsed.other, 'false'); + t.end(); +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/test/usage.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/test/usage.js new file mode 100644 index 0000000..300454c --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/optimist/test/usage.js @@ -0,0 +1,292 @@ +var Hash = require('hashish'); +var optimist = require('../index'); +var test = require('tap').test; + +test('usageFail', function (t) { + var r = checkUsage(function () { + return optimist('-x 10 -z 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .demand(['x','y']) + .argv; + }); + t.same( + r.result, + { x : 10, z : 20, _ : [], $0 : './usage' } + ); + + t.same( + r.errors.join('\n').split(/\n+/), + [ + 'Usage: ./usage -x NUM -y NUM', + 'Options:', + ' -x [required]', + ' -y [required]', + 'Missing required arguments: y', + ] + ); + t.same(r.logs, []); + t.ok(r.exit); + t.end(); +}); + + +test('usagePass', function (t) { + var r = checkUsage(function () { + return optimist('-x 10 -y 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .demand(['x','y']) + .argv; + }); + t.same(r, { + result : { x : 10, y : 20, _ : [], $0 : './usage' }, + errors : [], + logs : [], + exit : false, + }); + t.end(); +}); + +test('checkPass', function (t) { + var r = checkUsage(function () { + return optimist('-x 10 -y 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .check(function (argv) { + if (!('x' in argv)) throw 'You forgot about -x'; + if (!('y' in argv)) throw 'You forgot about -y'; + }) + .argv; + }); + t.same(r, { + result : { x : 10, y : 20, _ : [], $0 : './usage' }, + errors : [], + logs : [], + exit : false, + }); + t.end(); +}); + +test('checkFail', function (t) { + var r = checkUsage(function () { + return optimist('-x 10 -z 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .check(function (argv) { + if (!('x' in argv)) throw 'You forgot about -x'; + if (!('y' in argv)) throw 'You forgot about -y'; + }) + .argv; + }); + + t.same( + r.result, + { x : 10, z : 20, _ : [], $0 : './usage' } + ); + + t.same( + r.errors.join('\n').split(/\n+/), + [ + 'Usage: ./usage -x NUM -y NUM', + 'You forgot about -y' + ] + ); + + t.same(r.logs, []); + t.ok(r.exit); + t.end(); +}); + +test('checkCondPass', function (t) { + function checker (argv) { + return 'x' in argv && 'y' in argv; + } + + var r = checkUsage(function () { + return optimist('-x 10 -y 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .check(checker) + .argv; + }); + t.same(r, { + result : { x : 10, y : 20, _ : [], $0 : './usage' }, + errors : [], + logs : [], + exit : false, + }); + t.end(); +}); + +test('checkCondFail', function (t) { + function checker (argv) { + return 'x' in argv && 'y' in argv; + } + + var r = checkUsage(function () { + return optimist('-x 10 -z 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .check(checker) + .argv; + }); + + t.same( + r.result, + { x : 10, z : 20, _ : [], $0 : './usage' } + ); + + t.same( + r.errors.join('\n').split(/\n+/).join('\n'), + 'Usage: ./usage -x NUM -y NUM\n' + + 'Argument check failed: ' + checker.toString() + ); + + t.same(r.logs, []); + t.ok(r.exit); + t.end(); +}); + +test('countPass', function (t) { + var r = checkUsage(function () { + return optimist('1 2 3 --moo'.split(' ')) + .usage('Usage: $0 [x] [y] [z] {OPTIONS}') + .demand(3) + .argv; + }); + t.same(r, { + result : { _ : [ '1', '2', '3' ], moo : true, $0 : './usage' }, + errors : [], + logs : [], + exit : false, + }); + t.end(); +}); + +test('countFail', function (t) { + var r = checkUsage(function () { + return optimist('1 2 --moo'.split(' ')) + .usage('Usage: $0 [x] [y] [z] {OPTIONS}') + .demand(3) + .argv; + }); + t.same( + r.result, + { _ : [ '1', '2' ], moo : true, $0 : './usage' } + ); + + t.same( + r.errors.join('\n').split(/\n+/), + [ + 'Usage: ./usage [x] [y] [z] {OPTIONS}', + 'Not enough non-option arguments: got 2, need at least 3', + ] + ); + + t.same(r.logs, []); + t.ok(r.exit); + t.end(); +}); + +test('defaultSingles', function (t) { + var r = checkUsage(function () { + return optimist('--foo 50 --baz 70 --powsy'.split(' ')) + .default('foo', 5) + .default('bar', 6) + .default('baz', 7) + .argv + ; + }); + t.same(r.result, { + foo : '50', + bar : 6, + baz : '70', + powsy : true, + _ : [], + $0 : './usage', + }); + t.end(); +}); + +test('defaultAliases', function (t) { + var r = checkUsage(function () { + return optimist('') + .alias('f', 'foo') + .default('f', 5) + .argv + ; + }); + t.same(r.result, { + f : '5', + foo : '5', + _ : [], + $0 : './usage', + }); + t.end(); +}); + +test('defaultHash', function (t) { + var r = checkUsage(function () { + return optimist('--foo 50 --baz 70'.split(' ')) + .default({ foo : 10, bar : 20, quux : 30 }) + .argv + ; + }); + t.same(r.result, { + _ : [], + $0 : './usage', + foo : 50, + baz : 70, + bar : 20, + quux : 30, + }); + t.end(); +}); + +test('rebase', function (t) { + t.equal( + optimist.rebase('/home/substack', '/home/substack/foo/bar/baz'), + './foo/bar/baz' + ); + t.equal( + optimist.rebase('/home/substack/foo/bar/baz', '/home/substack'), + '../../..' + ); + t.equal( + optimist.rebase('/home/substack/foo', '/home/substack/pow/zoom.txt'), + '../pow/zoom.txt' + ); + t.end(); +}); + +function checkUsage (f) { + + var exit = false; + + process._exit = process.exit; + process._env = process.env; + process._argv = process.argv; + + process.exit = function (t) { exit = true }; + process.env = Hash.merge(process.env, { _ : 'node' }); + process.argv = [ './usage' ]; + + var errors = []; + var logs = []; + + console._error = console.error; + console.error = function (msg) { errors.push(msg) }; + console._log = console.log; + console.log = function (msg) { logs.push(msg) }; + + var result = f(); + + process.exit = process._exit; + process.env = process._env; + process.argv = process._argv; + + console.error = console._error; + console.log = console._log; + + return { + errors : errors, + logs : logs, + exit : exit, + result : result, + }; +}; diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/.npmignore b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/.npmignore new file mode 100644 index 0000000..3dddf3f --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/.npmignore @@ -0,0 +1,2 @@ +dist/* +node_modules/* diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/.travis.yml b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/.travis.yml new file mode 100644 index 0000000..ddc9c4f --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.8 + - "0.10" \ No newline at end of file diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/CHANGELOG.md b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/CHANGELOG.md new file mode 100644 index 0000000..98b90d5 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/CHANGELOG.md @@ -0,0 +1,112 @@ +# Change Log + +## 0.1.31 + +* Delay parsing the mappings in SourceMapConsumer until queried for a source + location. + +* Support Sass source maps (which at the time of writing deviate from the spec + in small ways) in SourceMapConsumer. + +## 0.1.30 + +* Do not join source root with a source, when the source is a data URI. + +* Extend the test runner to allow running single specific test files at a time. + +* Performance improvements in `SourceNode.prototype.walk` and + `SourceMapConsumer.prototype.eachMapping`. + +* Source map browser builds will now work inside Workers. + +* Better error messages when attempting to add an invalid mapping to a + `SourceMapGenerator`. + +## 0.1.29 + +* Allow duplicate entries in the `names` and `sources` arrays of source maps + (usually from TypeScript) we are parsing. Fixes github isse 72. + +## 0.1.28 + +* Skip duplicate mappings when creating source maps from SourceNode; github + issue 75. + +## 0.1.27 + +* Don't throw an error when the `file` property is missing in SourceMapConsumer, + we don't use it anyway. + +## 0.1.26 + +* Fix SourceNode.fromStringWithSourceMap for empty maps. Fixes github issue 70. + +## 0.1.25 + +* Make compatible with browserify + +## 0.1.24 + +* Fix issue with absolute paths and `file://` URIs. See + https://bugzilla.mozilla.org/show_bug.cgi?id=885597 + +## 0.1.23 + +* Fix issue with absolute paths and sourcesContent, github issue 64. + +## 0.1.22 + +* Ignore duplicate mappings in SourceMapGenerator. Fixes github issue 21. + +## 0.1.21 + +* Fixed handling of sources that start with a slash so that they are relative to + the source root's host. + +## 0.1.20 + +* Fixed github issue #43: absolute URLs aren't joined with the source root + anymore. + +## 0.1.19 + +* Using Travis CI to run tests. + +## 0.1.18 + +* Fixed a bug in the handling of sourceRoot. + +## 0.1.17 + +* Added SourceNode.fromStringWithSourceMap. + +## 0.1.16 + +* Added missing documentation. + +* Fixed the generating of empty mappings in SourceNode. + +## 0.1.15 + +* Added SourceMapGenerator.applySourceMap. + +## 0.1.14 + +* The sourceRoot is now handled consistently. + +## 0.1.13 + +* Added SourceMapGenerator.fromSourceMap. + +## 0.1.12 + +* SourceNode now generates empty mappings too. + +## 0.1.11 + +* Added name support to SourceNode. + +## 0.1.10 + +* Added sourcesContent support to the customer and generator. + diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/LICENSE b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/LICENSE new file mode 100644 index 0000000..ed1b7cf --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/LICENSE @@ -0,0 +1,28 @@ + +Copyright (c) 2009-2011, Mozilla Foundation and contributors +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 names of the Mozilla Foundation nor the names of project + 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/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/Makefile.dryice.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/Makefile.dryice.js new file mode 100644 index 0000000..d6fc26a --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/Makefile.dryice.js @@ -0,0 +1,166 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +var path = require('path'); +var fs = require('fs'); +var copy = require('dryice').copy; + +function removeAmdefine(src) { + src = String(src).replace( + /if\s*\(typeof\s*define\s*!==\s*'function'\)\s*{\s*var\s*define\s*=\s*require\('amdefine'\)\(module,\s*require\);\s*}\s*/g, + ''); + src = src.replace( + /\b(define\(.*)('amdefine',?)/gm, + '$1'); + return src; +} +removeAmdefine.onRead = true; + +function makeNonRelative(src) { + return src + .replace(/require\('.\//g, 'require(\'source-map/') + .replace(/\.\.\/\.\.\/lib\//g, ''); +} +makeNonRelative.onRead = true; + +function buildBrowser() { + console.log('\nCreating dist/source-map.js'); + + var project = copy.createCommonJsProject({ + roots: [ path.join(__dirname, 'lib') ] + }); + + copy({ + source: [ + 'build/mini-require.js', + { + project: project, + require: [ 'source-map/source-map-generator', + 'source-map/source-map-consumer', + 'source-map/source-node'] + }, + 'build/suffix-browser.js' + ], + filter: [ + copy.filter.moduleDefines, + removeAmdefine + ], + dest: 'dist/source-map.js' + }); +} + +function buildBrowserMin() { + console.log('\nCreating dist/source-map.min.js'); + + copy({ + source: 'dist/source-map.js', + filter: copy.filter.uglifyjs, + dest: 'dist/source-map.min.js' + }); +} + +function buildFirefox() { + console.log('\nCreating dist/SourceMap.jsm'); + + var project = copy.createCommonJsProject({ + roots: [ path.join(__dirname, 'lib') ] + }); + + copy({ + source: [ + 'build/prefix-source-map.jsm', + { + project: project, + require: [ 'source-map/source-map-consumer', + 'source-map/source-map-generator', + 'source-map/source-node' ] + }, + 'build/suffix-source-map.jsm' + ], + filter: [ + copy.filter.moduleDefines, + removeAmdefine, + makeNonRelative + ], + dest: 'dist/SourceMap.jsm' + }); + + // Create dist/test/Utils.jsm + console.log('\nCreating dist/test/Utils.jsm'); + + project = copy.createCommonJsProject({ + roots: [ __dirname, path.join(__dirname, 'lib') ] + }); + + copy({ + source: [ + 'build/prefix-utils.jsm', + 'build/assert-shim.js', + { + project: project, + require: [ 'test/source-map/util' ] + }, + 'build/suffix-utils.jsm' + ], + filter: [ + copy.filter.moduleDefines, + removeAmdefine, + makeNonRelative + ], + dest: 'dist/test/Utils.jsm' + }); + + function isTestFile(f) { + return /^test\-.*?\.js/.test(f); + } + + var testFiles = fs.readdirSync(path.join(__dirname, 'test', 'source-map')).filter(isTestFile); + + testFiles.forEach(function (testFile) { + console.log('\nCreating', path.join('dist', 'test', testFile.replace(/\-/g, '_'))); + + copy({ + source: [ + 'build/test-prefix.js', + path.join('test', 'source-map', testFile), + 'build/test-suffix.js' + ], + filter: [ + removeAmdefine, + makeNonRelative, + function (input, source) { + return input.replace('define(', + 'define("' + + path.join('test', 'source-map', testFile.replace(/\.js$/, '')) + + '", ["require", "exports", "module"], '); + }, + function (input, source) { + return input.replace('{THIS_MODULE}', function () { + return "test/source-map/" + testFile.replace(/\.js$/, ''); + }); + } + ], + dest: path.join('dist', 'test', testFile.replace(/\-/g, '_')) + }); + }); +} + +function ensureDir(name) { + var dirExists = false; + try { + dirExists = fs.statSync(name).isDirectory(); + } catch (err) {} + + if (!dirExists) { + fs.mkdirSync(name, 0777); + } +} + +ensureDir("dist"); +ensureDir("dist/test"); +buildFirefox(); +buildBrowser(); +buildBrowserMin(); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/README.md b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/README.md new file mode 100644 index 0000000..c20437b --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/README.md @@ -0,0 +1,434 @@ +# Source Map + +This is a library to generate and consume the source map format +[described here][format]. + +This library is written in the Asynchronous Module Definition format, and works +in the following environments: + +* Modern Browsers supporting ECMAScript 5 (either after the build, or with an + AMD loader such as RequireJS) + +* Inside Firefox (as a JSM file, after the build) + +* With NodeJS versions 0.8.X and higher + +## Node + + $ npm install source-map + +## Building from Source (for everywhere else) + +Install Node and then run + + $ git clone https://fitzgen@github.com/mozilla/source-map.git + $ cd source-map + $ npm link . + +Next, run + + $ node Makefile.dryice.js + +This should spew a bunch of stuff to stdout, and create the following files: + +* `dist/source-map.js` - The unminified browser version. + +* `dist/source-map.min.js` - The minified browser version. + +* `dist/SourceMap.jsm` - The JavaScript Module for inclusion in Firefox source. + +## Examples + +### Consuming a source map + + var rawSourceMap = { + version: 3, + file: 'min.js', + names: ['bar', 'baz', 'n'], + sources: ['one.js', 'two.js'], + sourceRoot: 'http://example.com/www/js/', + mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA' + }; + + var smc = new SourceMapConsumer(rawSourceMap); + + console.log(smc.sources); + // [ 'http://example.com/www/js/one.js', + // 'http://example.com/www/js/two.js' ] + + console.log(smc.originalPositionFor({ + line: 2, + column: 28 + })); + // { source: 'http://example.com/www/js/two.js', + // line: 2, + // column: 10, + // name: 'n' } + + console.log(smc.generatedPositionFor({ + source: 'http://example.com/www/js/two.js', + line: 2, + column: 10 + })); + // { line: 2, column: 28 } + + smc.eachMapping(function (m) { + // ... + }); + +### Generating a source map + +In depth guide: +[**Compiling to JavaScript, and Debugging with Source Maps**](https://hacks.mozilla.org/2013/05/compiling-to-javascript-and-debugging-with-source-maps/) + +#### With SourceNode (high level API) + + function compile(ast) { + switch (ast.type) { + case 'BinaryExpression': + return new SourceNode( + ast.location.line, + ast.location.column, + ast.location.source, + [compile(ast.left), " + ", compile(ast.right)] + ); + case 'Literal': + return new SourceNode( + ast.location.line, + ast.location.column, + ast.location.source, + String(ast.value) + ); + // ... + default: + throw new Error("Bad AST"); + } + } + + var ast = parse("40 + 2", "add.js"); + console.log(compile(ast).toStringWithSourceMap({ + file: 'add.js' + })); + // { code: '40 + 2', + // map: [object SourceMapGenerator] } + +#### With SourceMapGenerator (low level API) + + var map = new SourceMapGenerator({ + file: "source-mapped.js" + }); + + map.addMapping({ + generated: { + line: 10, + column: 35 + }, + source: "foo.js", + original: { + line: 33, + column: 2 + }, + name: "christopher" + }); + + console.log(map.toString()); + // '{"version":3,"file":"source-mapped.js","sources":["foo.js"],"names":["christopher"],"mappings":";;;;;;;;;mCAgCEA"}' + +## API + +Get a reference to the module: + + // NodeJS + var sourceMap = require('source-map'); + + // Browser builds + var sourceMap = window.sourceMap; + + // Inside Firefox + let sourceMap = {}; + Components.utils.import('resource:///modules/devtools/SourceMap.jsm', sourceMap); + +### SourceMapConsumer + +A SourceMapConsumer instance represents a parsed source map which we can query +for information about the original file positions by giving it a file position +in the generated source. + +#### new SourceMapConsumer(rawSourceMap) + +The only parameter is the raw source map (either as a string which can be +`JSON.parse`'d, or an object). According to the spec, source maps have the +following attributes: + +* `version`: Which version of the source map spec this map is following. + +* `sources`: An array of URLs to the original source files. + +* `names`: An array of identifiers which can be referrenced by individual + mappings. + +* `sourceRoot`: Optional. The URL root from which all sources are relative. + +* `sourcesContent`: Optional. An array of contents of the original source files. + +* `mappings`: A string of base64 VLQs which contain the actual mappings. + +* `file`: The generated filename this source map is associated with. + +#### SourceMapConsumer.prototype.originalPositionFor(generatedPosition) + +Returns the original source, line, and column information for the generated +source's line and column positions provided. The only argument is an object with +the following properties: + +* `line`: The line number in the generated source. + +* `column`: The column number in the generated source. + +and an object is returned with the following properties: + +* `source`: The original source file, or null if this information is not + available. + +* `line`: The line number in the original source, or null if this information is + not available. + +* `column`: The column number in the original source, or null or null if this + information is not available. + +* `name`: The original identifier, or null if this information is not available. + +#### SourceMapConsumer.prototype.generatedPositionFor(originalPosition) + +Returns the generated line and column information for the original source, +line, and column positions provided. The only argument is an object with +the following properties: + +* `source`: The filename of the original source. + +* `line`: The line number in the original source. + +* `column`: The column number in the original source. + +and an object is returned with the following properties: + +* `line`: The line number in the generated source, or null. + +* `column`: The column number in the generated source, or null. + +#### SourceMapConsumer.prototype.sourceContentFor(source) + +Returns the original source content for the source provided. The only +argument is the URL of the original source file. + +#### SourceMapConsumer.prototype.eachMapping(callback, context, order) + +Iterate over each mapping between an original source/line/column and a +generated line/column in this source map. + +* `callback`: The function that is called with each mapping. Mappings have the + form `{ source, generatedLine, generatedColumn, originalLine, originalColumn, + name }` + +* `context`: Optional. If specified, this object will be the value of `this` + every time that `callback` is called. + +* `order`: Either `SourceMapConsumer.GENERATED_ORDER` or + `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to iterate over + the mappings sorted by the generated file's line/column order or the + original's source/line/column order, respectively. Defaults to + `SourceMapConsumer.GENERATED_ORDER`. + +### SourceMapGenerator + +An instance of the SourceMapGenerator represents a source map which is being +built incrementally. + +#### new SourceMapGenerator(startOfSourceMap) + +To create a new one, you must pass an object with the following properties: + +* `file`: The filename of the generated source that this source map is + associated with. + +* `sourceRoot`: An optional root for all relative URLs in this source map. + +#### SourceMapGenerator.fromSourceMap(sourceMapConsumer) + +Creates a new SourceMapGenerator based on a SourceMapConsumer + +* `sourceMapConsumer` The SourceMap. + +#### SourceMapGenerator.prototype.addMapping(mapping) + +Add a single mapping from original source line and column to the generated +source's line and column for this source map being created. The mapping object +should have the following properties: + +* `generated`: An object with the generated line and column positions. + +* `original`: An object with the original line and column positions. + +* `source`: The original source file (relative to the sourceRoot). + +* `name`: An optional original token name for this mapping. + +#### SourceMapGenerator.prototype.setSourceContent(sourceFile, sourceContent) + +Set the source content for an original source file. + +* `sourceFile` the URL of the original source file. + +* `sourceContent` the content of the source file. + +#### SourceMapGenerator.prototype.applySourceMap(sourceMapConsumer[, sourceFile]) + +Applies a SourceMap for a source file to the SourceMap. +Each mapping to the supplied source file is rewritten using the +supplied SourceMap. Note: The resolution for the resulting mappings +is the minimium of this map and the supplied map. + +* `sourceMapConsumer`: The SourceMap to be applied. + +* `sourceFile`: Optional. The filename of the source file. + If omitted, sourceMapConsumer.file will be used. + +#### SourceMapGenerator.prototype.toString() + +Renders the source map being generated to a string. + +### SourceNode + +SourceNodes provide a way to abstract over interpolating and/or concatenating +snippets of generated JavaScript source code, while maintaining the line and +column information associated between those snippets and the original source +code. This is useful as the final intermediate representation a compiler might +use before outputting the generated JS and source map. + +#### new SourceNode(line, column, source[, chunk[, name]]) + +* `line`: The original line number associated with this source node, or null if + it isn't associated with an original line. + +* `column`: The original column number associated with this source node, or null + if it isn't associated with an original column. + +* `source`: The original source's filename. + +* `chunk`: Optional. Is immediately passed to `SourceNode.prototype.add`, see + below. + +* `name`: Optional. The original identifier. + +#### SourceNode.fromStringWithSourceMap(code, sourceMapConsumer) + +Creates a SourceNode from generated code and a SourceMapConsumer. + +* `code`: The generated code + +* `sourceMapConsumer` The SourceMap for the generated code + +#### SourceNode.prototype.add(chunk) + +Add a chunk of generated JS to this source node. + +* `chunk`: A string snippet of generated JS code, another instance of + `SourceNode`, or an array where each member is one of those things. + +#### SourceNode.prototype.prepend(chunk) + +Prepend a chunk of generated JS to this source node. + +* `chunk`: A string snippet of generated JS code, another instance of + `SourceNode`, or an array where each member is one of those things. + +#### SourceNode.prototype.setSourceContent(sourceFile, sourceContent) + +Set the source content for a source file. This will be added to the +`SourceMap` in the `sourcesContent` field. + +* `sourceFile`: The filename of the source file + +* `sourceContent`: The content of the source file + +#### SourceNode.prototype.walk(fn) + +Walk over the tree of JS snippets in this node and its children. The walking +function is called once for each snippet of JS and is passed that snippet and +the its original associated source's line/column location. + +* `fn`: The traversal function. + +#### SourceNode.prototype.walkSourceContents(fn) + +Walk over the tree of SourceNodes. The walking function is called for each +source file content and is passed the filename and source content. + +* `fn`: The traversal function. + +#### SourceNode.prototype.join(sep) + +Like `Array.prototype.join` except for SourceNodes. Inserts the separator +between each of this source node's children. + +* `sep`: The separator. + +#### SourceNode.prototype.replaceRight(pattern, replacement) + +Call `String.prototype.replace` on the very right-most source snippet. Useful +for trimming whitespace from the end of a source node, etc. + +* `pattern`: The pattern to replace. + +* `replacement`: The thing to replace the pattern with. + +#### SourceNode.prototype.toString() + +Return the string representation of this source node. Walks over the tree and +concatenates all the various snippets together to one string. + +### SourceNode.prototype.toStringWithSourceMap(startOfSourceMap) + +Returns the string representation of this tree of source nodes, plus a +SourceMapGenerator which contains all the mappings between the generated and +original sources. + +The arguments are the same as those to `new SourceMapGenerator`. + +## Tests + +[![Build Status](https://travis-ci.org/mozilla/source-map.png?branch=master)](https://travis-ci.org/mozilla/source-map) + +Install NodeJS version 0.8.0 or greater, then run `node test/run-tests.js`. + +To add new tests, create a new file named `test/test-.js` +and export your test functions with names that start with "test", for example + + exports["test doing the foo bar"] = function (assert, util) { + ... + }; + +The new test will be located automatically when you run the suite. + +The `util` argument is the test utility module located at `test/source-map/util`. + +The `assert` argument is a cut down version of node's assert module. You have +access to the following assertion functions: + +* `doesNotThrow` + +* `equal` + +* `ok` + +* `strictEqual` + +* `throws` + +(The reason for the restricted set of test functions is because we need the +tests to run inside Firefox's test suite as well and so the assert module is +shimmed in that environment. See `build/assert-shim.js`.) + +[format]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit +[feature]: https://wiki.mozilla.org/DevTools/Features/SourceMap +[Dryice]: https://github.com/mozilla/dryice diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/assert-shim.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/assert-shim.js new file mode 100644 index 0000000..daa1a62 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/assert-shim.js @@ -0,0 +1,56 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('test/source-map/assert', ['exports'], function (exports) { + + let do_throw = function (msg) { + throw new Error(msg); + }; + + exports.init = function (throw_fn) { + do_throw = throw_fn; + }; + + exports.doesNotThrow = function (fn) { + try { + fn(); + } + catch (e) { + do_throw(e.message); + } + }; + + exports.equal = function (actual, expected, msg) { + msg = msg || String(actual) + ' != ' + String(expected); + if (actual != expected) { + do_throw(msg); + } + }; + + exports.ok = function (val, msg) { + msg = msg || String(val) + ' is falsey'; + if (!Boolean(val)) { + do_throw(msg); + } + }; + + exports.strictEqual = function (actual, expected, msg) { + msg = msg || String(actual) + ' !== ' + String(expected); + if (actual !== expected) { + do_throw(msg); + } + }; + + exports.throws = function (fn) { + try { + fn(); + do_throw('Expected an error to be thrown, but it wasn\'t.'); + } + catch (e) { + } + }; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/mini-require.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/mini-require.js new file mode 100644 index 0000000..0daf453 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/mini-require.js @@ -0,0 +1,152 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +/** + * Define a module along with a payload. + * @param {string} moduleName Name for the payload + * @param {ignored} deps Ignored. For compatibility with CommonJS AMD Spec + * @param {function} payload Function with (require, exports, module) params + */ +function define(moduleName, deps, payload) { + if (typeof moduleName != "string") { + throw new TypeError('Expected string, got: ' + moduleName); + } + + if (arguments.length == 2) { + payload = deps; + } + + if (moduleName in define.modules) { + throw new Error("Module already defined: " + moduleName); + } + define.modules[moduleName] = payload; +}; + +/** + * The global store of un-instantiated modules + */ +define.modules = {}; + + +/** + * We invoke require() in the context of a Domain so we can have multiple + * sets of modules running separate from each other. + * This contrasts with JSMs which are singletons, Domains allows us to + * optionally load a CommonJS module twice with separate data each time. + * Perhaps you want 2 command lines with a different set of commands in each, + * for example. + */ +function Domain() { + this.modules = {}; + this._currentModule = null; +} + +(function () { + + /** + * Lookup module names and resolve them by calling the definition function if + * needed. + * There are 2 ways to call this, either with an array of dependencies and a + * callback to call when the dependencies are found (which can happen + * asynchronously in an in-page context) or with a single string an no callback + * where the dependency is resolved synchronously and returned. + * The API is designed to be compatible with the CommonJS AMD spec and + * RequireJS. + * @param {string[]|string} deps A name, or names for the payload + * @param {function|undefined} callback Function to call when the dependencies + * are resolved + * @return {undefined|object} The module required or undefined for + * array/callback method + */ + Domain.prototype.require = function(deps, callback) { + if (Array.isArray(deps)) { + var params = deps.map(function(dep) { + return this.lookup(dep); + }, this); + if (callback) { + callback.apply(null, params); + } + return undefined; + } + else { + return this.lookup(deps); + } + }; + + function normalize(path) { + var bits = path.split('/'); + var i = 1; + while (i < bits.length) { + if (bits[i] === '..') { + bits.splice(i-1, 1); + } else if (bits[i] === '.') { + bits.splice(i, 1); + } else { + i++; + } + } + return bits.join('/'); + } + + function join(a, b) { + a = a.trim(); + b = b.trim(); + if (/^\//.test(b)) { + return b; + } else { + return a.replace(/\/*$/, '/') + b; + } + } + + function dirname(path) { + var bits = path.split('/'); + bits.pop(); + return bits.join('/'); + } + + /** + * Lookup module names and resolve them by calling the definition function if + * needed. + * @param {string} moduleName A name for the payload to lookup + * @return {object} The module specified by aModuleName or null if not found. + */ + Domain.prototype.lookup = function(moduleName) { + if (/^\./.test(moduleName)) { + moduleName = normalize(join(dirname(this._currentModule), moduleName)); + } + + if (moduleName in this.modules) { + var module = this.modules[moduleName]; + return module; + } + + if (!(moduleName in define.modules)) { + throw new Error("Module not defined: " + moduleName); + } + + var module = define.modules[moduleName]; + + if (typeof module == "function") { + var exports = {}; + var previousModule = this._currentModule; + this._currentModule = moduleName; + module(this.require.bind(this), exports, { id: moduleName, uri: "" }); + this._currentModule = previousModule; + module = exports; + } + + // cache the resulting module object for next time + this.modules[moduleName] = module; + + return module; + }; + +}()); + +define.Domain = Domain; +define.globalDomain = new Domain(); +var require = define.globalDomain.require.bind(define.globalDomain); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/prefix-source-map.jsm b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/prefix-source-map.jsm new file mode 100644 index 0000000..ee2539d --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/prefix-source-map.jsm @@ -0,0 +1,20 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +/* + * WARNING! + * + * Do not edit this file directly, it is built from the sources at + * https://github.com/mozilla/source-map/ + */ + +/////////////////////////////////////////////////////////////////////////////// + + +this.EXPORTED_SYMBOLS = [ "SourceMapConsumer", "SourceMapGenerator", "SourceNode" ]; + +Components.utils.import('resource://gre/modules/devtools/Require.jsm'); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/prefix-utils.jsm b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/prefix-utils.jsm new file mode 100644 index 0000000..80341d4 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/prefix-utils.jsm @@ -0,0 +1,18 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +/* + * WARNING! + * + * Do not edit this file directly, it is built from the sources at + * https://github.com/mozilla/source-map/ + */ + +Components.utils.import('resource://gre/modules/devtools/Require.jsm'); +Components.utils.import('resource://gre/modules/devtools/SourceMap.jsm'); + +this.EXPORTED_SYMBOLS = [ "define", "runSourceMapTests" ]; diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/suffix-browser.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/suffix-browser.js new file mode 100644 index 0000000..fb29ff5 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/suffix-browser.js @@ -0,0 +1,8 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/////////////////////////////////////////////////////////////////////////////// + +this.sourceMap = { + SourceMapConsumer: require('source-map/source-map-consumer').SourceMapConsumer, + SourceMapGenerator: require('source-map/source-map-generator').SourceMapGenerator, + SourceNode: require('source-map/source-node').SourceNode +}; diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/suffix-source-map.jsm b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/suffix-source-map.jsm new file mode 100644 index 0000000..cf3c2d8 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/suffix-source-map.jsm @@ -0,0 +1,6 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/////////////////////////////////////////////////////////////////////////////// + +this.SourceMapConsumer = require('source-map/source-map-consumer').SourceMapConsumer; +this.SourceMapGenerator = require('source-map/source-map-generator').SourceMapGenerator; +this.SourceNode = require('source-map/source-node').SourceNode; diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/suffix-utils.jsm b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/suffix-utils.jsm new file mode 100644 index 0000000..b31b84c --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/suffix-utils.jsm @@ -0,0 +1,21 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +function runSourceMapTests(modName, do_throw) { + let mod = require(modName); + let assert = require('test/source-map/assert'); + let util = require('test/source-map/util'); + + assert.init(do_throw); + + for (let k in mod) { + if (/^test/.test(k)) { + mod[k](assert, util); + } + } + +} +this.runSourceMapTests = runSourceMapTests; diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/test-prefix.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/test-prefix.js new file mode 100644 index 0000000..1b13f30 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/test-prefix.js @@ -0,0 +1,8 @@ +/* + * WARNING! + * + * Do not edit this file directly, it is built from the sources at + * https://github.com/mozilla/source-map/ + */ + +Components.utils.import('resource://test/Utils.jsm'); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/test-suffix.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/test-suffix.js new file mode 100644 index 0000000..bec2de3 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/build/test-suffix.js @@ -0,0 +1,3 @@ +function run_test() { + runSourceMapTests('{THIS_MODULE}', do_throw); +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map.js new file mode 100644 index 0000000..121ad24 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map.js @@ -0,0 +1,8 @@ +/* + * Copyright 2009-2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE.txt or: + * http://opensource.org/licenses/BSD-3-Clause + */ +exports.SourceMapGenerator = require('./source-map/source-map-generator').SourceMapGenerator; +exports.SourceMapConsumer = require('./source-map/source-map-consumer').SourceMapConsumer; +exports.SourceNode = require('./source-map/source-node').SourceNode; diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/array-set.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/array-set.js new file mode 100644 index 0000000..40f9a18 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/array-set.js @@ -0,0 +1,97 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var util = require('./util'); + + /** + * A data structure which is a combination of an array and a set. Adding a new + * member is O(1), testing for membership is O(1), and finding the index of an + * element is O(1). Removing elements from the set is not supported. Only + * strings are supported for membership. + */ + function ArraySet() { + this._array = []; + this._set = {}; + } + + /** + * Static method for creating ArraySet instances from an existing array. + */ + ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { + var set = new ArraySet(); + for (var i = 0, len = aArray.length; i < len; i++) { + set.add(aArray[i], aAllowDuplicates); + } + return set; + }; + + /** + * Add the given string to this set. + * + * @param String aStr + */ + ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { + var isDuplicate = this.has(aStr); + var idx = this._array.length; + if (!isDuplicate || aAllowDuplicates) { + this._array.push(aStr); + } + if (!isDuplicate) { + this._set[util.toSetString(aStr)] = idx; + } + }; + + /** + * Is the given string a member of this set? + * + * @param String aStr + */ + ArraySet.prototype.has = function ArraySet_has(aStr) { + return Object.prototype.hasOwnProperty.call(this._set, + util.toSetString(aStr)); + }; + + /** + * What is the index of the given string in the array? + * + * @param String aStr + */ + ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { + if (this.has(aStr)) { + return this._set[util.toSetString(aStr)]; + } + throw new Error('"' + aStr + '" is not in the set.'); + }; + + /** + * What is the element at the given index? + * + * @param Number aIdx + */ + ArraySet.prototype.at = function ArraySet_at(aIdx) { + if (aIdx >= 0 && aIdx < this._array.length) { + return this._array[aIdx]; + } + throw new Error('No element indexed by ' + aIdx); + }; + + /** + * Returns the array representation of this set (which has the proper indices + * indicated by indexOf). Note that this is a copy of the internal array used + * for storing the members so that no one can mess with internal state. + */ + ArraySet.prototype.toArray = function ArraySet_toArray() { + return this._array.slice(); + }; + + exports.ArraySet = ArraySet; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/base64-vlq.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/base64-vlq.js new file mode 100644 index 0000000..1b67bb3 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/base64-vlq.js @@ -0,0 +1,144 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + * + * Based on the Base 64 VLQ implementation in Closure Compiler: + * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java + * + * Copyright 2011 The Closure Compiler Authors. 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 Google Inc. 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 + * OWNER 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. + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var base64 = require('./base64'); + + // A single base 64 digit can contain 6 bits of data. For the base 64 variable + // length quantities we use in the source map spec, the first bit is the sign, + // the next four bits are the actual value, and the 6th bit is the + // continuation bit. The continuation bit tells us whether there are more + // digits in this value following this digit. + // + // Continuation + // | Sign + // | | + // V V + // 101011 + + var VLQ_BASE_SHIFT = 5; + + // binary: 100000 + var VLQ_BASE = 1 << VLQ_BASE_SHIFT; + + // binary: 011111 + var VLQ_BASE_MASK = VLQ_BASE - 1; + + // binary: 100000 + var VLQ_CONTINUATION_BIT = VLQ_BASE; + + /** + * Converts from a two-complement value to a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) + * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) + */ + function toVLQSigned(aValue) { + return aValue < 0 + ? ((-aValue) << 1) + 1 + : (aValue << 1) + 0; + } + + /** + * Converts to a two-complement value from a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 + * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 + */ + function fromVLQSigned(aValue) { + var isNegative = (aValue & 1) === 1; + var shifted = aValue >> 1; + return isNegative + ? -shifted + : shifted; + } + + /** + * Returns the base 64 VLQ encoded value. + */ + exports.encode = function base64VLQ_encode(aValue) { + var encoded = ""; + var digit; + + var vlq = toVLQSigned(aValue); + + do { + digit = vlq & VLQ_BASE_MASK; + vlq >>>= VLQ_BASE_SHIFT; + if (vlq > 0) { + // There are still more digits in this value, so we must make sure the + // continuation bit is marked. + digit |= VLQ_CONTINUATION_BIT; + } + encoded += base64.encode(digit); + } while (vlq > 0); + + return encoded; + }; + + /** + * Decodes the next base 64 VLQ value from the given string and returns the + * value and the rest of the string. + */ + exports.decode = function base64VLQ_decode(aStr) { + var i = 0; + var strLen = aStr.length; + var result = 0; + var shift = 0; + var continuation, digit; + + do { + if (i >= strLen) { + throw new Error("Expected more digits in base 64 VLQ value."); + } + digit = base64.decode(aStr.charAt(i++)); + continuation = !!(digit & VLQ_CONTINUATION_BIT); + digit &= VLQ_BASE_MASK; + result = result + (digit << shift); + shift += VLQ_BASE_SHIFT; + } while (continuation); + + return { + value: fromVLQSigned(result), + rest: aStr.slice(i) + }; + }; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/base64.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/base64.js new file mode 100644 index 0000000..863cc46 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/base64.js @@ -0,0 +1,42 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var charToIntMap = {}; + var intToCharMap = {}; + + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + .split('') + .forEach(function (ch, index) { + charToIntMap[ch] = index; + intToCharMap[index] = ch; + }); + + /** + * Encode an integer in the range of 0 to 63 to a single base 64 digit. + */ + exports.encode = function base64_encode(aNumber) { + if (aNumber in intToCharMap) { + return intToCharMap[aNumber]; + } + throw new TypeError("Must be between 0 and 63: " + aNumber); + }; + + /** + * Decode a single base 64 digit to an integer. + */ + exports.decode = function base64_decode(aChar) { + if (aChar in charToIntMap) { + return charToIntMap[aChar]; + } + throw new TypeError("Not a valid base 64 digit: " + aChar); + }; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/binary-search.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/binary-search.js new file mode 100644 index 0000000..ff347c6 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/binary-search.js @@ -0,0 +1,81 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + /** + * Recursive implementation of binary search. + * + * @param aLow Indices here and lower do not contain the needle. + * @param aHigh Indices here and higher do not contain the needle. + * @param aNeedle The element being searched for. + * @param aHaystack The non-empty array being searched. + * @param aCompare Function which takes two elements and returns -1, 0, or 1. + */ + function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) { + // This function terminates when one of the following is true: + // + // 1. We find the exact element we are looking for. + // + // 2. We did not find the exact element, but we can return the next + // closest element that is less than that element. + // + // 3. We did not find the exact element, and there is no next-closest + // element which is less than the one we are searching for, so we + // return null. + var mid = Math.floor((aHigh - aLow) / 2) + aLow; + var cmp = aCompare(aNeedle, aHaystack[mid], true); + if (cmp === 0) { + // Found the element we are looking for. + return aHaystack[mid]; + } + else if (cmp > 0) { + // aHaystack[mid] is greater than our needle. + if (aHigh - mid > 1) { + // The element is in the upper half. + return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare); + } + // We did not find an exact match, return the next closest one + // (termination case 2). + return aHaystack[mid]; + } + else { + // aHaystack[mid] is less than our needle. + if (mid - aLow > 1) { + // The element is in the lower half. + return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare); + } + // The exact needle element was not found in this haystack. Determine if + // we are in termination case (2) or (3) and return the appropriate thing. + return aLow < 0 + ? null + : aHaystack[aLow]; + } + } + + /** + * This is an implementation of binary search which will always try and return + * the next lowest value checked if there is no exact hit. This is because + * mappings between original and generated line/col pairs are single points, + * and there is an implicit region between each of them, so a miss just means + * that you aren't on the very start of a region. + * + * @param aNeedle The element you are looking for. + * @param aHaystack The array that is being searched. + * @param aCompare A function which takes the needle and an element in the + * array and returns -1, 0, or 1 depending on whether the needle is less + * than, equal to, or greater than the element, respectively. + */ + exports.search = function search(aNeedle, aHaystack, aCompare) { + return aHaystack.length > 0 + ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) + : null; + }; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-map-consumer.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-map-consumer.js new file mode 100644 index 0000000..a3b9dc0 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-map-consumer.js @@ -0,0 +1,477 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var util = require('./util'); + var binarySearch = require('./binary-search'); + var ArraySet = require('./array-set').ArraySet; + var base64VLQ = require('./base64-vlq'); + + /** + * A SourceMapConsumer instance represents a parsed source map which we can + * query for information about the original file positions by giving it a file + * position in the generated source. + * + * The only parameter is the raw source map (either as a JSON string, or + * already parsed to an object). According to the spec, source maps have the + * following attributes: + * + * - version: Which version of the source map spec this map is following. + * - sources: An array of URLs to the original source files. + * - names: An array of identifiers which can be referrenced by individual mappings. + * - sourceRoot: Optional. The URL root from which all sources are relative. + * - sourcesContent: Optional. An array of contents of the original source files. + * - mappings: A string of base64 VLQs which contain the actual mappings. + * - file: The generated file this source map is associated with. + * + * Here is an example source map, taken from the source map spec[0]: + * + * { + * version : 3, + * file: "out.js", + * sourceRoot : "", + * sources: ["foo.js", "bar.js"], + * names: ["src", "maps", "are", "fun"], + * mappings: "AA,AB;;ABCDE;" + * } + * + * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# + */ + function SourceMapConsumer(aSourceMap) { + var sourceMap = aSourceMap; + if (typeof aSourceMap === 'string') { + sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); + } + + var version = util.getArg(sourceMap, 'version'); + var sources = util.getArg(sourceMap, 'sources'); + // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which + // requires the array) to play nice here. + var names = util.getArg(sourceMap, 'names', []); + var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); + var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); + var mappings = util.getArg(sourceMap, 'mappings'); + var file = util.getArg(sourceMap, 'file', null); + + // Once again, Sass deviates from the spec and supplies the version as a + // string rather than a number, so we use loose equality checking here. + if (version != this._version) { + throw new Error('Unsupported version: ' + version); + } + + // Pass `true` below to allow duplicate names and sources. While source maps + // are intended to be compressed and deduplicated, the TypeScript compiler + // sometimes generates source maps with duplicates in them. See Github issue + // #72 and bugzil.la/889492. + this._names = ArraySet.fromArray(names, true); + this._sources = ArraySet.fromArray(sources, true); + + this.sourceRoot = sourceRoot; + this.sourcesContent = sourcesContent; + this._mappings = mappings; + this.file = file; + } + + /** + * Create a SourceMapConsumer from a SourceMapGenerator. + * + * @param SourceMapGenerator aSourceMap + * The source map that will be consumed. + * @returns SourceMapConsumer + */ + SourceMapConsumer.fromSourceMap = + function SourceMapConsumer_fromSourceMap(aSourceMap) { + var smc = Object.create(SourceMapConsumer.prototype); + + smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true); + smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true); + smc.sourceRoot = aSourceMap._sourceRoot; + smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(), + smc.sourceRoot); + smc.file = aSourceMap._file; + + smc.__generatedMappings = aSourceMap._mappings.slice() + .sort(util.compareByGeneratedPositions); + smc.__originalMappings = aSourceMap._mappings.slice() + .sort(util.compareByOriginalPositions); + + return smc; + }; + + /** + * The version of the source mapping spec that we are consuming. + */ + SourceMapConsumer.prototype._version = 3; + + /** + * The list of original sources. + */ + Object.defineProperty(SourceMapConsumer.prototype, 'sources', { + get: function () { + return this._sources.toArray().map(function (s) { + return this.sourceRoot ? util.join(this.sourceRoot, s) : s; + }, this); + } + }); + + // `__generatedMappings` and `__originalMappings` are arrays that hold the + // parsed mapping coordinates from the source map's "mappings" attribute. They + // are lazily instantiated, accessed via the `_generatedMappings` and + // `_originalMappings` getters respectively, and we only parse the mappings + // and create these arrays once queried for a source location. We jump through + // these hoops because there can be many thousands of mappings, and parsing + // them is expensive, so we only want to do it if we must. + // + // Each object in the arrays is of the form: + // + // { + // generatedLine: The line number in the generated code, + // generatedColumn: The column number in the generated code, + // source: The path to the original source file that generated this + // chunk of code, + // originalLine: The line number in the original source that + // corresponds to this chunk of generated code, + // originalColumn: The column number in the original source that + // corresponds to this chunk of generated code, + // name: The name of the original symbol which generated this chunk of + // code. + // } + // + // All properties except for `generatedLine` and `generatedColumn` can be + // `null`. + // + // `_generatedMappings` is ordered by the generated positions. + // + // `_originalMappings` is ordered by the original positions. + + SourceMapConsumer.prototype.__generatedMappings = null; + Object.defineProperty(SourceMapConsumer.prototype, '_generatedMappings', { + get: function () { + if (!this.__generatedMappings) { + this.__generatedMappings = []; + this.__originalMappings = []; + this._parseMappings(this._mappings, this.sourceRoot); + } + + return this.__generatedMappings; + } + }); + + SourceMapConsumer.prototype.__originalMappings = null; + Object.defineProperty(SourceMapConsumer.prototype, '_originalMappings', { + get: function () { + if (!this.__originalMappings) { + this.__generatedMappings = []; + this.__originalMappings = []; + this._parseMappings(this._mappings, this.sourceRoot); + } + + return this.__originalMappings; + } + }); + + /** + * Parse the mappings in a string in to a data structure which we can easily + * query (the ordered arrays in the `this.__generatedMappings` and + * `this.__originalMappings` properties). + */ + SourceMapConsumer.prototype._parseMappings = + function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { + var generatedLine = 1; + var previousGeneratedColumn = 0; + var previousOriginalLine = 0; + var previousOriginalColumn = 0; + var previousSource = 0; + var previousName = 0; + var mappingSeparator = /^[,;]/; + var str = aStr; + var mapping; + var temp; + + while (str.length > 0) { + if (str.charAt(0) === ';') { + generatedLine++; + str = str.slice(1); + previousGeneratedColumn = 0; + } + else if (str.charAt(0) === ',') { + str = str.slice(1); + } + else { + mapping = {}; + mapping.generatedLine = generatedLine; + + // Generated column. + temp = base64VLQ.decode(str); + mapping.generatedColumn = previousGeneratedColumn + temp.value; + previousGeneratedColumn = mapping.generatedColumn; + str = temp.rest; + + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + // Original source. + temp = base64VLQ.decode(str); + mapping.source = this._sources.at(previousSource + temp.value); + previousSource += temp.value; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source, but no line and column'); + } + + // Original line. + temp = base64VLQ.decode(str); + mapping.originalLine = previousOriginalLine + temp.value; + previousOriginalLine = mapping.originalLine; + // Lines are stored 0-based + mapping.originalLine += 1; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source and line, but no column'); + } + + // Original column. + temp = base64VLQ.decode(str); + mapping.originalColumn = previousOriginalColumn + temp.value; + previousOriginalColumn = mapping.originalColumn; + str = temp.rest; + + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + // Original name. + temp = base64VLQ.decode(str); + mapping.name = this._names.at(previousName + temp.value); + previousName += temp.value; + str = temp.rest; + } + } + + this.__generatedMappings.push(mapping); + if (typeof mapping.originalLine === 'number') { + this.__originalMappings.push(mapping); + } + } + } + + this.__originalMappings.sort(util.compareByOriginalPositions); + }; + + /** + * Find the mapping that best matches the hypothetical "needle" mapping that + * we are searching for in the given "haystack" of mappings. + */ + SourceMapConsumer.prototype._findMapping = + function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, + aColumnName, aComparator) { + // To return the position we are searching for, we must first find the + // mapping for the given position and then return the opposite position it + // points to. Because the mappings are sorted, we can use binary search to + // find the best mapping. + + if (aNeedle[aLineName] <= 0) { + throw new TypeError('Line must be greater than or equal to 1, got ' + + aNeedle[aLineName]); + } + if (aNeedle[aColumnName] < 0) { + throw new TypeError('Column must be greater than or equal to 0, got ' + + aNeedle[aColumnName]); + } + + return binarySearch.search(aNeedle, aMappings, aComparator); + }; + + /** + * Returns the original source, line, and column information for the generated + * source's line and column positions provided. The only argument is an object + * with the following properties: + * + * - line: The line number in the generated source. + * - column: The column number in the generated source. + * + * and an object is returned with the following properties: + * + * - source: The original source file, or null. + * - line: The line number in the original source, or null. + * - column: The column number in the original source, or null. + * - name: The original identifier, or null. + */ + SourceMapConsumer.prototype.originalPositionFor = + function SourceMapConsumer_originalPositionFor(aArgs) { + var needle = { + generatedLine: util.getArg(aArgs, 'line'), + generatedColumn: util.getArg(aArgs, 'column') + }; + + var mapping = this._findMapping(needle, + this._generatedMappings, + "generatedLine", + "generatedColumn", + util.compareByGeneratedPositions); + + if (mapping) { + var source = util.getArg(mapping, 'source', null); + if (source && this.sourceRoot) { + source = util.join(this.sourceRoot, source); + } + return { + source: source, + line: util.getArg(mapping, 'originalLine', null), + column: util.getArg(mapping, 'originalColumn', null), + name: util.getArg(mapping, 'name', null) + }; + } + + return { + source: null, + line: null, + column: null, + name: null + }; + }; + + /** + * Returns the original source content. The only argument is the url of the + * original source file. Returns null if no original source content is + * availible. + */ + SourceMapConsumer.prototype.sourceContentFor = + function SourceMapConsumer_sourceContentFor(aSource) { + if (!this.sourcesContent) { + return null; + } + + if (this.sourceRoot) { + aSource = util.relative(this.sourceRoot, aSource); + } + + if (this._sources.has(aSource)) { + return this.sourcesContent[this._sources.indexOf(aSource)]; + } + + var url; + if (this.sourceRoot + && (url = util.urlParse(this.sourceRoot))) { + // XXX: file:// URIs and absolute paths lead to unexpected behavior for + // many users. We can help them out when they expect file:// URIs to + // behave like it would if they were running a local HTTP server. See + // https://bugzilla.mozilla.org/show_bug.cgi?id=885597. + var fileUriAbsPath = aSource.replace(/^file:\/\//, ""); + if (url.scheme == "file" + && this._sources.has(fileUriAbsPath)) { + return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)] + } + + if ((!url.path || url.path == "/") + && this._sources.has("/" + aSource)) { + return this.sourcesContent[this._sources.indexOf("/" + aSource)]; + } + } + + throw new Error('"' + aSource + '" is not in the SourceMap.'); + }; + + /** + * Returns the generated line and column information for the original source, + * line, and column positions provided. The only argument is an object with + * the following properties: + * + * - source: The filename of the original source. + * - line: The line number in the original source. + * - column: The column number in the original source. + * + * and an object is returned with the following properties: + * + * - line: The line number in the generated source, or null. + * - column: The column number in the generated source, or null. + */ + SourceMapConsumer.prototype.generatedPositionFor = + function SourceMapConsumer_generatedPositionFor(aArgs) { + var needle = { + source: util.getArg(aArgs, 'source'), + originalLine: util.getArg(aArgs, 'line'), + originalColumn: util.getArg(aArgs, 'column') + }; + + if (this.sourceRoot) { + needle.source = util.relative(this.sourceRoot, needle.source); + } + + var mapping = this._findMapping(needle, + this._originalMappings, + "originalLine", + "originalColumn", + util.compareByOriginalPositions); + + if (mapping) { + return { + line: util.getArg(mapping, 'generatedLine', null), + column: util.getArg(mapping, 'generatedColumn', null) + }; + } + + return { + line: null, + column: null + }; + }; + + SourceMapConsumer.GENERATED_ORDER = 1; + SourceMapConsumer.ORIGINAL_ORDER = 2; + + /** + * Iterate over each mapping between an original source/line/column and a + * generated line/column in this source map. + * + * @param Function aCallback + * The function that is called with each mapping. + * @param Object aContext + * Optional. If specified, this object will be the value of `this` every + * time that `aCallback` is called. + * @param aOrder + * Either `SourceMapConsumer.GENERATED_ORDER` or + * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to + * iterate over the mappings sorted by the generated file's line/column + * order or the original's source/line/column order, respectively. Defaults to + * `SourceMapConsumer.GENERATED_ORDER`. + */ + SourceMapConsumer.prototype.eachMapping = + function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { + var context = aContext || null; + var order = aOrder || SourceMapConsumer.GENERATED_ORDER; + + var mappings; + switch (order) { + case SourceMapConsumer.GENERATED_ORDER: + mappings = this._generatedMappings; + break; + case SourceMapConsumer.ORIGINAL_ORDER: + mappings = this._originalMappings; + break; + default: + throw new Error("Unknown order of iteration."); + } + + var sourceRoot = this.sourceRoot; + mappings.map(function (mapping) { + var source = mapping.source; + if (source && sourceRoot) { + source = util.join(sourceRoot, source); + } + return { + source: source, + generatedLine: mapping.generatedLine, + generatedColumn: mapping.generatedColumn, + originalLine: mapping.originalLine, + originalColumn: mapping.originalColumn, + name: mapping.name + }; + }).forEach(aCallback, context); + }; + + exports.SourceMapConsumer = SourceMapConsumer; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-map-generator.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-map-generator.js new file mode 100644 index 0000000..48ead7d --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-map-generator.js @@ -0,0 +1,380 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var base64VLQ = require('./base64-vlq'); + var util = require('./util'); + var ArraySet = require('./array-set').ArraySet; + + /** + * An instance of the SourceMapGenerator represents a source map which is + * being built incrementally. To create a new one, you must pass an object + * with the following properties: + * + * - file: The filename of the generated source. + * - sourceRoot: An optional root for all URLs in this source map. + */ + function SourceMapGenerator(aArgs) { + this._file = util.getArg(aArgs, 'file'); + this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); + this._sources = new ArraySet(); + this._names = new ArraySet(); + this._mappings = []; + this._sourcesContents = null; + } + + SourceMapGenerator.prototype._version = 3; + + /** + * Creates a new SourceMapGenerator based on a SourceMapConsumer + * + * @param aSourceMapConsumer The SourceMap. + */ + SourceMapGenerator.fromSourceMap = + function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { + var sourceRoot = aSourceMapConsumer.sourceRoot; + var generator = new SourceMapGenerator({ + file: aSourceMapConsumer.file, + sourceRoot: sourceRoot + }); + aSourceMapConsumer.eachMapping(function (mapping) { + var newMapping = { + generated: { + line: mapping.generatedLine, + column: mapping.generatedColumn + } + }; + + if (mapping.source) { + newMapping.source = mapping.source; + if (sourceRoot) { + newMapping.source = util.relative(sourceRoot, newMapping.source); + } + + newMapping.original = { + line: mapping.originalLine, + column: mapping.originalColumn + }; + + if (mapping.name) { + newMapping.name = mapping.name; + } + } + + generator.addMapping(newMapping); + }); + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + generator.setSourceContent(sourceFile, content); + } + }); + return generator; + }; + + /** + * Add a single mapping from original source line and column to the generated + * source's line and column for this source map being created. The mapping + * object should have the following properties: + * + * - generated: An object with the generated line and column positions. + * - original: An object with the original line and column positions. + * - source: The original source file (relative to the sourceRoot). + * - name: An optional original token name for this mapping. + */ + SourceMapGenerator.prototype.addMapping = + function SourceMapGenerator_addMapping(aArgs) { + var generated = util.getArg(aArgs, 'generated'); + var original = util.getArg(aArgs, 'original', null); + var source = util.getArg(aArgs, 'source', null); + var name = util.getArg(aArgs, 'name', null); + + this._validateMapping(generated, original, source, name); + + if (source && !this._sources.has(source)) { + this._sources.add(source); + } + + if (name && !this._names.has(name)) { + this._names.add(name); + } + + this._mappings.push({ + generatedLine: generated.line, + generatedColumn: generated.column, + originalLine: original != null && original.line, + originalColumn: original != null && original.column, + source: source, + name: name + }); + }; + + /** + * Set the source content for a source file. + */ + SourceMapGenerator.prototype.setSourceContent = + function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { + var source = aSourceFile; + if (this._sourceRoot) { + source = util.relative(this._sourceRoot, source); + } + + if (aSourceContent !== null) { + // Add the source content to the _sourcesContents map. + // Create a new _sourcesContents map if the property is null. + if (!this._sourcesContents) { + this._sourcesContents = {}; + } + this._sourcesContents[util.toSetString(source)] = aSourceContent; + } else { + // Remove the source file from the _sourcesContents map. + // If the _sourcesContents map is empty, set the property to null. + delete this._sourcesContents[util.toSetString(source)]; + if (Object.keys(this._sourcesContents).length === 0) { + this._sourcesContents = null; + } + } + }; + + /** + * Applies the mappings of a sub-source-map for a specific source file to the + * source map being generated. Each mapping to the supplied source file is + * rewritten using the supplied source map. Note: The resolution for the + * resulting mappings is the minimium of this map and the supplied map. + * + * @param aSourceMapConsumer The source map to be applied. + * @param aSourceFile Optional. The filename of the source file. + * If omitted, SourceMapConsumer's file property will be used. + */ + SourceMapGenerator.prototype.applySourceMap = + function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { + // If aSourceFile is omitted, we will use the file property of the SourceMap + if (!aSourceFile) { + aSourceFile = aSourceMapConsumer.file; + } + var sourceRoot = this._sourceRoot; + // Make "aSourceFile" relative if an absolute Url is passed. + if (sourceRoot) { + aSourceFile = util.relative(sourceRoot, aSourceFile); + } + // Applying the SourceMap can add and remove items from the sources and + // the names array. + var newSources = new ArraySet(); + var newNames = new ArraySet(); + + // Find mappings for the "aSourceFile" + this._mappings.forEach(function (mapping) { + if (mapping.source === aSourceFile && mapping.originalLine) { + // Check if it can be mapped by the source map, then update the mapping. + var original = aSourceMapConsumer.originalPositionFor({ + line: mapping.originalLine, + column: mapping.originalColumn + }); + if (original.source !== null) { + // Copy mapping + if (sourceRoot) { + mapping.source = util.relative(sourceRoot, original.source); + } else { + mapping.source = original.source; + } + mapping.originalLine = original.line; + mapping.originalColumn = original.column; + if (original.name !== null && mapping.name !== null) { + // Only use the identifier name if it's an identifier + // in both SourceMaps + mapping.name = original.name; + } + } + } + + var source = mapping.source; + if (source && !newSources.has(source)) { + newSources.add(source); + } + + var name = mapping.name; + if (name && !newNames.has(name)) { + newNames.add(name); + } + + }, this); + this._sources = newSources; + this._names = newNames; + + // Copy sourcesContents of applied map. + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + if (sourceRoot) { + sourceFile = util.relative(sourceRoot, sourceFile); + } + this.setSourceContent(sourceFile, content); + } + }, this); + }; + + /** + * A mapping can have one of the three levels of data: + * + * 1. Just the generated position. + * 2. The Generated position, original position, and original source. + * 3. Generated and original position, original source, as well as a name + * token. + * + * To maintain consistency, we validate that any new mapping being added falls + * in to one of these categories. + */ + SourceMapGenerator.prototype._validateMapping = + function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, + aName) { + if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aGenerated.line > 0 && aGenerated.column >= 0 + && !aOriginal && !aSource && !aName) { + // Case 1. + return; + } + else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aOriginal && 'line' in aOriginal && 'column' in aOriginal + && aGenerated.line > 0 && aGenerated.column >= 0 + && aOriginal.line > 0 && aOriginal.column >= 0 + && aSource) { + // Cases 2 and 3. + return; + } + else { + throw new Error('Invalid mapping: ' + JSON.stringify({ + generated: aGenerated, + source: aSource, + orginal: aOriginal, + name: aName + })); + } + }; + + /** + * Serialize the accumulated mappings in to the stream of base 64 VLQs + * specified by the source map format. + */ + SourceMapGenerator.prototype._serializeMappings = + function SourceMapGenerator_serializeMappings() { + var previousGeneratedColumn = 0; + var previousGeneratedLine = 1; + var previousOriginalColumn = 0; + var previousOriginalLine = 0; + var previousName = 0; + var previousSource = 0; + var result = ''; + var mapping; + + // The mappings must be guaranteed to be in sorted order before we start + // serializing them or else the generated line numbers (which are defined + // via the ';' separators) will be all messed up. Note: it might be more + // performant to maintain the sorting as we insert them, rather than as we + // serialize them, but the big O is the same either way. + this._mappings.sort(util.compareByGeneratedPositions); + + for (var i = 0, len = this._mappings.length; i < len; i++) { + mapping = this._mappings[i]; + + if (mapping.generatedLine !== previousGeneratedLine) { + previousGeneratedColumn = 0; + while (mapping.generatedLine !== previousGeneratedLine) { + result += ';'; + previousGeneratedLine++; + } + } + else { + if (i > 0) { + if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) { + continue; + } + result += ','; + } + } + + result += base64VLQ.encode(mapping.generatedColumn + - previousGeneratedColumn); + previousGeneratedColumn = mapping.generatedColumn; + + if (mapping.source) { + result += base64VLQ.encode(this._sources.indexOf(mapping.source) + - previousSource); + previousSource = this._sources.indexOf(mapping.source); + + // lines are stored 0-based in SourceMap spec version 3 + result += base64VLQ.encode(mapping.originalLine - 1 + - previousOriginalLine); + previousOriginalLine = mapping.originalLine - 1; + + result += base64VLQ.encode(mapping.originalColumn + - previousOriginalColumn); + previousOriginalColumn = mapping.originalColumn; + + if (mapping.name) { + result += base64VLQ.encode(this._names.indexOf(mapping.name) + - previousName); + previousName = this._names.indexOf(mapping.name); + } + } + } + + return result; + }; + + SourceMapGenerator.prototype._generateSourcesContent = + function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) { + return aSources.map(function (source) { + if (!this._sourcesContents) { + return null; + } + if (aSourceRoot) { + source = util.relative(aSourceRoot, source); + } + var key = util.toSetString(source); + return Object.prototype.hasOwnProperty.call(this._sourcesContents, + key) + ? this._sourcesContents[key] + : null; + }, this); + }; + + /** + * Externalize the source map. + */ + SourceMapGenerator.prototype.toJSON = + function SourceMapGenerator_toJSON() { + var map = { + version: this._version, + file: this._file, + sources: this._sources.toArray(), + names: this._names.toArray(), + mappings: this._serializeMappings() + }; + if (this._sourceRoot) { + map.sourceRoot = this._sourceRoot; + } + if (this._sourcesContents) { + map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); + } + + return map; + }; + + /** + * Render the source map being generated to a string. + */ + SourceMapGenerator.prototype.toString = + function SourceMapGenerator_toString() { + return JSON.stringify(this); + }; + + exports.SourceMapGenerator = SourceMapGenerator; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-node.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-node.js new file mode 100644 index 0000000..626cb65 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-node.js @@ -0,0 +1,371 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; + var util = require('./util'); + + /** + * SourceNodes provide a way to abstract over interpolating/concatenating + * snippets of generated JavaScript source code while maintaining the line and + * column information associated with the original source code. + * + * @param aLine The original line number. + * @param aColumn The original column number. + * @param aSource The original source's filename. + * @param aChunks Optional. An array of strings which are snippets of + * generated JS, or other SourceNodes. + * @param aName The original identifier. + */ + function SourceNode(aLine, aColumn, aSource, aChunks, aName) { + this.children = []; + this.sourceContents = {}; + this.line = aLine === undefined ? null : aLine; + this.column = aColumn === undefined ? null : aColumn; + this.source = aSource === undefined ? null : aSource; + this.name = aName === undefined ? null : aName; + if (aChunks != null) this.add(aChunks); + } + + /** + * Creates a SourceNode from generated code and a SourceMapConsumer. + * + * @param aGeneratedCode The generated code + * @param aSourceMapConsumer The SourceMap for the generated code + */ + SourceNode.fromStringWithSourceMap = + function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) { + // The SourceNode we want to fill with the generated code + // and the SourceMap + var node = new SourceNode(); + + // The generated code + // Processed fragments are removed from this array. + var remainingLines = aGeneratedCode.split('\n'); + + // We need to remember the position of "remainingLines" + var lastGeneratedLine = 1, lastGeneratedColumn = 0; + + // The generate SourceNodes we need a code range. + // To extract it current and last mapping is used. + // Here we store the last mapping. + var lastMapping = null; + + aSourceMapConsumer.eachMapping(function (mapping) { + if (lastMapping === null) { + // We add the generated code until the first mapping + // to the SourceNode without any mapping. + // Each line is added as separate string. + while (lastGeneratedLine < mapping.generatedLine) { + node.add(remainingLines.shift() + "\n"); + lastGeneratedLine++; + } + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + node.add(nextLine.substr(0, mapping.generatedColumn)); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + } else { + // We add the code from "lastMapping" to "mapping": + // First check if there is a new line in between. + if (lastGeneratedLine < mapping.generatedLine) { + var code = ""; + // Associate full lines with "lastMapping" + do { + code += remainingLines.shift() + "\n"; + lastGeneratedLine++; + lastGeneratedColumn = 0; + } while (lastGeneratedLine < mapping.generatedLine); + // When we reached the correct line, we add code until we + // reach the correct column too. + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + code += nextLine.substr(0, mapping.generatedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + // Create the SourceNode. + addMappingWithCode(lastMapping, code); + } else { + // There is no new line in between. + // Associate the code between "lastGeneratedColumn" and + // "mapping.generatedColumn" with "lastMapping" + var nextLine = remainingLines[0]; + var code = nextLine.substr(0, mapping.generatedColumn - + lastGeneratedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn - + lastGeneratedColumn); + lastGeneratedColumn = mapping.generatedColumn; + addMappingWithCode(lastMapping, code); + } + } + lastMapping = mapping; + }, this); + // We have processed all mappings. + // Associate the remaining code in the current line with "lastMapping" + // and add the remaining lines without any mapping + addMappingWithCode(lastMapping, remainingLines.join("\n")); + + // Copy sourcesContent into SourceNode + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + node.setSourceContent(sourceFile, content); + } + }); + + return node; + + function addMappingWithCode(mapping, code) { + if (mapping === null || mapping.source === undefined) { + node.add(code); + } else { + node.add(new SourceNode(mapping.originalLine, + mapping.originalColumn, + mapping.source, + code, + mapping.name)); + } + } + }; + + /** + * Add a chunk of generated JS to this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + SourceNode.prototype.add = function SourceNode_add(aChunk) { + if (Array.isArray(aChunk)) { + aChunk.forEach(function (chunk) { + this.add(chunk); + }, this); + } + else if (aChunk instanceof SourceNode || typeof aChunk === "string") { + if (aChunk) { + this.children.push(aChunk); + } + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; + }; + + /** + * Add a chunk of generated JS to the beginning of this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { + if (Array.isArray(aChunk)) { + for (var i = aChunk.length-1; i >= 0; i--) { + this.prepend(aChunk[i]); + } + } + else if (aChunk instanceof SourceNode || typeof aChunk === "string") { + this.children.unshift(aChunk); + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; + }; + + /** + * Walk over the tree of JS snippets in this node and its children. The + * walking function is called once for each snippet of JS and is passed that + * snippet and the its original associated source's line/column location. + * + * @param aFn The traversal function. + */ + SourceNode.prototype.walk = function SourceNode_walk(aFn) { + var chunk; + for (var i = 0, len = this.children.length; i < len; i++) { + chunk = this.children[i]; + if (chunk instanceof SourceNode) { + chunk.walk(aFn); + } + else { + if (chunk !== '') { + aFn(chunk, { source: this.source, + line: this.line, + column: this.column, + name: this.name }); + } + } + } + }; + + /** + * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between + * each of `this.children`. + * + * @param aSep The separator. + */ + SourceNode.prototype.join = function SourceNode_join(aSep) { + var newChildren; + var i; + var len = this.children.length; + if (len > 0) { + newChildren = []; + for (i = 0; i < len-1; i++) { + newChildren.push(this.children[i]); + newChildren.push(aSep); + } + newChildren.push(this.children[i]); + this.children = newChildren; + } + return this; + }; + + /** + * Call String.prototype.replace on the very right-most source snippet. Useful + * for trimming whitespace from the end of a source node, etc. + * + * @param aPattern The pattern to replace. + * @param aReplacement The thing to replace the pattern with. + */ + SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { + var lastChild = this.children[this.children.length - 1]; + if (lastChild instanceof SourceNode) { + lastChild.replaceRight(aPattern, aReplacement); + } + else if (typeof lastChild === 'string') { + this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); + } + else { + this.children.push(''.replace(aPattern, aReplacement)); + } + return this; + }; + + /** + * Set the source content for a source file. This will be added to the SourceMapGenerator + * in the sourcesContent field. + * + * @param aSourceFile The filename of the source file + * @param aSourceContent The content of the source file + */ + SourceNode.prototype.setSourceContent = + function SourceNode_setSourceContent(aSourceFile, aSourceContent) { + this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; + }; + + /** + * Walk over the tree of SourceNodes. The walking function is called for each + * source file content and is passed the filename and source content. + * + * @param aFn The traversal function. + */ + SourceNode.prototype.walkSourceContents = + function SourceNode_walkSourceContents(aFn) { + for (var i = 0, len = this.children.length; i < len; i++) { + if (this.children[i] instanceof SourceNode) { + this.children[i].walkSourceContents(aFn); + } + } + + var sources = Object.keys(this.sourceContents); + for (var i = 0, len = sources.length; i < len; i++) { + aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]); + } + }; + + /** + * Return the string representation of this source node. Walks over the tree + * and concatenates all the various snippets together to one string. + */ + SourceNode.prototype.toString = function SourceNode_toString() { + var str = ""; + this.walk(function (chunk) { + str += chunk; + }); + return str; + }; + + /** + * Returns the string representation of this source node along with a source + * map. + */ + SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { + var generated = { + code: "", + line: 1, + column: 0 + }; + var map = new SourceMapGenerator(aArgs); + var sourceMappingActive = false; + var lastOriginalSource = null; + var lastOriginalLine = null; + var lastOriginalColumn = null; + var lastOriginalName = null; + this.walk(function (chunk, original) { + generated.code += chunk; + if (original.source !== null + && original.line !== null + && original.column !== null) { + if(lastOriginalSource !== original.source + || lastOriginalLine !== original.line + || lastOriginalColumn !== original.column + || lastOriginalName !== original.name) { + map.addMapping({ + source: original.source, + original: { + line: original.line, + column: original.column + }, + generated: { + line: generated.line, + column: generated.column + }, + name: original.name + }); + } + lastOriginalSource = original.source; + lastOriginalLine = original.line; + lastOriginalColumn = original.column; + lastOriginalName = original.name; + sourceMappingActive = true; + } else if (sourceMappingActive) { + map.addMapping({ + generated: { + line: generated.line, + column: generated.column + } + }); + lastOriginalSource = null; + sourceMappingActive = false; + } + chunk.split('').forEach(function (ch) { + if (ch === '\n') { + generated.line++; + generated.column = 0; + } else { + generated.column++; + } + }); + }); + this.walkSourceContents(function (sourceFile, sourceContent) { + map.setSourceContent(sourceFile, sourceContent); + }); + + return { code: generated.code, map: map }; + }; + + exports.SourceNode = SourceNode; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/util.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/util.js new file mode 100644 index 0000000..87946d3 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/lib/source-map/util.js @@ -0,0 +1,205 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + /** + * This is a helper function for getting values from parameter/options + * objects. + * + * @param args The object we are extracting values from + * @param name The name of the property we are getting. + * @param defaultValue An optional value to return if the property is missing + * from the object. If this is not specified and the property is missing, an + * error will be thrown. + */ + function getArg(aArgs, aName, aDefaultValue) { + if (aName in aArgs) { + return aArgs[aName]; + } else if (arguments.length === 3) { + return aDefaultValue; + } else { + throw new Error('"' + aName + '" is a required argument.'); + } + } + exports.getArg = getArg; + + var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; + var dataUrlRegexp = /^data:.+\,.+/; + + function urlParse(aUrl) { + var match = aUrl.match(urlRegexp); + if (!match) { + return null; + } + return { + scheme: match[1], + auth: match[3], + host: match[4], + port: match[6], + path: match[7] + }; + } + exports.urlParse = urlParse; + + function urlGenerate(aParsedUrl) { + var url = aParsedUrl.scheme + "://"; + if (aParsedUrl.auth) { + url += aParsedUrl.auth + "@" + } + if (aParsedUrl.host) { + url += aParsedUrl.host; + } + if (aParsedUrl.port) { + url += ":" + aParsedUrl.port + } + if (aParsedUrl.path) { + url += aParsedUrl.path; + } + return url; + } + exports.urlGenerate = urlGenerate; + + function join(aRoot, aPath) { + var url; + + if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) { + return aPath; + } + + if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { + url.path = aPath; + return urlGenerate(url); + } + + return aRoot.replace(/\/$/, '') + '/' + aPath; + } + exports.join = join; + + /** + * Because behavior goes wacky when you set `__proto__` on objects, we + * have to prefix all the strings in our set with an arbitrary character. + * + * See https://github.com/mozilla/source-map/pull/31 and + * https://github.com/mozilla/source-map/issues/30 + * + * @param String aStr + */ + function toSetString(aStr) { + return '$' + aStr; + } + exports.toSetString = toSetString; + + function fromSetString(aStr) { + return aStr.substr(1); + } + exports.fromSetString = fromSetString; + + function relative(aRoot, aPath) { + aRoot = aRoot.replace(/\/$/, ''); + + var url = urlParse(aRoot); + if (aPath.charAt(0) == "/" && url && url.path == "/") { + return aPath.slice(1); + } + + return aPath.indexOf(aRoot + '/') === 0 + ? aPath.substr(aRoot.length + 1) + : aPath; + } + exports.relative = relative; + + function strcmp(aStr1, aStr2) { + var s1 = aStr1 || ""; + var s2 = aStr2 || ""; + return (s1 > s2) - (s1 < s2); + } + + /** + * Comparator between two mappings where the original positions are compared. + * + * Optionally pass in `true` as `onlyCompareGenerated` to consider two + * mappings with the same original source/line/column, but different generated + * line and column the same. Useful when searching for a mapping with a + * stubbed out mapping. + */ + function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) { + var cmp; + + cmp = strcmp(mappingA.source, mappingB.source); + if (cmp) { + return cmp; + } + + cmp = mappingA.originalLine - mappingB.originalLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.originalColumn - mappingB.originalColumn; + if (cmp || onlyCompareOriginal) { + return cmp; + } + + cmp = strcmp(mappingA.name, mappingB.name); + if (cmp) { + return cmp; + } + + cmp = mappingA.generatedLine - mappingB.generatedLine; + if (cmp) { + return cmp; + } + + return mappingA.generatedColumn - mappingB.generatedColumn; + }; + exports.compareByOriginalPositions = compareByOriginalPositions; + + /** + * Comparator between two mappings where the generated positions are + * compared. + * + * Optionally pass in `true` as `onlyCompareGenerated` to consider two + * mappings with the same generated line and column, but different + * source/name/original line and column the same. Useful when searching for a + * mapping with a stubbed out mapping. + */ + function compareByGeneratedPositions(mappingA, mappingB, onlyCompareGenerated) { + var cmp; + + cmp = mappingA.generatedLine - mappingB.generatedLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.generatedColumn - mappingB.generatedColumn; + if (cmp || onlyCompareGenerated) { + return cmp; + } + + cmp = strcmp(mappingA.source, mappingB.source); + if (cmp) { + return cmp; + } + + cmp = mappingA.originalLine - mappingB.originalLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.originalColumn - mappingB.originalColumn; + if (cmp) { + return cmp; + } + + return strcmp(mappingA.name, mappingB.name); + }; + exports.compareByGeneratedPositions = compareByGeneratedPositions; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/LICENSE b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/LICENSE new file mode 100644 index 0000000..f33d665 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/LICENSE @@ -0,0 +1,58 @@ +amdefine is released under two licenses: new BSD, and MIT. You may pick the +license that best suits your development needs. The text of both licenses are +provided below. + + +The "New" BSD License: +---------------------- + +Copyright (c) 2011, The Dojo Foundation +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 the Dojo Foundation 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 OWNER 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. + + + +MIT License +----------- + +Copyright (c) 2011, The Dojo Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/README.md b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/README.md new file mode 100644 index 0000000..c6995c0 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/README.md @@ -0,0 +1,171 @@ +# amdefine + +A module that can be used to implement AMD's define() in Node. This allows you +to code to the AMD API and have the module work in node programs without +requiring those other programs to use AMD. + +## Usage + +**1)** Update your package.json to indicate amdefine as a dependency: + +```javascript + "dependencies": { + "amdefine": ">=0.1.0" + } +``` + +Then run `npm install` to get amdefine into your project. + +**2)** At the top of each module that uses define(), place this code: + +```javascript +if (typeof define !== 'function') { var define = require('amdefine')(module) } +``` + +**Only use these snippets** when loading amdefine. If you preserve the basic structure, +with the braces, it will be stripped out when using the [RequireJS optimizer](#optimizer). + +You can add spaces, line breaks and even require amdefine with a local path, but +keep the rest of the structure to get the stripping behavior. + +As you may know, because `if` statements in JavaScript don't have their own scope, the var +declaration in the above snippet is made whether the `if` expression is truthy or not. If +RequireJS is loaded then the declaration is superfluous because `define` is already already +declared in the same scope in RequireJS. Fortunately JavaScript handles multiple `var` +declarations of the same variable in the same scope gracefully. + +If you want to deliver amdefine.js with your code rather than specifying it as a dependency +with npm, then just download the latest release and refer to it using a relative path: + +[Latest Version](https://github.com/jrburke/amdefine/raw/latest/amdefine.js) + +### amdefine/intercept + +Consider this very experimental. + +Instead of pasting the piece of text for the amdefine setup of a `define` +variable in each module you create or consume, you can use `amdefine/intercept` +instead. It will automatically insert the above snippet in each .js file loaded +by Node. + +**Warning**: you should only use this if you are creating an application that +is consuming AMD style defined()'d modules that are distributed via npm and want +to run that code in Node. + +For library code where you are not sure if it will be used by others in Node or +in the browser, then explicitly depending on amdefine and placing the code +snippet above is suggested path, instead of using `amdefine/intercept`. The +intercept module affects all .js files loaded in the Node app, and it is +inconsiderate to modify global state like that unless you are also controlling +the top level app. + +#### Why distribute AMD-style nodes via npm? + +npm has a lot of weaknesses for front-end use (installed layout is not great, +should have better support for the `baseUrl + moduleID + '.js' style of loading, +single file JS installs), but some people want a JS package manager and are +willing to live with those constraints. If that is you, but still want to author +in AMD style modules to get dynamic require([]), better direct source usage and +powerful loader plugin support in the browser, then this tool can help. + +#### amdefine/intercept usage + +Just require it in your top level app module (for example index.js, server.js): + +```javascript +require('amdefine/intercept'); +``` + +The module does not return a value, so no need to assign the result to a local +variable. + +Then just require() code as you normally would with Node's require(). Any .js +loaded after the intercept require will have the amdefine check injected in +the .js source as it is loaded. It does not modify the source on disk, just +prepends some content to the text of the module as it is loaded by Node. + +#### How amdefine/intercept works + +It overrides the `Module._extensions['.js']` in Node to automatically prepend +the amdefine snippet above. So, it will affect any .js file loaded by your +app. + +## define() usage + +It is best if you use the anonymous forms of define() in your module: + +```javascript +define(function (require) { + var dependency = require('dependency'); +}); +``` + +or + +```javascript +define(['dependency'], function (dependency) { + +}); +``` + +## RequireJS optimizer integration.
    + +Version 1.0.3 of the [RequireJS optimizer](http://requirejs.org/docs/optimization.html) +will have support for stripping the `if (typeof define !== 'function')` check +mentioned above, so you can include this snippet for code that runs in the +browser, but avoid taking the cost of the if() statement once the code is +optimized for deployment. + +## Node 0.4 Support + +If you want to support Node 0.4, then add `require` as the second parameter to amdefine: + +```javascript +//Only if you want Node 0.4. If using 0.5 or later, use the above snippet. +if (typeof define !== 'function') { var define = require('amdefine')(module, require) } +``` + +## Limitations + +### Synchronous vs Asynchronous + +amdefine creates a define() function that is callable by your code. It will +execute and trace dependencies and call the factory function *synchronously*, +to keep the behavior in line with Node's synchronous dependency tracing. + +The exception: calling AMD's callback-style require() from inside a factory +function. The require callback is called on process.nextTick(): + +```javascript +define(function (require) { + require(['a'], function(a) { + //'a' is loaded synchronously, but + //this callback is called on process.nextTick(). + }); +}); +``` + +### Loader Plugins + +Loader plugins are supported as long as they call their load() callbacks +synchronously. So ones that do network requests will not work. However plugins +like [text](http://requirejs.org/docs/api.html#text) can load text files locally. + +The plugin API's `load.fromText()` is **not supported** in amdefine, so this means +transpiler plugins like the [CoffeeScript loader plugin](https://github.com/jrburke/require-cs) +will not work. This may be fixable, but it is a bit complex, and I do not have +enough node-fu to figure it out yet. See the source for amdefine.js if you want +to get an idea of the issues involved. + +## Tests + +To run the tests, cd to **tests** and run: + +``` +node all.js +node all-intercept.js +``` + +## License + +New BSD and MIT. Check the LICENSE file for all the details. diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/amdefine.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/amdefine.js new file mode 100644 index 0000000..53bf5a6 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/amdefine.js @@ -0,0 +1,299 @@ +/** vim: et:ts=4:sw=4:sts=4 + * @license amdefine 0.1.0 Copyright (c) 2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/amdefine for details + */ + +/*jslint node: true */ +/*global module, process */ +'use strict'; + +/** + * Creates a define for node. + * @param {Object} module the "module" object that is defined by Node for the + * current module. + * @param {Function} [requireFn]. Node's require function for the current module. + * It only needs to be passed in Node versions before 0.5, when module.require + * did not exist. + * @returns {Function} a define function that is usable for the current node + * module. + */ +function amdefine(module, requireFn) { + 'use strict'; + var defineCache = {}, + loaderCache = {}, + alreadyCalled = false, + path = require('path'), + makeRequire, stringRequire; + + /** + * Trims the . and .. from an array of path segments. + * It will keep a leading path segment if a .. will become + * the first path segment, to help with module name lookups, + * which act like paths, but can be remapped. But the end result, + * all paths that use this function should look normalized. + * NOTE: this method MODIFIES the input array. + * @param {Array} ary the array of path segments. + */ + function trimDots(ary) { + var i, part; + for (i = 0; ary[i]; i+= 1) { + part = ary[i]; + if (part === '.') { + ary.splice(i, 1); + i -= 1; + } else if (part === '..') { + if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { + //End of the line. Keep at least one non-dot + //path segment at the front so it can be mapped + //correctly to disk. Otherwise, there is likely + //no path mapping for a path starting with '..'. + //This can still fail, but catches the most reasonable + //uses of .. + break; + } else if (i > 0) { + ary.splice(i - 1, 2); + i -= 2; + } + } + } + } + + function normalize(name, baseName) { + var baseParts; + + //Adjust any relative paths. + if (name && name.charAt(0) === '.') { + //If have a base name, try to normalize against it, + //otherwise, assume it is a top-level require that will + //be relative to baseUrl in the end. + if (baseName) { + baseParts = baseName.split('/'); + baseParts = baseParts.slice(0, baseParts.length - 1); + baseParts = baseParts.concat(name.split('/')); + trimDots(baseParts); + name = baseParts.join('/'); + } + } + + return name; + } + + /** + * Create the normalize() function passed to a loader plugin's + * normalize method. + */ + function makeNormalize(relName) { + return function (name) { + return normalize(name, relName); + }; + } + + function makeLoad(id) { + function load(value) { + loaderCache[id] = value; + } + + load.fromText = function (id, text) { + //This one is difficult because the text can/probably uses + //define, and any relative paths and requires should be relative + //to that id was it would be found on disk. But this would require + //bootstrapping a module/require fairly deeply from node core. + //Not sure how best to go about that yet. + throw new Error('amdefine does not implement load.fromText'); + }; + + return load; + } + + makeRequire = function (systemRequire, exports, module, relId) { + function amdRequire(deps, callback) { + if (typeof deps === 'string') { + //Synchronous, single module require('') + return stringRequire(systemRequire, exports, module, deps, relId); + } else { + //Array of dependencies with a callback. + + //Convert the dependencies to modules. + deps = deps.map(function (depName) { + return stringRequire(systemRequire, exports, module, depName, relId); + }); + + //Wait for next tick to call back the require call. + process.nextTick(function () { + callback.apply(null, deps); + }); + } + } + + amdRequire.toUrl = function (filePath) { + if (filePath.indexOf('.') === 0) { + return normalize(filePath, path.dirname(module.filename)); + } else { + return filePath; + } + }; + + return amdRequire; + }; + + //Favor explicit value, passed in if the module wants to support Node 0.4. + requireFn = requireFn || function req() { + return module.require.apply(module, arguments); + }; + + function runFactory(id, deps, factory) { + var r, e, m, result; + + if (id) { + e = loaderCache[id] = {}; + m = { + id: id, + uri: __filename, + exports: e + }; + r = makeRequire(requireFn, e, m, id); + } else { + //Only support one define call per file + if (alreadyCalled) { + throw new Error('amdefine with no module ID cannot be called more than once per file.'); + } + alreadyCalled = true; + + //Use the real variables from node + //Use module.exports for exports, since + //the exports in here is amdefine exports. + e = module.exports; + m = module; + r = makeRequire(requireFn, e, m, module.id); + } + + //If there are dependencies, they are strings, so need + //to convert them to dependency values. + if (deps) { + deps = deps.map(function (depName) { + return r(depName); + }); + } + + //Call the factory with the right dependencies. + if (typeof factory === 'function') { + result = factory.apply(m.exports, deps); + } else { + result = factory; + } + + if (result !== undefined) { + m.exports = result; + if (id) { + loaderCache[id] = m.exports; + } + } + } + + stringRequire = function (systemRequire, exports, module, id, relId) { + //Split the ID by a ! so that + var index = id.indexOf('!'), + originalId = id, + prefix, plugin; + + if (index === -1) { + id = normalize(id, relId); + + //Straight module lookup. If it is one of the special dependencies, + //deal with it, otherwise, delegate to node. + if (id === 'require') { + return makeRequire(systemRequire, exports, module, relId); + } else if (id === 'exports') { + return exports; + } else if (id === 'module') { + return module; + } else if (loaderCache.hasOwnProperty(id)) { + return loaderCache[id]; + } else if (defineCache[id]) { + runFactory.apply(null, defineCache[id]); + return loaderCache[id]; + } else { + if(systemRequire) { + return systemRequire(originalId); + } else { + throw new Error('No module with ID: ' + id); + } + } + } else { + //There is a plugin in play. + prefix = id.substring(0, index); + id = id.substring(index + 1, id.length); + + plugin = stringRequire(systemRequire, exports, module, prefix, relId); + + if (plugin.normalize) { + id = plugin.normalize(id, makeNormalize(relId)); + } else { + //Normalize the ID normally. + id = normalize(id, relId); + } + + if (loaderCache[id]) { + return loaderCache[id]; + } else { + plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {}); + + return loaderCache[id]; + } + } + }; + + //Create a define function specific to the module asking for amdefine. + function define(id, deps, factory) { + if (Array.isArray(id)) { + factory = deps; + deps = id; + id = undefined; + } else if (typeof id !== 'string') { + factory = id; + id = deps = undefined; + } + + if (deps && !Array.isArray(deps)) { + factory = deps; + deps = undefined; + } + + if (!deps) { + deps = ['require', 'exports', 'module']; + } + + //Set up properties for this module. If an ID, then use + //internal cache. If no ID, then use the external variables + //for this node module. + if (id) { + //Put the module in deep freeze until there is a + //require call for it. + defineCache[id] = [id, deps, factory]; + } else { + runFactory(id, deps, factory); + } + } + + //define.require, which has access to all the values in the + //cache. Useful for AMD modules that all have IDs in the file, + //but need to finally export a value to node based on one of those + //IDs. + define.require = function (id) { + if (loaderCache[id]) { + return loaderCache[id]; + } + + if (defineCache[id]) { + runFactory.apply(null, defineCache[id]); + return loaderCache[id]; + } + }; + + define.amd = {}; + + return define; +} + +module.exports = amdefine; diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/intercept.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/intercept.js new file mode 100644 index 0000000..771a983 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/intercept.js @@ -0,0 +1,36 @@ +/*jshint node: true */ +var inserted, + Module = require('module'), + fs = require('fs'), + existingExtFn = Module._extensions['.js'], + amdefineRegExp = /amdefine\.js/; + +inserted = "if (typeof define !== 'function') {var define = require('amdefine')(module)}"; + +//From the node/lib/module.js source: +function stripBOM(content) { + // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) + // because the buffer-to-string conversion in `fs.readFileSync()` + // translates it to FEFF, the UTF-16 BOM. + if (content.charCodeAt(0) === 0xFEFF) { + content = content.slice(1); + } + return content; +} + +//Also adapted from the node/lib/module.js source: +function intercept(module, filename) { + var content = stripBOM(fs.readFileSync(filename, 'utf8')); + + if (!amdefineRegExp.test(module.id)) { + content = inserted + content; + } + + module._compile(content, filename); +} + +intercept._id = 'amdefine/intercept'; + +if (!existingExtFn._id || existingExtFn._id !== intercept._id) { + Module._extensions['.js'] = intercept; +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/package.json b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/package.json new file mode 100644 index 0000000..7041776 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/package.json @@ -0,0 +1,40 @@ +{ + "name": "amdefine", + "description": "Provide AMD's define() API for declaring modules in the AMD format", + "version": "0.1.0", + "homepage": "http://github.com/jrburke/amdefine", + "author": { + "name": "James Burke", + "email": "jrburke@gmail.com", + "url": "http://github.com/jrburke" + }, + "licenses": [ + { + "type": "BSD", + "url": "https://github.com/jrburke/amdefine/blob/master/LICENSE" + }, + { + "type": "MIT", + "url": "https://github.com/jrburke/amdefine/blob/master/LICENSE" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/jrburke/amdefine.git" + }, + "main": "./amdefine.js", + "engines": { + "node": ">=0.4.2" + }, + "readme": "# amdefine\n\nA module that can be used to implement AMD's define() in Node. This allows you\nto code to the AMD API and have the module work in node programs without\nrequiring those other programs to use AMD.\n\n## Usage\n\n**1)** Update your package.json to indicate amdefine as a dependency:\n\n```javascript\n \"dependencies\": {\n \"amdefine\": \">=0.1.0\"\n }\n```\n\nThen run `npm install` to get amdefine into your project.\n\n**2)** At the top of each module that uses define(), place this code:\n\n```javascript\nif (typeof define !== 'function') { var define = require('amdefine')(module) }\n```\n\n**Only use these snippets** when loading amdefine. If you preserve the basic structure,\nwith the braces, it will be stripped out when using the [RequireJS optimizer](#optimizer).\n\nYou can add spaces, line breaks and even require amdefine with a local path, but\nkeep the rest of the structure to get the stripping behavior.\n\nAs you may know, because `if` statements in JavaScript don't have their own scope, the var\ndeclaration in the above snippet is made whether the `if` expression is truthy or not. If\nRequireJS is loaded then the declaration is superfluous because `define` is already already\ndeclared in the same scope in RequireJS. Fortunately JavaScript handles multiple `var`\ndeclarations of the same variable in the same scope gracefully.\n\nIf you want to deliver amdefine.js with your code rather than specifying it as a dependency\nwith npm, then just download the latest release and refer to it using a relative path:\n\n[Latest Version](https://github.com/jrburke/amdefine/raw/latest/amdefine.js)\n\n### amdefine/intercept\n\nConsider this very experimental.\n\nInstead of pasting the piece of text for the amdefine setup of a `define`\nvariable in each module you create or consume, you can use `amdefine/intercept`\ninstead. It will automatically insert the above snippet in each .js file loaded\nby Node.\n\n**Warning**: you should only use this if you are creating an application that\nis consuming AMD style defined()'d modules that are distributed via npm and want\nto run that code in Node.\n\nFor library code where you are not sure if it will be used by others in Node or\nin the browser, then explicitly depending on amdefine and placing the code\nsnippet above is suggested path, instead of using `amdefine/intercept`. The\nintercept module affects all .js files loaded in the Node app, and it is\ninconsiderate to modify global state like that unless you are also controlling\nthe top level app.\n\n#### Why distribute AMD-style nodes via npm?\n\nnpm has a lot of weaknesses for front-end use (installed layout is not great,\nshould have better support for the `baseUrl + moduleID + '.js' style of loading,\nsingle file JS installs), but some people want a JS package manager and are\nwilling to live with those constraints. If that is you, but still want to author\nin AMD style modules to get dynamic require([]), better direct source usage and\npowerful loader plugin support in the browser, then this tool can help.\n\n#### amdefine/intercept usage\n\nJust require it in your top level app module (for example index.js, server.js):\n\n```javascript\nrequire('amdefine/intercept');\n```\n\nThe module does not return a value, so no need to assign the result to a local\nvariable.\n\nThen just require() code as you normally would with Node's require(). Any .js\nloaded after the intercept require will have the amdefine check injected in\nthe .js source as it is loaded. It does not modify the source on disk, just\nprepends some content to the text of the module as it is loaded by Node.\n\n#### How amdefine/intercept works\n\nIt overrides the `Module._extensions['.js']` in Node to automatically prepend\nthe amdefine snippet above. So, it will affect any .js file loaded by your\napp.\n\n## define() usage\n\nIt is best if you use the anonymous forms of define() in your module:\n\n```javascript\ndefine(function (require) {\n var dependency = require('dependency');\n});\n```\n\nor\n\n```javascript\ndefine(['dependency'], function (dependency) {\n\n});\n```\n\n## RequireJS optimizer integration. \n\nVersion 1.0.3 of the [RequireJS optimizer](http://requirejs.org/docs/optimization.html)\nwill have support for stripping the `if (typeof define !== 'function')` check\nmentioned above, so you can include this snippet for code that runs in the\nbrowser, but avoid taking the cost of the if() statement once the code is\noptimized for deployment.\n\n## Node 0.4 Support\n\nIf you want to support Node 0.4, then add `require` as the second parameter to amdefine:\n\n```javascript\n//Only if you want Node 0.4. If using 0.5 or later, use the above snippet.\nif (typeof define !== 'function') { var define = require('amdefine')(module, require) }\n```\n\n## Limitations\n\n### Synchronous vs Asynchronous\n\namdefine creates a define() function that is callable by your code. It will\nexecute and trace dependencies and call the factory function *synchronously*,\nto keep the behavior in line with Node's synchronous dependency tracing.\n\nThe exception: calling AMD's callback-style require() from inside a factory\nfunction. The require callback is called on process.nextTick():\n\n```javascript\ndefine(function (require) {\n require(['a'], function(a) {\n //'a' is loaded synchronously, but\n //this callback is called on process.nextTick().\n });\n});\n```\n\n### Loader Plugins\n\nLoader plugins are supported as long as they call their load() callbacks\nsynchronously. So ones that do network requests will not work. However plugins\nlike [text](http://requirejs.org/docs/api.html#text) can load text files locally.\n\nThe plugin API's `load.fromText()` is **not supported** in amdefine, so this means\ntranspiler plugins like the [CoffeeScript loader plugin](https://github.com/jrburke/require-cs)\nwill not work. This may be fixable, but it is a bit complex, and I do not have\nenough node-fu to figure it out yet. See the source for amdefine.js if you want\nto get an idea of the issues involved.\n\n## Tests\n\nTo run the tests, cd to **tests** and run:\n\n```\nnode all.js\nnode all-intercept.js\n```\n\n## License\n\nNew BSD and MIT. Check the LICENSE file for all the details.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/jrburke/amdefine/issues" + }, + "_id": "amdefine@0.1.0", + "dist": { + "shasum": "273a820f5f58f0585e74bf1f5b8d7c03e2e56ba8" + }, + "_from": "amdefine@>=0.0.4", + "_resolved": "https://registry.npmjs.org/amdefine/-/amdefine-0.1.0.tgz" +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/package.json b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/package.json new file mode 100644 index 0000000..8ff0560 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/package.json @@ -0,0 +1,114 @@ +{ + "name": "source-map", + "description": "Generates and consumes source maps", + "version": "0.1.31", + "homepage": "https://github.com/mozilla/source-map", + "author": { + "name": "Nick Fitzgerald", + "email": "nfitzgerald@mozilla.com" + }, + "contributors": [ + { + "name": "Tobias Koppers", + "email": "tobias.koppers@googlemail.com" + }, + { + "name": "Duncan Beevers", + "email": "duncan@dweebd.com" + }, + { + "name": "Stephen Crane", + "email": "scrane@mozilla.com" + }, + { + "name": "Ryan Seddon", + "email": "seddon.ryan@gmail.com" + }, + { + "name": "Miles Elam", + "email": "miles.elam@deem.com" + }, + { + "name": "Mihai Bazon", + "email": "mihai.bazon@gmail.com" + }, + { + "name": "Michael Ficarra", + "email": "github.public.email@michael.ficarra.me" + }, + { + "name": "Todd Wolfson", + "email": "todd@twolfson.com" + }, + { + "name": "Alexander Solovyov", + "email": "alexander@solovyov.net" + }, + { + "name": "Felix Gnass", + "email": "fgnass@gmail.com" + }, + { + "name": "Conrad Irwin", + "email": "conrad.irwin@gmail.com" + }, + { + "name": "usrbincc", + "email": "usrbincc@yahoo.com" + }, + { + "name": "David Glasser", + "email": "glasser@davidglasser.net" + }, + { + "name": "Chase Douglas", + "email": "chase@newrelic.com" + }, + { + "name": "Evan Wallace", + "email": "evan.exe@gmail.com" + }, + { + "name": "Heather Arthur", + "email": "fayearthur@gmail.com" + } + ], + "repository": { + "type": "git", + "url": "http://github.com/mozilla/source-map.git" + }, + "directories": { + "lib": "./lib" + }, + "main": "./lib/source-map.js", + "engines": { + "node": ">=0.8.0" + }, + "licenses": [ + { + "type": "BSD", + "url": "http://opensource.org/licenses/BSD-3-Clause" + } + ], + "dependencies": { + "amdefine": ">=0.0.4" + }, + "devDependencies": { + "dryice": ">=0.4.8" + }, + "scripts": { + "test": "node test/run-tests.js", + "build": "node Makefile.dryice.js" + }, + "readme": "# Source Map\n\nThis is a library to generate and consume the source map format\n[described here][format].\n\nThis library is written in the Asynchronous Module Definition format, and works\nin the following environments:\n\n* Modern Browsers supporting ECMAScript 5 (either after the build, or with an\n AMD loader such as RequireJS)\n\n* Inside Firefox (as a JSM file, after the build)\n\n* With NodeJS versions 0.8.X and higher\n\n## Node\n\n $ npm install source-map\n\n## Building from Source (for everywhere else)\n\nInstall Node and then run\n\n $ git clone https://fitzgen@github.com/mozilla/source-map.git\n $ cd source-map\n $ npm link .\n\nNext, run\n\n $ node Makefile.dryice.js\n\nThis should spew a bunch of stuff to stdout, and create the following files:\n\n* `dist/source-map.js` - The unminified browser version.\n\n* `dist/source-map.min.js` - The minified browser version.\n\n* `dist/SourceMap.jsm` - The JavaScript Module for inclusion in Firefox source.\n\n## Examples\n\n### Consuming a source map\n\n var rawSourceMap = {\n version: 3,\n file: 'min.js',\n names: ['bar', 'baz', 'n'],\n sources: ['one.js', 'two.js'],\n sourceRoot: 'http://example.com/www/js/',\n mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'\n };\n\n var smc = new SourceMapConsumer(rawSourceMap);\n\n console.log(smc.sources);\n // [ 'http://example.com/www/js/one.js',\n // 'http://example.com/www/js/two.js' ]\n\n console.log(smc.originalPositionFor({\n line: 2,\n column: 28\n }));\n // { source: 'http://example.com/www/js/two.js',\n // line: 2,\n // column: 10,\n // name: 'n' }\n\n console.log(smc.generatedPositionFor({\n source: 'http://example.com/www/js/two.js',\n line: 2,\n column: 10\n }));\n // { line: 2, column: 28 }\n\n smc.eachMapping(function (m) {\n // ...\n });\n\n### Generating a source map\n\nIn depth guide:\n[**Compiling to JavaScript, and Debugging with Source Maps**](https://hacks.mozilla.org/2013/05/compiling-to-javascript-and-debugging-with-source-maps/)\n\n#### With SourceNode (high level API)\n\n function compile(ast) {\n switch (ast.type) {\n case 'BinaryExpression':\n return new SourceNode(\n ast.location.line,\n ast.location.column,\n ast.location.source,\n [compile(ast.left), \" + \", compile(ast.right)]\n );\n case 'Literal':\n return new SourceNode(\n ast.location.line,\n ast.location.column,\n ast.location.source,\n String(ast.value)\n );\n // ...\n default:\n throw new Error(\"Bad AST\");\n }\n }\n\n var ast = parse(\"40 + 2\", \"add.js\");\n console.log(compile(ast).toStringWithSourceMap({\n file: 'add.js'\n }));\n // { code: '40 + 2',\n // map: [object SourceMapGenerator] }\n\n#### With SourceMapGenerator (low level API)\n\n var map = new SourceMapGenerator({\n file: \"source-mapped.js\"\n });\n\n map.addMapping({\n generated: {\n line: 10,\n column: 35\n },\n source: \"foo.js\",\n original: {\n line: 33,\n column: 2\n },\n name: \"christopher\"\n });\n\n console.log(map.toString());\n // '{\"version\":3,\"file\":\"source-mapped.js\",\"sources\":[\"foo.js\"],\"names\":[\"christopher\"],\"mappings\":\";;;;;;;;;mCAgCEA\"}'\n\n## API\n\nGet a reference to the module:\n\n // NodeJS\n var sourceMap = require('source-map');\n\n // Browser builds\n var sourceMap = window.sourceMap;\n\n // Inside Firefox\n let sourceMap = {};\n Components.utils.import('resource:///modules/devtools/SourceMap.jsm', sourceMap);\n\n### SourceMapConsumer\n\nA SourceMapConsumer instance represents a parsed source map which we can query\nfor information about the original file positions by giving it a file position\nin the generated source.\n\n#### new SourceMapConsumer(rawSourceMap)\n\nThe only parameter is the raw source map (either as a string which can be\n`JSON.parse`'d, or an object). According to the spec, source maps have the\nfollowing attributes:\n\n* `version`: Which version of the source map spec this map is following.\n\n* `sources`: An array of URLs to the original source files.\n\n* `names`: An array of identifiers which can be referrenced by individual\n mappings.\n\n* `sourceRoot`: Optional. The URL root from which all sources are relative.\n\n* `sourcesContent`: Optional. An array of contents of the original source files.\n\n* `mappings`: A string of base64 VLQs which contain the actual mappings.\n\n* `file`: The generated filename this source map is associated with.\n\n#### SourceMapConsumer.prototype.originalPositionFor(generatedPosition)\n\nReturns the original source, line, and column information for the generated\nsource's line and column positions provided. The only argument is an object with\nthe following properties:\n\n* `line`: The line number in the generated source.\n\n* `column`: The column number in the generated source.\n\nand an object is returned with the following properties:\n\n* `source`: The original source file, or null if this information is not\n available.\n\n* `line`: The line number in the original source, or null if this information is\n not available.\n\n* `column`: The column number in the original source, or null or null if this\n information is not available.\n\n* `name`: The original identifier, or null if this information is not available.\n\n#### SourceMapConsumer.prototype.generatedPositionFor(originalPosition)\n\nReturns the generated line and column information for the original source,\nline, and column positions provided. The only argument is an object with\nthe following properties:\n\n* `source`: The filename of the original source.\n\n* `line`: The line number in the original source.\n\n* `column`: The column number in the original source.\n\nand an object is returned with the following properties:\n\n* `line`: The line number in the generated source, or null.\n\n* `column`: The column number in the generated source, or null.\n\n#### SourceMapConsumer.prototype.sourceContentFor(source)\n\nReturns the original source content for the source provided. The only\nargument is the URL of the original source file.\n\n#### SourceMapConsumer.prototype.eachMapping(callback, context, order)\n\nIterate over each mapping between an original source/line/column and a\ngenerated line/column in this source map.\n\n* `callback`: The function that is called with each mapping. Mappings have the\n form `{ source, generatedLine, generatedColumn, originalLine, originalColumn,\n name }`\n\n* `context`: Optional. If specified, this object will be the value of `this`\n every time that `callback` is called.\n\n* `order`: Either `SourceMapConsumer.GENERATED_ORDER` or\n `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to iterate over\n the mappings sorted by the generated file's line/column order or the\n original's source/line/column order, respectively. Defaults to\n `SourceMapConsumer.GENERATED_ORDER`.\n\n### SourceMapGenerator\n\nAn instance of the SourceMapGenerator represents a source map which is being\nbuilt incrementally.\n\n#### new SourceMapGenerator(startOfSourceMap)\n\nTo create a new one, you must pass an object with the following properties:\n\n* `file`: The filename of the generated source that this source map is\n associated with.\n\n* `sourceRoot`: An optional root for all relative URLs in this source map.\n\n#### SourceMapGenerator.fromSourceMap(sourceMapConsumer)\n\nCreates a new SourceMapGenerator based on a SourceMapConsumer\n\n* `sourceMapConsumer` The SourceMap.\n\n#### SourceMapGenerator.prototype.addMapping(mapping)\n\nAdd a single mapping from original source line and column to the generated\nsource's line and column for this source map being created. The mapping object\nshould have the following properties:\n\n* `generated`: An object with the generated line and column positions.\n\n* `original`: An object with the original line and column positions.\n\n* `source`: The original source file (relative to the sourceRoot).\n\n* `name`: An optional original token name for this mapping.\n\n#### SourceMapGenerator.prototype.setSourceContent(sourceFile, sourceContent)\n\nSet the source content for an original source file.\n\n* `sourceFile` the URL of the original source file.\n\n* `sourceContent` the content of the source file.\n\n#### SourceMapGenerator.prototype.applySourceMap(sourceMapConsumer[, sourceFile])\n\nApplies a SourceMap for a source file to the SourceMap.\nEach mapping to the supplied source file is rewritten using the\nsupplied SourceMap. Note: The resolution for the resulting mappings\nis the minimium of this map and the supplied map.\n\n* `sourceMapConsumer`: The SourceMap to be applied.\n\n* `sourceFile`: Optional. The filename of the source file.\n If omitted, sourceMapConsumer.file will be used.\n\n#### SourceMapGenerator.prototype.toString()\n\nRenders the source map being generated to a string.\n\n### SourceNode\n\nSourceNodes provide a way to abstract over interpolating and/or concatenating\nsnippets of generated JavaScript source code, while maintaining the line and\ncolumn information associated between those snippets and the original source\ncode. This is useful as the final intermediate representation a compiler might\nuse before outputting the generated JS and source map.\n\n#### new SourceNode(line, column, source[, chunk[, name]])\n\n* `line`: The original line number associated with this source node, or null if\n it isn't associated with an original line.\n\n* `column`: The original column number associated with this source node, or null\n if it isn't associated with an original column.\n\n* `source`: The original source's filename.\n\n* `chunk`: Optional. Is immediately passed to `SourceNode.prototype.add`, see\n below.\n\n* `name`: Optional. The original identifier.\n\n#### SourceNode.fromStringWithSourceMap(code, sourceMapConsumer)\n\nCreates a SourceNode from generated code and a SourceMapConsumer.\n\n* `code`: The generated code\n\n* `sourceMapConsumer` The SourceMap for the generated code\n\n#### SourceNode.prototype.add(chunk)\n\nAdd a chunk of generated JS to this source node.\n\n* `chunk`: A string snippet of generated JS code, another instance of\n `SourceNode`, or an array where each member is one of those things.\n\n#### SourceNode.prototype.prepend(chunk)\n\nPrepend a chunk of generated JS to this source node.\n\n* `chunk`: A string snippet of generated JS code, another instance of\n `SourceNode`, or an array where each member is one of those things.\n\n#### SourceNode.prototype.setSourceContent(sourceFile, sourceContent)\n\nSet the source content for a source file. This will be added to the\n`SourceMap` in the `sourcesContent` field.\n\n* `sourceFile`: The filename of the source file\n\n* `sourceContent`: The content of the source file\n\n#### SourceNode.prototype.walk(fn)\n\nWalk over the tree of JS snippets in this node and its children. The walking\nfunction is called once for each snippet of JS and is passed that snippet and\nthe its original associated source's line/column location.\n\n* `fn`: The traversal function.\n\n#### SourceNode.prototype.walkSourceContents(fn)\n\nWalk over the tree of SourceNodes. The walking function is called for each\nsource file content and is passed the filename and source content.\n\n* `fn`: The traversal function.\n\n#### SourceNode.prototype.join(sep)\n\nLike `Array.prototype.join` except for SourceNodes. Inserts the separator\nbetween each of this source node's children.\n\n* `sep`: The separator.\n\n#### SourceNode.prototype.replaceRight(pattern, replacement)\n\nCall `String.prototype.replace` on the very right-most source snippet. Useful\nfor trimming whitespace from the end of a source node, etc.\n\n* `pattern`: The pattern to replace.\n\n* `replacement`: The thing to replace the pattern with.\n\n#### SourceNode.prototype.toString()\n\nReturn the string representation of this source node. Walks over the tree and\nconcatenates all the various snippets together to one string.\n\n### SourceNode.prototype.toStringWithSourceMap(startOfSourceMap)\n\nReturns the string representation of this tree of source nodes, plus a\nSourceMapGenerator which contains all the mappings between the generated and\noriginal sources.\n\nThe arguments are the same as those to `new SourceMapGenerator`.\n\n## Tests\n\n[![Build Status](https://travis-ci.org/mozilla/source-map.png?branch=master)](https://travis-ci.org/mozilla/source-map)\n\nInstall NodeJS version 0.8.0 or greater, then run `node test/run-tests.js`.\n\nTo add new tests, create a new file named `test/test-.js`\nand export your test functions with names that start with \"test\", for example\n\n exports[\"test doing the foo bar\"] = function (assert, util) {\n ...\n };\n\nThe new test will be located automatically when you run the suite.\n\nThe `util` argument is the test utility module located at `test/source-map/util`.\n\nThe `assert` argument is a cut down version of node's assert module. You have\naccess to the following assertion functions:\n\n* `doesNotThrow`\n\n* `equal`\n\n* `ok`\n\n* `strictEqual`\n\n* `throws`\n\n(The reason for the restricted set of test functions is because we need the\ntests to run inside Firefox's test suite as well and so the assert module is\nshimmed in that environment. See `build/assert-shim.js`.)\n\n[format]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit\n[feature]: https://wiki.mozilla.org/DevTools/Features/SourceMap\n[Dryice]: https://github.com/mozilla/dryice\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/mozilla/source-map/issues" + }, + "_id": "source-map@0.1.31", + "dist": { + "shasum": "11aa197fd21ff05341ed68496292befec6c1ef23" + }, + "_from": "source-map@~0.1.7", + "_resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.31.tgz" +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/run-tests.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/run-tests.js new file mode 100755 index 0000000..626c53f --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/run-tests.js @@ -0,0 +1,71 @@ +#!/usr/bin/env node +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +var assert = require('assert'); +var fs = require('fs'); +var path = require('path'); +var util = require('./source-map/util'); + +function run(tests) { + var failures = []; + var total = 0; + var passed = 0; + + for (var i = 0; i < tests.length; i++) { + for (var k in tests[i].testCase) { + if (/^test/.test(k)) { + total++; + try { + tests[i].testCase[k](assert, util); + passed++; + } + catch (e) { + console.log('FAILED ' + tests[i].name + ': ' + k + '!'); + console.log(e.stack); + } + } + } + } + + console.log(""); + console.log(passed + ' / ' + total + ' tests passed.'); + console.log(""); + + failures.forEach(function (f) { + }); + + return failures.length; +} + +var code; + +process.stdout.on('close', function () { + process.exit(code); +}); + +function isTestFile(f) { + var testToRun = process.argv[2]; + return testToRun + ? path.basename(testToRun) === f + : /^test\-.*?\.js/.test(f); +} + +function toModule(f) { + return './source-map/' + f.replace(/\.js$/, ''); +} + +var requires = fs.readdirSync(path.join(__dirname, 'source-map')) + .filter(isTestFile) + .map(toModule); + +code = run(requires.map(require).map(function (mod, i) { + return { + name: requires[i], + testCase: mod + }; +})); +process.exit(code); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-api.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-api.js new file mode 100644 index 0000000..3801233 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-api.js @@ -0,0 +1,26 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2012 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var sourceMap; + try { + sourceMap = require('../../lib/source-map'); + } catch (e) { + sourceMap = {}; + Components.utils.import('resource:///modules/devtools/SourceMap.jsm', sourceMap); + } + + exports['test that the api is properly exposed in the top level'] = function (assert, util) { + assert.equal(typeof sourceMap.SourceMapGenerator, "function"); + assert.equal(typeof sourceMap.SourceMapConsumer, "function"); + assert.equal(typeof sourceMap.SourceNode, "function"); + }; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-array-set.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-array-set.js new file mode 100644 index 0000000..b5797ed --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-array-set.js @@ -0,0 +1,104 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var ArraySet = require('../../lib/source-map/array-set').ArraySet; + + function makeTestSet() { + var set = new ArraySet(); + for (var i = 0; i < 100; i++) { + set.add(String(i)); + } + return set; + } + + exports['test .has() membership'] = function (assert, util) { + var set = makeTestSet(); + for (var i = 0; i < 100; i++) { + assert.ok(set.has(String(i))); + } + }; + + exports['test .indexOf() elements'] = function (assert, util) { + var set = makeTestSet(); + for (var i = 0; i < 100; i++) { + assert.strictEqual(set.indexOf(String(i)), i); + } + }; + + exports['test .at() indexing'] = function (assert, util) { + var set = makeTestSet(); + for (var i = 0; i < 100; i++) { + assert.strictEqual(set.at(i), String(i)); + } + }; + + exports['test creating from an array'] = function (assert, util) { + var set = ArraySet.fromArray(['foo', 'bar', 'baz', 'quux', 'hasOwnProperty']); + + assert.ok(set.has('foo')); + assert.ok(set.has('bar')); + assert.ok(set.has('baz')); + assert.ok(set.has('quux')); + assert.ok(set.has('hasOwnProperty')); + + assert.strictEqual(set.indexOf('foo'), 0); + assert.strictEqual(set.indexOf('bar'), 1); + assert.strictEqual(set.indexOf('baz'), 2); + assert.strictEqual(set.indexOf('quux'), 3); + + assert.strictEqual(set.at(0), 'foo'); + assert.strictEqual(set.at(1), 'bar'); + assert.strictEqual(set.at(2), 'baz'); + assert.strictEqual(set.at(3), 'quux'); + }; + + exports['test that you can add __proto__; see github issue #30'] = function (assert, util) { + var set = new ArraySet(); + set.add('__proto__'); + assert.ok(set.has('__proto__')); + assert.strictEqual(set.at(0), '__proto__'); + assert.strictEqual(set.indexOf('__proto__'), 0); + }; + + exports['test .fromArray() with duplicates'] = function (assert, util) { + var set = ArraySet.fromArray(['foo', 'foo']); + assert.ok(set.has('foo')); + assert.strictEqual(set.at(0), 'foo'); + assert.strictEqual(set.indexOf('foo'), 0); + assert.strictEqual(set.toArray().length, 1); + + set = ArraySet.fromArray(['foo', 'foo'], true); + assert.ok(set.has('foo')); + assert.strictEqual(set.at(0), 'foo'); + assert.strictEqual(set.at(1), 'foo'); + assert.strictEqual(set.indexOf('foo'), 0); + assert.strictEqual(set.toArray().length, 2); + }; + + exports['test .add() with duplicates'] = function (assert, util) { + var set = new ArraySet(); + set.add('foo'); + + set.add('foo'); + assert.ok(set.has('foo')); + assert.strictEqual(set.at(0), 'foo'); + assert.strictEqual(set.indexOf('foo'), 0); + assert.strictEqual(set.toArray().length, 1); + + set.add('foo', true); + assert.ok(set.has('foo')); + assert.strictEqual(set.at(0), 'foo'); + assert.strictEqual(set.at(1), 'foo'); + assert.strictEqual(set.indexOf('foo'), 0); + assert.strictEqual(set.toArray().length, 2); + }; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-base64-vlq.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-base64-vlq.js new file mode 100644 index 0000000..653a874 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-base64-vlq.js @@ -0,0 +1,24 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var base64VLQ = require('../../lib/source-map/base64-vlq'); + + exports['test normal encoding and decoding'] = function (assert, util) { + var result; + for (var i = -255; i < 256; i++) { + result = base64VLQ.decode(base64VLQ.encode(i)); + assert.ok(result); + assert.equal(result.value, i); + assert.equal(result.rest, ""); + } + }; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-base64.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-base64.js new file mode 100644 index 0000000..ff3a244 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-base64.js @@ -0,0 +1,35 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var base64 = require('../../lib/source-map/base64'); + + exports['test out of range encoding'] = function (assert, util) { + assert.throws(function () { + base64.encode(-1); + }); + assert.throws(function () { + base64.encode(64); + }); + }; + + exports['test out of range decoding'] = function (assert, util) { + assert.throws(function () { + base64.decode('='); + }); + }; + + exports['test normal encoding and decoding'] = function (assert, util) { + for (var i = 0; i < 64; i++) { + assert.equal(base64.decode(base64.encode(i)), i); + } + }; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-binary-search.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-binary-search.js new file mode 100644 index 0000000..ee30683 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-binary-search.js @@ -0,0 +1,54 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var binarySearch = require('../../lib/source-map/binary-search'); + + function numberCompare(a, b) { + return a - b; + } + + exports['test too high'] = function (assert, util) { + var needle = 30; + var haystack = [2,4,6,8,10,12,14,16,18,20]; + + assert.doesNotThrow(function () { + binarySearch.search(needle, haystack, numberCompare); + }); + + assert.equal(binarySearch.search(needle, haystack, numberCompare), 20); + }; + + exports['test too low'] = function (assert, util) { + var needle = 1; + var haystack = [2,4,6,8,10,12,14,16,18,20]; + + assert.doesNotThrow(function () { + binarySearch.search(needle, haystack, numberCompare); + }); + + assert.equal(binarySearch.search(needle, haystack, numberCompare), null); + }; + + exports['test exact search'] = function (assert, util) { + var needle = 4; + var haystack = [2,4,6,8,10,12,14,16,18,20]; + + assert.equal(binarySearch.search(needle, haystack, numberCompare), 4); + }; + + exports['test fuzzy search'] = function (assert, util) { + var needle = 19; + var haystack = [2,4,6,8,10,12,14,16,18,20]; + + assert.equal(binarySearch.search(needle, haystack, numberCompare), 18); + }; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-dog-fooding.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-dog-fooding.js new file mode 100644 index 0000000..d831b92 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-dog-fooding.js @@ -0,0 +1,72 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var SourceMapConsumer = require('../../lib/source-map/source-map-consumer').SourceMapConsumer; + var SourceMapGenerator = require('../../lib/source-map/source-map-generator').SourceMapGenerator; + + exports['test eating our own dog food'] = function (assert, util) { + var smg = new SourceMapGenerator({ + file: 'testing.js', + sourceRoot: '/wu/tang' + }); + + smg.addMapping({ + source: 'gza.coffee', + original: { line: 1, column: 0 }, + generated: { line: 2, column: 2 } + }); + + smg.addMapping({ + source: 'gza.coffee', + original: { line: 2, column: 0 }, + generated: { line: 3, column: 2 } + }); + + smg.addMapping({ + source: 'gza.coffee', + original: { line: 3, column: 0 }, + generated: { line: 4, column: 2 } + }); + + smg.addMapping({ + source: 'gza.coffee', + original: { line: 4, column: 0 }, + generated: { line: 5, column: 2 } + }); + + var smc = new SourceMapConsumer(smg.toString()); + + // Exact + util.assertMapping(2, 2, '/wu/tang/gza.coffee', 1, 0, null, smc, assert); + util.assertMapping(3, 2, '/wu/tang/gza.coffee', 2, 0, null, smc, assert); + util.assertMapping(4, 2, '/wu/tang/gza.coffee', 3, 0, null, smc, assert); + util.assertMapping(5, 2, '/wu/tang/gza.coffee', 4, 0, null, smc, assert); + + // Fuzzy + + // Original to generated + util.assertMapping(2, 0, null, null, null, null, smc, assert, true); + util.assertMapping(2, 9, '/wu/tang/gza.coffee', 1, 0, null, smc, assert, true); + util.assertMapping(3, 0, '/wu/tang/gza.coffee', 1, 0, null, smc, assert, true); + util.assertMapping(3, 9, '/wu/tang/gza.coffee', 2, 0, null, smc, assert, true); + util.assertMapping(4, 0, '/wu/tang/gza.coffee', 2, 0, null, smc, assert, true); + util.assertMapping(4, 9, '/wu/tang/gza.coffee', 3, 0, null, smc, assert, true); + util.assertMapping(5, 0, '/wu/tang/gza.coffee', 3, 0, null, smc, assert, true); + util.assertMapping(5, 9, '/wu/tang/gza.coffee', 4, 0, null, smc, assert, true); + + // Generated to original + util.assertMapping(2, 2, '/wu/tang/gza.coffee', 1, 1, null, smc, assert, null, true); + util.assertMapping(3, 2, '/wu/tang/gza.coffee', 2, 3, null, smc, assert, null, true); + util.assertMapping(4, 2, '/wu/tang/gza.coffee', 3, 6, null, smc, assert, null, true); + util.assertMapping(5, 2, '/wu/tang/gza.coffee', 4, 9, null, smc, assert, null, true); + }; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-map-consumer.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-map-consumer.js new file mode 100644 index 0000000..f2c65a7 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-map-consumer.js @@ -0,0 +1,451 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var SourceMapConsumer = require('../../lib/source-map/source-map-consumer').SourceMapConsumer; + var SourceMapGenerator = require('../../lib/source-map/source-map-generator').SourceMapGenerator; + + exports['test that we can instantiate with a string or an objects'] = function (assert, util) { + assert.doesNotThrow(function () { + var map = new SourceMapConsumer(util.testMap); + }); + assert.doesNotThrow(function () { + var map = new SourceMapConsumer(JSON.stringify(util.testMap)); + }); + }; + + exports['test that the `sources` field has the original sources'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMap); + var sources = map.sources; + + assert.equal(sources[0], '/the/root/one.js'); + assert.equal(sources[1], '/the/root/two.js'); + assert.equal(sources.length, 2); + }; + + exports['test that the source root is reflected in a mapping\'s source field'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMap); + var mapping; + + mapping = map.originalPositionFor({ + line: 2, + column: 1 + }); + assert.equal(mapping.source, '/the/root/two.js'); + + mapping = map.originalPositionFor({ + line: 1, + column: 1 + }); + assert.equal(mapping.source, '/the/root/one.js'); + }; + + exports['test mapping tokens back exactly'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMap); + + util.assertMapping(1, 1, '/the/root/one.js', 1, 1, null, map, assert); + util.assertMapping(1, 5, '/the/root/one.js', 1, 5, null, map, assert); + util.assertMapping(1, 9, '/the/root/one.js', 1, 11, null, map, assert); + util.assertMapping(1, 18, '/the/root/one.js', 1, 21, 'bar', map, assert); + util.assertMapping(1, 21, '/the/root/one.js', 2, 3, null, map, assert); + util.assertMapping(1, 28, '/the/root/one.js', 2, 10, 'baz', map, assert); + util.assertMapping(1, 32, '/the/root/one.js', 2, 14, 'bar', map, assert); + + util.assertMapping(2, 1, '/the/root/two.js', 1, 1, null, map, assert); + util.assertMapping(2, 5, '/the/root/two.js', 1, 5, null, map, assert); + util.assertMapping(2, 9, '/the/root/two.js', 1, 11, null, map, assert); + util.assertMapping(2, 18, '/the/root/two.js', 1, 21, 'n', map, assert); + util.assertMapping(2, 21, '/the/root/two.js', 2, 3, null, map, assert); + util.assertMapping(2, 28, '/the/root/two.js', 2, 10, 'n', map, assert); + }; + + exports['test mapping tokens fuzzy'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMap); + + // Finding original positions + util.assertMapping(1, 20, '/the/root/one.js', 1, 21, 'bar', map, assert, true); + util.assertMapping(1, 30, '/the/root/one.js', 2, 10, 'baz', map, assert, true); + util.assertMapping(2, 12, '/the/root/two.js', 1, 11, null, map, assert, true); + + // Finding generated positions + util.assertMapping(1, 18, '/the/root/one.js', 1, 22, 'bar', map, assert, null, true); + util.assertMapping(1, 28, '/the/root/one.js', 2, 13, 'baz', map, assert, null, true); + util.assertMapping(2, 9, '/the/root/two.js', 1, 16, null, map, assert, null, true); + }; + + exports['test creating source map consumers with )]}\' prefix'] = function (assert, util) { + assert.doesNotThrow(function () { + var map = new SourceMapConsumer(")]}'" + JSON.stringify(util.testMap)); + }); + }; + + exports['test eachMapping'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMap); + var previousLine = -Infinity; + var previousColumn = -Infinity; + map.eachMapping(function (mapping) { + assert.ok(mapping.generatedLine >= previousLine); + + if (mapping.source) { + assert.equal(mapping.source.indexOf(util.testMap.sourceRoot), 0); + } + + if (mapping.generatedLine === previousLine) { + assert.ok(mapping.generatedColumn >= previousColumn); + previousColumn = mapping.generatedColumn; + } + else { + previousLine = mapping.generatedLine; + previousColumn = -Infinity; + } + }); + }; + + exports['test iterating over mappings in a different order'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMap); + var previousLine = -Infinity; + var previousColumn = -Infinity; + var previousSource = ""; + map.eachMapping(function (mapping) { + assert.ok(mapping.source >= previousSource); + + if (mapping.source === previousSource) { + assert.ok(mapping.originalLine >= previousLine); + + if (mapping.originalLine === previousLine) { + assert.ok(mapping.originalColumn >= previousColumn); + previousColumn = mapping.originalColumn; + } + else { + previousLine = mapping.originalLine; + previousColumn = -Infinity; + } + } + else { + previousSource = mapping.source; + previousLine = -Infinity; + previousColumn = -Infinity; + } + }, null, SourceMapConsumer.ORIGINAL_ORDER); + }; + + exports['test that we can set the context for `this` in eachMapping'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMap); + var context = {}; + map.eachMapping(function () { + assert.equal(this, context); + }, context); + }; + + exports['test that the `sourcesContent` field has the original sources'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMapWithSourcesContent); + var sourcesContent = map.sourcesContent; + + assert.equal(sourcesContent[0], ' ONE.foo = function (bar) {\n return baz(bar);\n };'); + assert.equal(sourcesContent[1], ' TWO.inc = function (n) {\n return n + 1;\n };'); + assert.equal(sourcesContent.length, 2); + }; + + exports['test that we can get the original sources for the sources'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMapWithSourcesContent); + var sources = map.sources; + + assert.equal(map.sourceContentFor(sources[0]), ' ONE.foo = function (bar) {\n return baz(bar);\n };'); + assert.equal(map.sourceContentFor(sources[1]), ' TWO.inc = function (n) {\n return n + 1;\n };'); + assert.equal(map.sourceContentFor("one.js"), ' ONE.foo = function (bar) {\n return baz(bar);\n };'); + assert.equal(map.sourceContentFor("two.js"), ' TWO.inc = function (n) {\n return n + 1;\n };'); + assert.throws(function () { + map.sourceContentFor(""); + }, Error); + assert.throws(function () { + map.sourceContentFor("/the/root/three.js"); + }, Error); + assert.throws(function () { + map.sourceContentFor("three.js"); + }, Error); + }; + + exports['test sourceRoot + generatedPositionFor'] = function (assert, util) { + var map = new SourceMapGenerator({ + sourceRoot: 'foo/bar', + file: 'baz.js' + }); + map.addMapping({ + original: { line: 1, column: 1 }, + generated: { line: 2, column: 2 }, + source: 'bang.coffee' + }); + map.addMapping({ + original: { line: 5, column: 5 }, + generated: { line: 6, column: 6 }, + source: 'bang.coffee' + }); + map = new SourceMapConsumer(map.toString()); + + // Should handle without sourceRoot. + var pos = map.generatedPositionFor({ + line: 1, + column: 1, + source: 'bang.coffee' + }); + + assert.equal(pos.line, 2); + assert.equal(pos.column, 2); + + // Should handle with sourceRoot. + var pos = map.generatedPositionFor({ + line: 1, + column: 1, + source: 'foo/bar/bang.coffee' + }); + + assert.equal(pos.line, 2); + assert.equal(pos.column, 2); + }; + + exports['test sourceRoot + originalPositionFor'] = function (assert, util) { + var map = new SourceMapGenerator({ + sourceRoot: 'foo/bar', + file: 'baz.js' + }); + map.addMapping({ + original: { line: 1, column: 1 }, + generated: { line: 2, column: 2 }, + source: 'bang.coffee' + }); + map = new SourceMapConsumer(map.toString()); + + var pos = map.originalPositionFor({ + line: 2, + column: 2, + }); + + // Should always have the prepended source root + assert.equal(pos.source, 'foo/bar/bang.coffee'); + assert.equal(pos.line, 1); + assert.equal(pos.column, 1); + }; + + exports['test github issue #56'] = function (assert, util) { + var map = new SourceMapGenerator({ + sourceRoot: 'http://', + file: 'www.example.com/foo.js' + }); + map.addMapping({ + original: { line: 1, column: 1 }, + generated: { line: 2, column: 2 }, + source: 'www.example.com/original.js' + }); + map = new SourceMapConsumer(map.toString()); + + var sources = map.sources; + assert.equal(sources.length, 1); + assert.equal(sources[0], 'http://www.example.com/original.js'); + }; + + exports['test github issue #43'] = function (assert, util) { + var map = new SourceMapGenerator({ + sourceRoot: 'http://example.com', + file: 'foo.js' + }); + map.addMapping({ + original: { line: 1, column: 1 }, + generated: { line: 2, column: 2 }, + source: 'http://cdn.example.com/original.js' + }); + map = new SourceMapConsumer(map.toString()); + + var sources = map.sources; + assert.equal(sources.length, 1, + 'Should only be one source.'); + assert.equal(sources[0], 'http://cdn.example.com/original.js', + 'Should not be joined with the sourceRoot.'); + }; + + exports['test absolute path, but same host sources'] = function (assert, util) { + var map = new SourceMapGenerator({ + sourceRoot: 'http://example.com/foo/bar', + file: 'foo.js' + }); + map.addMapping({ + original: { line: 1, column: 1 }, + generated: { line: 2, column: 2 }, + source: '/original.js' + }); + map = new SourceMapConsumer(map.toString()); + + var sources = map.sources; + assert.equal(sources.length, 1, + 'Should only be one source.'); + assert.equal(sources[0], 'http://example.com/original.js', + 'Source should be relative the host of the source root.'); + }; + + exports['test github issue #64'] = function (assert, util) { + var map = new SourceMapConsumer({ + "version": 3, + "file": "foo.js", + "sourceRoot": "http://example.com/", + "sources": ["/a"], + "names": [], + "mappings": "AACA", + "sourcesContent": ["foo"] + }); + + assert.equal(map.sourceContentFor("a"), "foo"); + assert.equal(map.sourceContentFor("/a"), "foo"); + }; + + exports['test bug 885597'] = function (assert, util) { + var map = new SourceMapConsumer({ + "version": 3, + "file": "foo.js", + "sourceRoot": "file:///Users/AlGore/Invented/The/Internet/", + "sources": ["/a"], + "names": [], + "mappings": "AACA", + "sourcesContent": ["foo"] + }); + + var s = map.sources[0]; + assert.equal(map.sourceContentFor(s), "foo"); + }; + + exports['test github issue #72, duplicate sources'] = function (assert, util) { + var map = new SourceMapConsumer({ + "version": 3, + "file": "foo.js", + "sources": ["source1.js", "source1.js", "source3.js"], + "names": [], + "mappings": ";EAAC;;IAEE;;MEEE", + "sourceRoot": "http://example.com" + }); + + var pos = map.originalPositionFor({ + line: 2, + column: 2 + }); + assert.equal(pos.source, 'http://example.com/source1.js'); + assert.equal(pos.line, 1); + assert.equal(pos.column, 1); + + var pos = map.originalPositionFor({ + line: 4, + column: 4 + }); + assert.equal(pos.source, 'http://example.com/source1.js'); + assert.equal(pos.line, 3); + assert.equal(pos.column, 3); + + var pos = map.originalPositionFor({ + line: 6, + column: 6 + }); + assert.equal(pos.source, 'http://example.com/source3.js'); + assert.equal(pos.line, 5); + assert.equal(pos.column, 5); + }; + + exports['test github issue #72, duplicate names'] = function (assert, util) { + var map = new SourceMapConsumer({ + "version": 3, + "file": "foo.js", + "sources": ["source.js"], + "names": ["name1", "name1", "name3"], + "mappings": ";EAACA;;IAEEA;;MAEEE", + "sourceRoot": "http://example.com" + }); + + var pos = map.originalPositionFor({ + line: 2, + column: 2 + }); + assert.equal(pos.name, 'name1'); + assert.equal(pos.line, 1); + assert.equal(pos.column, 1); + + var pos = map.originalPositionFor({ + line: 4, + column: 4 + }); + assert.equal(pos.name, 'name1'); + assert.equal(pos.line, 3); + assert.equal(pos.column, 3); + + var pos = map.originalPositionFor({ + line: 6, + column: 6 + }); + assert.equal(pos.name, 'name3'); + assert.equal(pos.line, 5); + assert.equal(pos.column, 5); + }; + + exports['test SourceMapConsumer.fromSourceMap'] = function (assert, util) { + var smg = new SourceMapGenerator({ + sourceRoot: 'http://example.com/', + file: 'foo.js' + }); + smg.addMapping({ + original: { line: 1, column: 1 }, + generated: { line: 2, column: 2 }, + source: 'bar.js' + }); + smg.addMapping({ + original: { line: 2, column: 2 }, + generated: { line: 4, column: 4 }, + source: 'baz.js', + name: 'dirtMcGirt' + }); + smg.setSourceContent('baz.js', 'baz.js content'); + + var smc = SourceMapConsumer.fromSourceMap(smg); + assert.equal(smc.file, 'foo.js'); + assert.equal(smc.sourceRoot, 'http://example.com/'); + assert.equal(smc.sources.length, 2); + assert.equal(smc.sources[0], 'http://example.com/bar.js'); + assert.equal(smc.sources[1], 'http://example.com/baz.js'); + assert.equal(smc.sourceContentFor('baz.js'), 'baz.js content'); + + var pos = smc.originalPositionFor({ + line: 2, + column: 2 + }); + assert.equal(pos.line, 1); + assert.equal(pos.column, 1); + assert.equal(pos.source, 'http://example.com/bar.js'); + assert.equal(pos.name, null); + + pos = smc.generatedPositionFor({ + line: 1, + column: 1, + source: 'http://example.com/bar.js' + }); + assert.equal(pos.line, 2); + assert.equal(pos.column, 2); + + pos = smc.originalPositionFor({ + line: 4, + column: 4 + }); + assert.equal(pos.line, 2); + assert.equal(pos.column, 2); + assert.equal(pos.source, 'http://example.com/baz.js'); + assert.equal(pos.name, 'dirtMcGirt'); + + pos = smc.generatedPositionFor({ + line: 2, + column: 2, + source: 'http://example.com/baz.js' + }); + assert.equal(pos.line, 4); + assert.equal(pos.column, 4); + }; +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-map-generator.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-map-generator.js new file mode 100644 index 0000000..ba292f5 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-map-generator.js @@ -0,0 +1,417 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var SourceMapGenerator = require('../../lib/source-map/source-map-generator').SourceMapGenerator; + var SourceMapConsumer = require('../../lib/source-map/source-map-consumer').SourceMapConsumer; + var SourceNode = require('../../lib/source-map/source-node').SourceNode; + var util = require('./util'); + + exports['test some simple stuff'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'foo.js', + sourceRoot: '.' + }); + assert.ok(true); + }; + + exports['test JSON serialization'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'foo.js', + sourceRoot: '.' + }); + assert.equal(map.toString(), JSON.stringify(map)); + }; + + exports['test adding mappings (case 1)'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'generated-foo.js', + sourceRoot: '.' + }); + + assert.doesNotThrow(function () { + map.addMapping({ + generated: { line: 1, column: 1 } + }); + }); + }; + + exports['test adding mappings (case 2)'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'generated-foo.js', + sourceRoot: '.' + }); + + assert.doesNotThrow(function () { + map.addMapping({ + generated: { line: 1, column: 1 }, + source: 'bar.js', + original: { line: 1, column: 1 } + }); + }); + }; + + exports['test adding mappings (case 3)'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'generated-foo.js', + sourceRoot: '.' + }); + + assert.doesNotThrow(function () { + map.addMapping({ + generated: { line: 1, column: 1 }, + source: 'bar.js', + original: { line: 1, column: 1 }, + name: 'someToken' + }); + }); + }; + + exports['test adding mappings (invalid)'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'generated-foo.js', + sourceRoot: '.' + }); + + // Not enough info. + assert.throws(function () { + map.addMapping({}); + }); + + // Original file position, but no source. + assert.throws(function () { + map.addMapping({ + generated: { line: 1, column: 1 }, + original: { line: 1, column: 1 } + }); + }); + }; + + exports['test that the correct mappings are being generated'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'min.js', + sourceRoot: '/the/root' + }); + + map.addMapping({ + generated: { line: 1, column: 1 }, + original: { line: 1, column: 1 }, + source: 'one.js' + }); + map.addMapping({ + generated: { line: 1, column: 5 }, + original: { line: 1, column: 5 }, + source: 'one.js' + }); + map.addMapping({ + generated: { line: 1, column: 9 }, + original: { line: 1, column: 11 }, + source: 'one.js' + }); + map.addMapping({ + generated: { line: 1, column: 18 }, + original: { line: 1, column: 21 }, + source: 'one.js', + name: 'bar' + }); + map.addMapping({ + generated: { line: 1, column: 21 }, + original: { line: 2, column: 3 }, + source: 'one.js' + }); + map.addMapping({ + generated: { line: 1, column: 28 }, + original: { line: 2, column: 10 }, + source: 'one.js', + name: 'baz' + }); + map.addMapping({ + generated: { line: 1, column: 32 }, + original: { line: 2, column: 14 }, + source: 'one.js', + name: 'bar' + }); + + map.addMapping({ + generated: { line: 2, column: 1 }, + original: { line: 1, column: 1 }, + source: 'two.js' + }); + map.addMapping({ + generated: { line: 2, column: 5 }, + original: { line: 1, column: 5 }, + source: 'two.js' + }); + map.addMapping({ + generated: { line: 2, column: 9 }, + original: { line: 1, column: 11 }, + source: 'two.js' + }); + map.addMapping({ + generated: { line: 2, column: 18 }, + original: { line: 1, column: 21 }, + source: 'two.js', + name: 'n' + }); + map.addMapping({ + generated: { line: 2, column: 21 }, + original: { line: 2, column: 3 }, + source: 'two.js' + }); + map.addMapping({ + generated: { line: 2, column: 28 }, + original: { line: 2, column: 10 }, + source: 'two.js', + name: 'n' + }); + + map = JSON.parse(map.toString()); + + util.assertEqualMaps(assert, map, util.testMap); + }; + + exports['test that source content can be set'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'min.js', + sourceRoot: '/the/root' + }); + map.addMapping({ + generated: { line: 1, column: 1 }, + original: { line: 1, column: 1 }, + source: 'one.js' + }); + map.addMapping({ + generated: { line: 2, column: 1 }, + original: { line: 1, column: 1 }, + source: 'two.js' + }); + map.setSourceContent('one.js', 'one file content'); + + map = JSON.parse(map.toString()); + assert.equal(map.sources[0], 'one.js'); + assert.equal(map.sources[1], 'two.js'); + assert.equal(map.sourcesContent[0], 'one file content'); + assert.equal(map.sourcesContent[1], null); + }; + + exports['test .fromSourceMap'] = function (assert, util) { + var map = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(util.testMap)); + util.assertEqualMaps(assert, map.toJSON(), util.testMap); + }; + + exports['test .fromSourceMap with sourcesContent'] = function (assert, util) { + var map = SourceMapGenerator.fromSourceMap( + new SourceMapConsumer(util.testMapWithSourcesContent)); + util.assertEqualMaps(assert, map.toJSON(), util.testMapWithSourcesContent); + }; + + exports['test applySourceMap'] = function (assert, util) { + var node = new SourceNode(null, null, null, [ + new SourceNode(2, 0, 'fileX', 'lineX2\n'), + 'genA1\n', + new SourceNode(2, 0, 'fileY', 'lineY2\n'), + 'genA2\n', + new SourceNode(1, 0, 'fileX', 'lineX1\n'), + 'genA3\n', + new SourceNode(1, 0, 'fileY', 'lineY1\n') + ]); + var mapStep1 = node.toStringWithSourceMap({ + file: 'fileA' + }).map; + mapStep1.setSourceContent('fileX', 'lineX1\nlineX2\n'); + mapStep1 = mapStep1.toJSON(); + + node = new SourceNode(null, null, null, [ + 'gen1\n', + new SourceNode(1, 0, 'fileA', 'lineA1\n'), + new SourceNode(2, 0, 'fileA', 'lineA2\n'), + new SourceNode(3, 0, 'fileA', 'lineA3\n'), + new SourceNode(4, 0, 'fileA', 'lineA4\n'), + new SourceNode(1, 0, 'fileB', 'lineB1\n'), + new SourceNode(2, 0, 'fileB', 'lineB2\n'), + 'gen2\n' + ]); + var mapStep2 = node.toStringWithSourceMap({ + file: 'fileGen' + }).map; + mapStep2.setSourceContent('fileB', 'lineB1\nlineB2\n'); + mapStep2 = mapStep2.toJSON(); + + node = new SourceNode(null, null, null, [ + 'gen1\n', + new SourceNode(2, 0, 'fileX', 'lineA1\n'), + new SourceNode(2, 0, 'fileA', 'lineA2\n'), + new SourceNode(2, 0, 'fileY', 'lineA3\n'), + new SourceNode(4, 0, 'fileA', 'lineA4\n'), + new SourceNode(1, 0, 'fileB', 'lineB1\n'), + new SourceNode(2, 0, 'fileB', 'lineB2\n'), + 'gen2\n' + ]); + var expectedMap = node.toStringWithSourceMap({ + file: 'fileGen' + }).map; + expectedMap.setSourceContent('fileX', 'lineX1\nlineX2\n'); + expectedMap.setSourceContent('fileB', 'lineB1\nlineB2\n'); + expectedMap = expectedMap.toJSON(); + + // apply source map "mapStep1" to "mapStep2" + var generator = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(mapStep2)); + generator.applySourceMap(new SourceMapConsumer(mapStep1)); + var actualMap = generator.toJSON(); + + util.assertEqualMaps(assert, actualMap, expectedMap); + }; + + exports['test sorting with duplicate generated mappings'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'test.js' + }); + map.addMapping({ + generated: { line: 3, column: 0 }, + original: { line: 2, column: 0 }, + source: 'a.js' + }); + map.addMapping({ + generated: { line: 2, column: 0 } + }); + map.addMapping({ + generated: { line: 2, column: 0 } + }); + map.addMapping({ + generated: { line: 1, column: 0 }, + original: { line: 1, column: 0 }, + source: 'a.js' + }); + + util.assertEqualMaps(assert, map.toJSON(), { + version: 3, + file: 'test.js', + sources: ['a.js'], + names: [], + mappings: 'AAAA;A;AACA' + }); + }; + + exports['test ignore duplicate mappings.'] = function (assert, util) { + var init = { file: 'min.js', sourceRoot: '/the/root' }; + var map1, map2; + + // null original source location + var nullMapping1 = { + generated: { line: 1, column: 0 } + }; + var nullMapping2 = { + generated: { line: 2, column: 2 } + }; + + map1 = new SourceMapGenerator(init); + map2 = new SourceMapGenerator(init); + + map1.addMapping(nullMapping1); + map1.addMapping(nullMapping1); + + map2.addMapping(nullMapping1); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + + map1.addMapping(nullMapping2); + map1.addMapping(nullMapping1); + + map2.addMapping(nullMapping2); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + + // original source location + var srcMapping1 = { + generated: { line: 1, column: 0 }, + original: { line: 11, column: 0 }, + source: 'srcMapping1.js' + }; + var srcMapping2 = { + generated: { line: 2, column: 2 }, + original: { line: 11, column: 0 }, + source: 'srcMapping2.js' + }; + + map1 = new SourceMapGenerator(init); + map2 = new SourceMapGenerator(init); + + map1.addMapping(srcMapping1); + map1.addMapping(srcMapping1); + + map2.addMapping(srcMapping1); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + + map1.addMapping(srcMapping2); + map1.addMapping(srcMapping1); + + map2.addMapping(srcMapping2); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + + // full original source and name information + var fullMapping1 = { + generated: { line: 1, column: 0 }, + original: { line: 11, column: 0 }, + source: 'fullMapping1.js', + name: 'fullMapping1' + }; + var fullMapping2 = { + generated: { line: 2, column: 2 }, + original: { line: 11, column: 0 }, + source: 'fullMapping2.js', + name: 'fullMapping2' + }; + + map1 = new SourceMapGenerator(init); + map2 = new SourceMapGenerator(init); + + map1.addMapping(fullMapping1); + map1.addMapping(fullMapping1); + + map2.addMapping(fullMapping1); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + + map1.addMapping(fullMapping2); + map1.addMapping(fullMapping1); + + map2.addMapping(fullMapping2); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + }; + + exports['test github issue #72, check for duplicate names or sources'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'test.js' + }); + map.addMapping({ + generated: { line: 1, column: 1 }, + original: { line: 2, column: 2 }, + source: 'a.js', + name: 'foo' + }); + map.addMapping({ + generated: { line: 3, column: 3 }, + original: { line: 4, column: 4 }, + source: 'a.js', + name: 'foo' + }); + util.assertEqualMaps(assert, map.toJSON(), { + version: 3, + file: 'test.js', + sources: ['a.js'], + names: ['foo'], + mappings: 'CACEA;;GAEEA' + }); + }; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-node.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-node.js new file mode 100644 index 0000000..6e0eca8 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-node.js @@ -0,0 +1,365 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var SourceMapGenerator = require('../../lib/source-map/source-map-generator').SourceMapGenerator; + var SourceMapConsumer = require('../../lib/source-map/source-map-consumer').SourceMapConsumer; + var SourceNode = require('../../lib/source-map/source-node').SourceNode; + + exports['test .add()'] = function (assert, util) { + var node = new SourceNode(null, null, null); + + // Adding a string works. + node.add('function noop() {}'); + + // Adding another source node works. + node.add(new SourceNode(null, null, null)); + + // Adding an array works. + node.add(['function foo() {', + new SourceNode(null, null, null, + 'return 10;'), + '}']); + + // Adding other stuff doesn't. + assert.throws(function () { + node.add({}); + }); + assert.throws(function () { + node.add(function () {}); + }); + }; + + exports['test .prepend()'] = function (assert, util) { + var node = new SourceNode(null, null, null); + + // Prepending a string works. + node.prepend('function noop() {}'); + assert.equal(node.children[0], 'function noop() {}'); + assert.equal(node.children.length, 1); + + // Prepending another source node works. + node.prepend(new SourceNode(null, null, null)); + assert.equal(node.children[0], ''); + assert.equal(node.children[1], 'function noop() {}'); + assert.equal(node.children.length, 2); + + // Prepending an array works. + node.prepend(['function foo() {', + new SourceNode(null, null, null, + 'return 10;'), + '}']); + assert.equal(node.children[0], 'function foo() {'); + assert.equal(node.children[1], 'return 10;'); + assert.equal(node.children[2], '}'); + assert.equal(node.children[3], ''); + assert.equal(node.children[4], 'function noop() {}'); + assert.equal(node.children.length, 5); + + // Prepending other stuff doesn't. + assert.throws(function () { + node.prepend({}); + }); + assert.throws(function () { + node.prepend(function () {}); + }); + }; + + exports['test .toString()'] = function (assert, util) { + assert.equal((new SourceNode(null, null, null, + ['function foo() {', + new SourceNode(null, null, null, 'return 10;'), + '}'])).toString(), + 'function foo() {return 10;}'); + }; + + exports['test .join()'] = function (assert, util) { + assert.equal((new SourceNode(null, null, null, + ['a', 'b', 'c', 'd'])).join(', ').toString(), + 'a, b, c, d'); + }; + + exports['test .walk()'] = function (assert, util) { + var node = new SourceNode(null, null, null, + ['(function () {\n', + ' ', new SourceNode(1, 0, 'a.js', ['someCall()']), ';\n', + ' ', new SourceNode(2, 0, 'b.js', ['if (foo) bar()']), ';\n', + '}());']); + var expected = [ + { str: '(function () {\n', source: null, line: null, column: null }, + { str: ' ', source: null, line: null, column: null }, + { str: 'someCall()', source: 'a.js', line: 1, column: 0 }, + { str: ';\n', source: null, line: null, column: null }, + { str: ' ', source: null, line: null, column: null }, + { str: 'if (foo) bar()', source: 'b.js', line: 2, column: 0 }, + { str: ';\n', source: null, line: null, column: null }, + { str: '}());', source: null, line: null, column: null }, + ]; + var i = 0; + node.walk(function (chunk, loc) { + assert.equal(expected[i].str, chunk); + assert.equal(expected[i].source, loc.source); + assert.equal(expected[i].line, loc.line); + assert.equal(expected[i].column, loc.column); + i++; + }); + }; + + exports['test .replaceRight'] = function (assert, util) { + var node; + + // Not nested + node = new SourceNode(null, null, null, 'hello world'); + node.replaceRight(/world/, 'universe'); + assert.equal(node.toString(), 'hello universe'); + + // Nested + node = new SourceNode(null, null, null, + [new SourceNode(null, null, null, 'hey sexy mama, '), + new SourceNode(null, null, null, 'want to kill all humans?')]); + node.replaceRight(/kill all humans/, 'watch Futurama'); + assert.equal(node.toString(), 'hey sexy mama, want to watch Futurama?'); + }; + + exports['test .toStringWithSourceMap()'] = function (assert, util) { + var node = new SourceNode(null, null, null, + ['(function () {\n', + ' ', + new SourceNode(1, 0, 'a.js', 'someCall', 'originalCall'), + new SourceNode(1, 8, 'a.js', '()'), + ';\n', + ' ', new SourceNode(2, 0, 'b.js', ['if (foo) bar()']), ';\n', + '}());']); + var map = node.toStringWithSourceMap({ + file: 'foo.js' + }).map; + + assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator'); + map = new SourceMapConsumer(map.toString()); + + var actual; + + actual = map.originalPositionFor({ + line: 1, + column: 4 + }); + assert.equal(actual.source, null); + assert.equal(actual.line, null); + assert.equal(actual.column, null); + + actual = map.originalPositionFor({ + line: 2, + column: 2 + }); + assert.equal(actual.source, 'a.js'); + assert.equal(actual.line, 1); + assert.equal(actual.column, 0); + assert.equal(actual.name, 'originalCall'); + + actual = map.originalPositionFor({ + line: 3, + column: 2 + }); + assert.equal(actual.source, 'b.js'); + assert.equal(actual.line, 2); + assert.equal(actual.column, 0); + + actual = map.originalPositionFor({ + line: 3, + column: 16 + }); + assert.equal(actual.source, null); + assert.equal(actual.line, null); + assert.equal(actual.column, null); + + actual = map.originalPositionFor({ + line: 4, + column: 2 + }); + assert.equal(actual.source, null); + assert.equal(actual.line, null); + assert.equal(actual.column, null); + }; + + exports['test .fromStringWithSourceMap()'] = function (assert, util) { + var node = SourceNode.fromStringWithSourceMap( + util.testGeneratedCode, + new SourceMapConsumer(util.testMap)); + + var result = node.toStringWithSourceMap({ + file: 'min.js' + }); + var map = result.map; + var code = result.code; + + assert.equal(code, util.testGeneratedCode); + assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator'); + map = map.toJSON(); + assert.equal(map.version, util.testMap.version); + assert.equal(map.file, util.testMap.file); + assert.equal(map.mappings, util.testMap.mappings); + }; + + exports['test .fromStringWithSourceMap() empty map'] = function (assert, util) { + var node = SourceNode.fromStringWithSourceMap( + util.testGeneratedCode, + new SourceMapConsumer(util.emptyMap)); + var result = node.toStringWithSourceMap({ + file: 'min.js' + }); + var map = result.map; + var code = result.code; + + assert.equal(code, util.testGeneratedCode); + assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator'); + map = map.toJSON(); + assert.equal(map.version, util.emptyMap.version); + assert.equal(map.file, util.emptyMap.file); + assert.equal(map.mappings.length, util.emptyMap.mappings.length); + assert.equal(map.mappings, util.emptyMap.mappings); + }; + + exports['test .fromStringWithSourceMap() complex version'] = function (assert, util) { + var input = new SourceNode(null, null, null, [ + "(function() {\n", + " var Test = {};\n", + " ", new SourceNode(1, 0, "a.js", "Test.A = { value: 1234 };\n"), + " ", new SourceNode(2, 0, "a.js", "Test.A.x = 'xyz';"), "\n", + "}());\n", + "/* Generated Source */"]); + input = input.toStringWithSourceMap({ + file: 'foo.js' + }); + + var node = SourceNode.fromStringWithSourceMap( + input.code, + new SourceMapConsumer(input.map.toString())); + + var result = node.toStringWithSourceMap({ + file: 'foo.js' + }); + var map = result.map; + var code = result.code; + + assert.equal(code, input.code); + assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator'); + map = map.toJSON(); + var inputMap = input.map.toJSON(); + util.assertEqualMaps(assert, map, inputMap); + }; + + exports['test .fromStringWithSourceMap() merging duplicate mappings'] = function (assert, util) { + var input = new SourceNode(null, null, null, [ + new SourceNode(1, 0, "a.js", "(function"), + new SourceNode(1, 0, "a.js", "() {\n"), + " ", + new SourceNode(1, 0, "a.js", "var Test = "), + new SourceNode(1, 0, "b.js", "{};\n"), + new SourceNode(2, 0, "b.js", "Test"), + new SourceNode(2, 0, "b.js", ".A", "A"), + new SourceNode(2, 20, "b.js", " = { value: 1234 };\n", "A"), + "}());\n", + "/* Generated Source */" + ]); + input = input.toStringWithSourceMap({ + file: 'foo.js' + }); + + var correctMap = new SourceMapGenerator({ + file: 'foo.js' + }); + correctMap.addMapping({ + generated: { line: 1, column: 0 }, + source: 'a.js', + original: { line: 1, column: 0 } + }); + correctMap.addMapping({ + generated: { line: 2, column: 0 } + }); + correctMap.addMapping({ + generated: { line: 2, column: 2 }, + source: 'a.js', + original: { line: 1, column: 0 } + }); + correctMap.addMapping({ + generated: { line: 2, column: 13 }, + source: 'b.js', + original: { line: 1, column: 0 } + }); + correctMap.addMapping({ + generated: { line: 3, column: 0 }, + source: 'b.js', + original: { line: 2, column: 0 } + }); + correctMap.addMapping({ + generated: { line: 3, column: 4 }, + source: 'b.js', + name: 'A', + original: { line: 2, column: 0 } + }); + correctMap.addMapping({ + generated: { line: 3, column: 6 }, + source: 'b.js', + name: 'A', + original: { line: 2, column: 20 } + }); + correctMap.addMapping({ + generated: { line: 4, column: 0 } + }); + + var inputMap = input.map.toJSON(); + correctMap = correctMap.toJSON(); + util.assertEqualMaps(assert, correctMap, inputMap); + }; + + exports['test setSourceContent with toStringWithSourceMap'] = function (assert, util) { + var aNode = new SourceNode(1, 1, 'a.js', 'a'); + aNode.setSourceContent('a.js', 'someContent'); + var node = new SourceNode(null, null, null, + ['(function () {\n', + ' ', aNode, + ' ', new SourceNode(1, 1, 'b.js', 'b'), + '}());']); + node.setSourceContent('b.js', 'otherContent'); + var map = node.toStringWithSourceMap({ + file: 'foo.js' + }).map; + + assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator'); + map = new SourceMapConsumer(map.toString()); + + assert.equal(map.sources.length, 2); + assert.equal(map.sources[0], 'a.js'); + assert.equal(map.sources[1], 'b.js'); + assert.equal(map.sourcesContent.length, 2); + assert.equal(map.sourcesContent[0], 'someContent'); + assert.equal(map.sourcesContent[1], 'otherContent'); + }; + + exports['test walkSourceContents'] = function (assert, util) { + var aNode = new SourceNode(1, 1, 'a.js', 'a'); + aNode.setSourceContent('a.js', 'someContent'); + var node = new SourceNode(null, null, null, + ['(function () {\n', + ' ', aNode, + ' ', new SourceNode(1, 1, 'b.js', 'b'), + '}());']); + node.setSourceContent('b.js', 'otherContent'); + var results = []; + node.walkSourceContents(function (sourceFile, sourceContent) { + results.push([sourceFile, sourceContent]); + }); + assert.equal(results.length, 2); + assert.equal(results[0][0], 'a.js'); + assert.equal(results[0][1], 'someContent'); + assert.equal(results[1][0], 'b.js'); + assert.equal(results[1][1], 'otherContent'); + }; +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/util.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/util.js new file mode 100644 index 0000000..288046b --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/source-map/test/source-map/util.js @@ -0,0 +1,161 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var util = require('../../lib/source-map/util'); + + // This is a test mapping which maps functions from two different files + // (one.js and two.js) to a minified generated source. + // + // Here is one.js: + // + // ONE.foo = function (bar) { + // return baz(bar); + // }; + // + // Here is two.js: + // + // TWO.inc = function (n) { + // return n + 1; + // }; + // + // And here is the generated code (min.js): + // + // ONE.foo=function(a){return baz(a);}; + // TWO.inc=function(a){return a+1;}; + exports.testGeneratedCode = " ONE.foo=function(a){return baz(a);};\n"+ + " TWO.inc=function(a){return a+1;};"; + exports.testMap = { + version: 3, + file: 'min.js', + names: ['bar', 'baz', 'n'], + sources: ['one.js', 'two.js'], + sourceRoot: '/the/root', + mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA' + }; + exports.testMapWithSourcesContent = { + version: 3, + file: 'min.js', + names: ['bar', 'baz', 'n'], + sources: ['one.js', 'two.js'], + sourcesContent: [ + ' ONE.foo = function (bar) {\n' + + ' return baz(bar);\n' + + ' };', + ' TWO.inc = function (n) {\n' + + ' return n + 1;\n' + + ' };' + ], + sourceRoot: '/the/root', + mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA' + }; + exports.emptyMap = { + version: 3, + file: 'min.js', + names: [], + sources: [], + mappings: '' + }; + + + function assertMapping(generatedLine, generatedColumn, originalSource, + originalLine, originalColumn, name, map, assert, + dontTestGenerated, dontTestOriginal) { + if (!dontTestOriginal) { + var origMapping = map.originalPositionFor({ + line: generatedLine, + column: generatedColumn + }); + assert.equal(origMapping.name, name, + 'Incorrect name, expected ' + JSON.stringify(name) + + ', got ' + JSON.stringify(origMapping.name)); + assert.equal(origMapping.line, originalLine, + 'Incorrect line, expected ' + JSON.stringify(originalLine) + + ', got ' + JSON.stringify(origMapping.line)); + assert.equal(origMapping.column, originalColumn, + 'Incorrect column, expected ' + JSON.stringify(originalColumn) + + ', got ' + JSON.stringify(origMapping.column)); + + var expectedSource; + + if (originalSource && map.sourceRoot && originalSource.indexOf(map.sourceRoot) === 0) { + expectedSource = originalSource; + } else if (originalSource) { + expectedSource = map.sourceRoot + ? util.join(map.sourceRoot, originalSource) + : originalSource; + } else { + expectedSource = null; + } + + assert.equal(origMapping.source, expectedSource, + 'Incorrect source, expected ' + JSON.stringify(expectedSource) + + ', got ' + JSON.stringify(origMapping.source)); + } + + if (!dontTestGenerated) { + var genMapping = map.generatedPositionFor({ + source: originalSource, + line: originalLine, + column: originalColumn + }); + assert.equal(genMapping.line, generatedLine, + 'Incorrect line, expected ' + JSON.stringify(generatedLine) + + ', got ' + JSON.stringify(genMapping.line)); + assert.equal(genMapping.column, generatedColumn, + 'Incorrect column, expected ' + JSON.stringify(generatedColumn) + + ', got ' + JSON.stringify(genMapping.column)); + } + } + exports.assertMapping = assertMapping; + + function assertEqualMaps(assert, actualMap, expectedMap) { + assert.equal(actualMap.version, expectedMap.version, "version mismatch"); + assert.equal(actualMap.file, expectedMap.file, "file mismatch"); + assert.equal(actualMap.names.length, + expectedMap.names.length, + "names length mismatch: " + + actualMap.names.join(", ") + " != " + expectedMap.names.join(", ")); + for (var i = 0; i < actualMap.names.length; i++) { + assert.equal(actualMap.names[i], + expectedMap.names[i], + "names[" + i + "] mismatch: " + + actualMap.names.join(", ") + " != " + expectedMap.names.join(", ")); + } + assert.equal(actualMap.sources.length, + expectedMap.sources.length, + "sources length mismatch: " + + actualMap.sources.join(", ") + " != " + expectedMap.sources.join(", ")); + for (var i = 0; i < actualMap.sources.length; i++) { + assert.equal(actualMap.sources[i], + expectedMap.sources[i], + "sources[" + i + "] length mismatch: " + + actualMap.sources.join(", ") + " != " + expectedMap.sources.join(", ")); + } + assert.equal(actualMap.sourceRoot, + expectedMap.sourceRoot, + "sourceRoot mismatch: " + + actualMap.sourceRoot + " != " + expectedMap.sourceRoot); + assert.equal(actualMap.mappings, expectedMap.mappings, + "mappings mismatch:\nActual: " + actualMap.mappings + "\nExpected: " + expectedMap.mappings); + if (actualMap.sourcesContent) { + assert.equal(actualMap.sourcesContent.length, + expectedMap.sourcesContent.length, + "sourcesContent length mismatch"); + for (var i = 0; i < actualMap.sourcesContent.length; i++) { + assert.equal(actualMap.sourcesContent[i], + expectedMap.sourcesContent[i], + "sourcesContent[" + i + "] mismatch"); + } + } + } + exports.assertEqualMaps = assertEqualMaps; + +}); diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/.npmignore b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/.npmignore new file mode 100644 index 0000000..3e56974 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/.npmignore @@ -0,0 +1,14 @@ +lib-cov +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.gz +pids +logs +results +npm-debug.log +node_modules +/test/output.js diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/.travis.yml b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/.travis.yml new file mode 100644 index 0000000..87f8cd9 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/.travis.yml @@ -0,0 +1,3 @@ +language: node_js +node_js: + - "0.10" \ No newline at end of file diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/LICENSE b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/LICENSE new file mode 100644 index 0000000..35cc606 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013 Forbes Lindesay + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/README.md b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/README.md new file mode 100644 index 0000000..c5dde96 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/README.md @@ -0,0 +1,15 @@ +# uglify-to-browserify + +A transform to make UglifyJS work in browserify. + +[![Build Status](https://travis-ci.org/ForbesLindesay/uglify-to-browserify.png?branch=master)](https://travis-ci.org/ForbesLindesay/uglify-to-browserify) +[![Dependency Status](https://gemnasium.com/ForbesLindesay/uglify-to-browserify.png)](https://gemnasium.com/ForbesLindesay/uglify-to-browserify) +[![NPM version](https://badge.fury.io/js/uglify-to-browserify.png)](http://badge.fury.io/js/uglify-to-browserify) + +## Installation + + npm install uglify-to-browserify + +## License + + MIT \ No newline at end of file diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/index.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/index.js new file mode 100644 index 0000000..5d33072 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/index.js @@ -0,0 +1,46 @@ +'use strict' + +var fs = require('fs') +var PassThrough = require('stream').PassThrough +var Transform = require('stream').Transform + +if (typeof Transform === 'undefined') { + throw new Error('UglifyJS only supports browserify when using node >= 0.10.x') +} + +var cache = {} +module.exports = transform +function transform(file) { + if (!/tools\/node\.js$/.test(file.replace(/\\/g,'/'))) return new PassThrough(); + if (cache[file]) return makeStream(cache[file]) + var uglify = require(file) + var src = 'var sys = require("util");\nvar MOZ_SourceMap = require("source-map");\nvar UglifyJS = exports;\n' + uglify.FILES.map(function (path) { return fs.readFileSync(path, 'utf8') }).join('\n') + + var ast = uglify.parse(src) + ast.figure_out_scope() + + var variables = ast.variables + .map(function (node, name) { + return name + }) + + src += '\n\n' + variables.map(function (v) { return 'exports.' + v + ' = ' + v + ';' }).join('\n') + '\n\n' + + src += 'exports.AST_Node.warn_function = function (txt) { if (typeof console != "undefined" && typeof console.warn === "function") console.warn(txt) }\n\n' + + src += 'exports.minify = ' + uglify.minify.toString() + ';\n\n' + src += 'exports.describe_ast = ' + uglify.describe_ast.toString() + ';' + + cache[file] = src + return makeStream(src); +} + +function makeStream(src) { + var res = new Transform(); + res._transform = function (chunk, encoding, callback) { callback() } + res._flush = function (callback) { + res.push(src) + callback() + } + return res; +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/package.json b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/package.json new file mode 100644 index 0000000..803cec8 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/package.json @@ -0,0 +1,33 @@ +{ + "name": "uglify-to-browserify", + "version": "1.0.1", + "description": "A transform to make UglifyJS work in browserify.", + "keywords": [], + "dependencies": {}, + "devDependencies": { + "uglify-js": "~2.4.0", + "source-map": "~0.1.27" + }, + "scripts": { + "test": "node test/index.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/ForbesLindesay/uglify-to-browserify.git" + }, + "author": { + "name": "ForbesLindesay" + }, + "license": "MIT", + "readme": "# uglify-to-browserify\r\n\r\nA transform to make UglifyJS work in browserify.\r\n\r\n[![Build Status](https://travis-ci.org/ForbesLindesay/uglify-to-browserify.png?branch=master)](https://travis-ci.org/ForbesLindesay/uglify-to-browserify)\r\n[![Dependency Status](https://gemnasium.com/ForbesLindesay/uglify-to-browserify.png)](https://gemnasium.com/ForbesLindesay/uglify-to-browserify)\r\n[![NPM version](https://badge.fury.io/js/uglify-to-browserify.png)](http://badge.fury.io/js/uglify-to-browserify)\r\n\r\n## Installation\r\n\r\n npm install uglify-to-browserify\r\n\r\n## License\r\n\r\n MIT", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/ForbesLindesay/uglify-to-browserify/issues" + }, + "_id": "uglify-to-browserify@1.0.1", + "dist": { + "shasum": "7e977b388edca6d77e667939b1956d180bcdfc8e" + }, + "_from": "uglify-to-browserify@~1.0.0", + "_resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.1.tgz" +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/test/index.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/test/index.js new file mode 100644 index 0000000..6befb6b --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/node_modules/uglify-to-browserify/test/index.js @@ -0,0 +1,22 @@ +var fs = require('fs') +var br = require('../') +var test = fs.readFileSync(require.resolve('uglify-js/test/run-tests.js'), 'utf8') + .replace(/^#.*\n/, '') + +var transform = br(require.resolve('uglify-js')) +transform.pipe(fs.createWriteStream(__dirname + '/output.js')) + .on('close', function () { + Function('module,require', test)({ + filename: require.resolve('uglify-js/test/run-tests.js') + }, + function (name) { + if (name === '../tools/node') { + return require('./output.js') + } else if (/^[a-z]+$/.test(name)) { + return require(name) + } else { + throw new Error('I didn\'t expect you to require ' + name) + } + }) + }) +transform.end(fs.readFileSync(require.resolve('uglify-js'), 'utf8')) \ No newline at end of file diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/package.json b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/package.json new file mode 100644 index 0000000..282a08d --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/package.json @@ -0,0 +1,49 @@ +{ + "name": "uglify-js", + "description": "JavaScript parser, mangler/compressor and beautifier toolkit", + "homepage": "http://lisperator.net/uglifyjs", + "main": "tools/node.js", + "version": "2.4.3", + "engines": { + "node": ">=0.4.0" + }, + "maintainers": [ + { + "name": "Mihai Bazon", + "email": "mihai.bazon@gmail.com", + "url": "http://lisperator.net/" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/mishoo/UglifyJS2.git" + }, + "dependencies": { + "async": "~0.2.6", + "source-map": "~0.1.7", + "optimist": "~0.3.5", + "uglify-to-browserify": "~1.0.0" + }, + "browserify": { + "transform": [ + "uglify-to-browserify" + ] + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "scripts": { + "test": "node test/run-tests.js" + }, + "readme": "UglifyJS 2\n==========\n[![Build Status](https://travis-ci.org/mishoo/UglifyJS2.png)](https://travis-ci.org/mishoo/UglifyJS2)\n\nUglifyJS is a JavaScript parser, minifier, compressor or beautifier toolkit.\n\nThis page documents the command line utility. For\n[API and internals documentation see my website](http://lisperator.net/uglifyjs/).\nThere's also an\n[in-browser online demo](http://lisperator.net/uglifyjs/#demo) (for Firefox,\nChrome and probably Safari).\n\nInstall\n-------\n\nFirst make sure you have installed the latest version of [node.js](http://nodejs.org/)\n(You may need to restart your computer after this step).\n\nFrom NPM for use as a command line app:\n\n npm install uglify-js -g\n\nFrom NPM for programmatic use:\n\n npm install uglify-js\n\nFrom Git:\n\n git clone git://github.com/mishoo/UglifyJS2.git\n cd UglifyJS2\n npm link .\n\nUsage\n-----\n\n uglifyjs [input files] [options]\n\nUglifyJS2 can take multiple input files. It's recommended that you pass the\ninput files first, then pass the options. UglifyJS will parse input files\nin sequence and apply any compression options. The files are parsed in the\nsame global scope, that is, a reference from a file to some\nvariable/function declared in another file will be matched properly.\n\nIf you want to read from STDIN instead, pass a single dash instead of input\nfiles.\n\nThe available options are:\n\n```\n --source-map Specify an output file where to generate source map.\n [string]\n --source-map-root The path to the original source to be included in the\n source map. [string]\n --source-map-url The path to the source map to be added in //#\n sourceMappingURL. Defaults to the value passed with\n --source-map. [string]\n --in-source-map Input source map, useful if you're compressing JS that was\n generated from some other original code.\n --screw-ie8 Pass this flag if you don't care about full compliance\n with Internet Explorer 6-8 quirks (by default UglifyJS\n will try to be IE-proof). [boolean]\n --expr Parse a single expression, rather than a program (for\n parsing JSON) [boolean]\n -p, --prefix Skip prefix for original filenames that appear in source\n maps. For example -p 3 will drop 3 directories from file\n names and ensure they are relative paths. You can also\n specify -p relative, which will make UglifyJS figure out\n itself the relative paths between original sources, the\n source map and the output file. [string]\n -o, --output Output file (default STDOUT).\n -b, --beautify Beautify output/specify output options. [string]\n -m, --mangle Mangle names/pass mangler options. [string]\n -r, --reserved Reserved names to exclude from mangling.\n -c, --compress Enable compressor/pass compressor options. Pass options\n like -c hoist_vars=false,if_return=false. Use -c with no\n argument to use the default compression options. [string]\n -d, --define Global definitions [string]\n -e, --enclose Embed everything in a big function, with a configurable\n parameter/argument list. [string]\n --comments Preserve copyright comments in the output. By default this\n works like Google Closure, keeping JSDoc-style comments\n that contain \"@license\" or \"@preserve\". You can optionally\n pass one of the following arguments to this flag:\n - \"all\" to keep all comments\n - a valid JS regexp (needs to start with a slash) to keep\n only comments that match.\n Note that currently not *all* comments can be kept when\n compression is on, because of dead code removal or\n cascading statements into sequences. [string]\n --preamble Preamble to prepend to the output. You can use this to\n insert a comment, for example for licensing information.\n This will not be parsed, but the source map will adjust\n for its presence.\n --stats Display operations run time on STDERR. [boolean]\n --acorn Use Acorn for parsing. [boolean]\n --spidermonkey Assume input files are SpiderMonkey AST format (as JSON).\n [boolean]\n --self Build itself (UglifyJS2) as a library (implies\n --wrap=UglifyJS --export-all) [boolean]\n --wrap Embed everything in a big function, making the “exports”\n and “global” variables available. You need to pass an\n argument to this option to specify the name that your\n module will take when included in, say, a browser.\n [string]\n --export-all Only used when --wrap, this tells UglifyJS to add code to\n automatically export all globals. [boolean]\n --lint Display some scope warnings [boolean]\n -v, --verbose Verbose [boolean]\n -V, --version Print version number and exit. [boolean]\n```\n\nSpecify `--output` (`-o`) to declare the output file. Otherwise the output\ngoes to STDOUT.\n\n## Source map options\n\nUglifyJS2 can generate a source map file, which is highly useful for\ndebugging your compressed JavaScript. To get a source map, pass\n`--source-map output.js.map` (full path to the file where you want the\nsource map dumped).\n\nAdditionally you might need `--source-map-root` to pass the URL where the\noriginal files can be found. In case you are passing full paths to input\nfiles to UglifyJS, you can use `--prefix` (`-p`) to specify the number of\ndirectories to drop from the path prefix when declaring files in the source\nmap.\n\nFor example:\n\n uglifyjs /home/doe/work/foo/src/js/file1.js \\\n /home/doe/work/foo/src/js/file2.js \\\n -o foo.min.js \\\n --source-map foo.min.js.map \\\n --source-map-root http://foo.com/src \\\n -p 5 -c -m\n\nThe above will compress and mangle `file1.js` and `file2.js`, will drop the\noutput in `foo.min.js` and the source map in `foo.min.js.map`. The source\nmapping will refer to `http://foo.com/src/js/file1.js` and\n`http://foo.com/src/js/file2.js` (in fact it will list `http://foo.com/src`\nas the source map root, and the original files as `js/file1.js` and\n`js/file2.js`).\n\n### Composed source map\n\nWhen you're compressing JS code that was output by a compiler such as\nCoffeeScript, mapping to the JS code won't be too helpful. Instead, you'd\nlike to map back to the original code (i.e. CoffeeScript). UglifyJS has an\noption to take an input source map. Assuming you have a mapping from\nCoffeeScript → compiled JS, UglifyJS can generate a map from CoffeeScript →\ncompressed JS by mapping every token in the compiled JS to its original\nlocation.\n\nTo use this feature you need to pass `--in-source-map\n/path/to/input/source.map`. Normally the input source map should also point\nto the file containing the generated JS, so if that's correct you can omit\ninput files from the command line.\n\n## Mangler options\n\nTo enable the mangler you need to pass `--mangle` (`-m`). The following\n(comma-separated) options are supported:\n\n- `sort` — to assign shorter names to most frequently used variables. This\n saves a few hundred bytes on jQuery before gzip, but the output is\n _bigger_ after gzip (and seems to happen for other libraries I tried it\n on) therefore it's not enabled by default.\n\n- `toplevel` — mangle names declared in the toplevel scope (disabled by\n default).\n\n- `eval` — mangle names visible in scopes where `eval` or `when` are used\n (disabled by default).\n\nWhen mangling is enabled but you want to prevent certain names from being\nmangled, you can declare those names with `--reserved` (`-r`) — pass a\ncomma-separated list of names. For example:\n\n uglifyjs ... -m -r '$,require,exports'\n\nto prevent the `require`, `exports` and `$` names from being changed.\n\n## Compressor options\n\nYou need to pass `--compress` (`-c`) to enable the compressor. Optionally\nyou can pass a comma-separated list of options. Options are in the form\n`foo=bar`, or just `foo` (the latter implies a boolean option that you want\nto set `true`; it's effectively a shortcut for `foo=true`).\n\n- `sequences` -- join consecutive simple statements using the comma operator\n\n- `properties` -- rewrite property access using the dot notation, for\n example `foo[\"bar\"] → foo.bar`\n\n- `dead_code` -- remove unreachable code\n\n- `drop_debugger` -- remove `debugger;` statements\n\n- `unsafe` (default: false) -- apply \"unsafe\" transformations (discussion below)\n\n- `conditionals` -- apply optimizations for `if`-s and conditional\n expressions\n\n- `comparisons` -- apply certain optimizations to binary nodes, for example:\n `!(a <= b) → a > b` (only when `unsafe`), attempts to negate binary nodes,\n e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.\n\n- `evaluate` -- attempt to evaluate constant expressions\n\n- `booleans` -- various optimizations for boolean context, for example `!!a\n ? b : c → a ? b : c`\n\n- `loops` -- optimizations for `do`, `while` and `for` loops when we can\n statically determine the condition\n\n- `unused` -- drop unreferenced functions and variables\n\n- `hoist_funs` -- hoist function declarations\n\n- `hoist_vars` (default: false) -- hoist `var` declarations (this is `false`\n by default because it seems to increase the size of the output in general)\n\n- `if_return` -- optimizations for if/return and if/continue\n\n- `join_vars` -- join consecutive `var` statements\n\n- `cascade` -- small optimization for sequences, transform `x, x` into `x`\n and `x = something(), x` into `x = something()`\n\n- `warnings` -- display warnings when dropping unreachable code or unused\n declarations etc.\n\n- `negate_iife` -- negate \"Immediately-Called Function Expressions\"\n where the return value is discarded, to avoid the parens that the\n code generator would insert.\n\n- `pure_getters` -- the default is `false`. If you pass `true` for\n this, UglifyJS will assume that object property access\n (e.g. `foo.bar` or `foo[\"bar\"]`) doesn't have any side effects.\n\n- `pure_funcs` -- default `null`. You can pass an array of names and\n UglifyJS will assume that those functions do not produce side\n effects. DANGER: will not check if the name is redefined in scope.\n An example case here, for instance `var q = Math.floor(a/b)`. If\n variable `q` is not used elsewhere, UglifyJS will drop it, but will\n still keep the `Math.floor(a/b)`, not knowing what it does. You can\n pass `pure_funcs: [ 'Math.floor' ]` to let it know that this\n function won't produce any side effect, in which case the whole\n statement would get discarded. The current implementation adds some\n overhead (compression will be slower).\n\n### The `unsafe` option\n\nIt enables some transformations that *might* break code logic in certain\ncontrived cases, but should be fine for most code. You might want to try it\non your own code, it should reduce the minified size. Here's what happens\nwhen this flag is on:\n\n- `new Array(1, 2, 3)` or `Array(1, 2, 3)` → `[1, 2, 3 ]`\n- `new Object()` → `{}`\n- `String(exp)` or `exp.toString()` → `\"\" + exp`\n- `new Object/RegExp/Function/Error/Array (...)` → we discard the `new`\n- `typeof foo == \"undefined\"` → `foo === void 0`\n- `void 0` → `undefined` (if there is a variable named \"undefined\" in\n scope; we do it because the variable name will be mangled, typically\n reduced to a single character).\n\n### Conditional compilation\n\nYou can use the `--define` (`-d`) switch in order to declare global\nvariables that UglifyJS will assume to be constants (unless defined in\nscope). For example if you pass `--define DEBUG=false` then, coupled with\ndead code removal UglifyJS will discard the following from the output:\n```javascript\nif (DEBUG) {\n\tconsole.log(\"debug stuff\");\n}\n```\n\nUglifyJS will warn about the condition being always false and about dropping\nunreachable code; for now there is no option to turn off only this specific\nwarning, you can pass `warnings=false` to turn off *all* warnings.\n\nAnother way of doing that is to declare your globals as constants in a\nseparate file and include it into the build. For example you can have a\n`build/defines.js` file with the following:\n```javascript\nconst DEBUG = false;\nconst PRODUCTION = true;\n// etc.\n```\n\nand build your code like this:\n\n uglifyjs build/defines.js js/foo.js js/bar.js... -c\n\nUglifyJS will notice the constants and, since they cannot be altered, it\nwill evaluate references to them to the value itself and drop unreachable\ncode as usual. The possible downside of this approach is that the build\nwill contain the `const` declarations.\n\n\n## Beautifier options\n\nThe code generator tries to output shortest code possible by default. In\ncase you want beautified output, pass `--beautify` (`-b`). Optionally you\ncan pass additional arguments that control the code output:\n\n- `beautify` (default `true`) -- whether to actually beautify the output.\n Passing `-b` will set this to true, but you might need to pass `-b` even\n when you want to generate minified code, in order to specify additional\n arguments, so you can use `-b beautify=false` to override it.\n- `indent-level` (default 4)\n- `indent-start` (default 0) -- prefix all lines by that many spaces\n- `quote-keys` (default `false`) -- pass `true` to quote all keys in literal\n objects\n- `space-colon` (default `true`) -- insert a space after the colon signs\n- `ascii-only` (default `false`) -- escape Unicode characters in strings and\n regexps\n- `inline-script` (default `false`) -- escape the slash in occurrences of\n `= (x = f(…)) + * + * For example, let the equation be: + * (a = parseInt('100')) <= a + * + * If a was an integer and has the value of 99, + * (a = parseInt('100')) <= a → 100 <= 100 → true + * + * When transformed incorrectly: + * a >= (a = parseInt('100')) → 99 >= 100 → false + */ + +tranformation_sort_order_equal: { + options = { + comparisons: true, + }; + + input: { (a = parseInt('100')) == a } + expect: { (a = parseInt('100')) == a } +} + +tranformation_sort_order_unequal: { + options = { + comparisons: true, + }; + + input: { (a = parseInt('100')) != a } + expect: { (a = parseInt('100')) != a } +} + +tranformation_sort_order_lesser_or_equal: { + options = { + comparisons: true, + }; + + input: { (a = parseInt('100')) <= a } + expect: { (a = parseInt('100')) <= a } +} +tranformation_sort_order_greater_or_equal: { + options = { + comparisons: true, + }; + + input: { (a = parseInt('100')) >= a } + expect: { (a = parseInt('100')) >= a } +} \ No newline at end of file diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/issue-22.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/issue-22.js new file mode 100644 index 0000000..a8b7bc6 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/issue-22.js @@ -0,0 +1,17 @@ +return_with_no_value_in_if_body: { + options = { conditionals: true }; + input: { + function foo(bar) { + if (bar) { + return; + } else { + return 1; + } + } + } + expect: { + function foo (bar) { + return bar ? void 0 : 1; + } + } +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/issue-267.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/issue-267.js new file mode 100644 index 0000000..7233d9f --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/issue-267.js @@ -0,0 +1,11 @@ +issue_267: { + options = { comparisons: true }; + input: { + x = a % b / b * c * 2; + x = a % b * 2 + } + expect: { + x = a % b / b * c * 2; + x = a % b * 2; + } +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/issue-269.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/issue-269.js new file mode 100644 index 0000000..70e82d0 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/issue-269.js @@ -0,0 +1,68 @@ +issue_269_1: { + options = {unsafe: true}; + input: { + f( + String(x), + Number(x), + Boolean(x), + + String(), + Number(), + Boolean() + ); + } + expect: { + f( + x + '', +x, !!x, + '', 0, false + ); + } +} + +issue_269_dangers: { + options = {unsafe: true}; + input: { + f( + String(x, x), + Number(x, x), + Boolean(x, x) + ); + } + expect: { + f(String(x, x), Number(x, x), Boolean(x, x)); + } +} + +issue_269_in_scope: { + options = {unsafe: true}; + input: { + var String, Number, Boolean; + f( + String(x), + Number(x, x), + Boolean(x) + ); + } + expect: { + var String, Number, Boolean; + f(String(x), Number(x, x), Boolean(x)); + } +} + +strings_concat: { + options = {unsafe: true}; + input: { + f( + String(x + 'str'), + String('str' + x), + String(x + 5) + ); + } + expect: { + f( + x + 'str', + 'str' + x, + x + '5' + ); + } +} \ No newline at end of file diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/issue-44.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/issue-44.js new file mode 100644 index 0000000..7a972f9 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/issue-44.js @@ -0,0 +1,31 @@ +issue_44_valid_ast_1: { + options = { unused: true }; + input: { + function a(b) { + for (var i = 0, e = b.qoo(); ; i++) {} + } + } + expect: { + function a(b) { + var i = 0; + for (b.qoo(); ; i++); + } + } +} + +issue_44_valid_ast_2: { + options = { unused: true }; + input: { + function a(b) { + if (foo) for (var i = 0, e = b.qoo(); ; i++) {} + } + } + expect: { + function a(b) { + if (foo) { + var i = 0; + for (b.qoo(); ; i++); + } + } + } +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/issue-59.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/issue-59.js new file mode 100644 index 0000000..82b3880 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/issue-59.js @@ -0,0 +1,30 @@ +keep_continue: { + options = { + dead_code: true, + evaluate: true + }; + input: { + while (a) { + if (b) { + switch (true) { + case c(): + d(); + } + continue; + } + f(); + } + } + expect: { + while (a) { + if (b) { + switch (true) { + case c(): + d(); + } + continue; + } + f(); + } + } +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/labels.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/labels.js new file mode 100644 index 0000000..044b7a7 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/labels.js @@ -0,0 +1,163 @@ +labels_1: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + out: { + if (foo) break out; + console.log("bar"); + } + }; + expect: { + foo || console.log("bar"); + } +} + +labels_2: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + out: { + if (foo) print("stuff"); + else break out; + console.log("here"); + } + }; + expect: { + if (foo) { + print("stuff"); + console.log("here"); + } + } +} + +labels_3: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + for (var i = 0; i < 5; ++i) { + if (i < 3) continue; + console.log(i); + } + }; + expect: { + for (var i = 0; i < 5; ++i) + i < 3 || console.log(i); + } +} + +labels_4: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + out: for (var i = 0; i < 5; ++i) { + if (i < 3) continue out; + console.log(i); + } + }; + expect: { + for (var i = 0; i < 5; ++i) + i < 3 || console.log(i); + } +} + +labels_5: { + options = { if_return: true, conditionals: true, dead_code: true }; + // should keep the break-s in the following + input: { + while (foo) { + if (bar) break; + console.log("foo"); + } + out: while (foo) { + if (bar) break out; + console.log("foo"); + } + }; + expect: { + while (foo) { + if (bar) break; + console.log("foo"); + } + out: while (foo) { + if (bar) break out; + console.log("foo"); + } + } +} + +labels_6: { + input: { + out: break out; + }; + expect: {} +} + +labels_7: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + while (foo) { + x(); + y(); + continue; + } + }; + expect: { + while (foo) { + x(); + y(); + } + } +} + +labels_8: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + while (foo) { + x(); + y(); + break; + } + }; + expect: { + while (foo) { + x(); + y(); + break; + } + } +} + +labels_9: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + out: while (foo) { + x(); + y(); + continue out; + z(); + k(); + } + }; + expect: { + while (foo) { + x(); + y(); + } + } +} + +labels_10: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + out: while (foo) { + x(); + y(); + break out; + z(); + k(); + } + }; + expect: { + out: while (foo) { + x(); + y(); + break out; + } + } +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/loops.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/loops.js new file mode 100644 index 0000000..cdf1f04 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/loops.js @@ -0,0 +1,123 @@ +while_becomes_for: { + options = { loops: true }; + input: { + while (foo()) bar(); + } + expect: { + for (; foo(); ) bar(); + } +} + +drop_if_break_1: { + options = { loops: true }; + input: { + for (;;) + if (foo()) break; + } + expect: { + for (; !foo();); + } +} + +drop_if_break_2: { + options = { loops: true }; + input: { + for (;bar();) + if (foo()) break; + } + expect: { + for (; bar() && !foo();); + } +} + +drop_if_break_3: { + options = { loops: true }; + input: { + for (;bar();) { + if (foo()) break; + stuff1(); + stuff2(); + } + } + expect: { + for (; bar() && !foo();) { + stuff1(); + stuff2(); + } + } +} + +drop_if_break_4: { + options = { loops: true, sequences: true }; + input: { + for (;bar();) { + x(); + y(); + if (foo()) break; + z(); + k(); + } + } + expect: { + for (; bar() && (x(), y(), !foo());) z(), k(); + } +} + +drop_if_else_break_1: { + options = { loops: true }; + input: { + for (;;) if (foo()) bar(); else break; + } + expect: { + for (; foo(); ) bar(); + } +} + +drop_if_else_break_2: { + options = { loops: true }; + input: { + for (;bar();) { + if (foo()) baz(); + else break; + } + } + expect: { + for (; bar() && foo();) baz(); + } +} + +drop_if_else_break_3: { + options = { loops: true }; + input: { + for (;bar();) { + if (foo()) baz(); + else break; + stuff1(); + stuff2(); + } + } + expect: { + for (; bar() && foo();) { + baz(); + stuff1(); + stuff2(); + } + } +} + +drop_if_else_break_4: { + options = { loops: true, sequences: true }; + input: { + for (;bar();) { + x(); + y(); + if (foo()) baz(); + else break; + z(); + k(); + } + } + expect: { + for (; bar() && (x(), y(), foo());) baz(), z(), k(); + } +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/negate-iife.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/negate-iife.js new file mode 100644 index 0000000..0362ffc --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/negate-iife.js @@ -0,0 +1,76 @@ +negate_iife_1: { + options = { + negate_iife: true + }; + input: { + (function(){ stuff() })(); + } + expect: { + !function(){ stuff() }(); + } +} + +negate_iife_2: { + options = { + negate_iife: true + }; + input: { + (function(){ return {} })().x = 10; // should not transform this one + } + expect: { + (function(){ return {} })().x = 10; + } +} + +negate_iife_3: { + options = { + negate_iife: true, + }; + input: { + (function(){ return true })() ? console.log(true) : console.log(false); + } + expect: { + !function(){ return true }() ? console.log(false) : console.log(true); + } +} + +negate_iife_3: { + options = { + negate_iife: true, + sequences: true + }; + input: { + (function(){ return true })() ? console.log(true) : console.log(false); + (function(){ + console.log("something"); + })(); + } + expect: { + !function(){ return true }() ? console.log(false) : console.log(true), function(){ + console.log("something"); + }(); + } +} + +negate_iife_4: { + options = { + negate_iife: true, + sequences: true, + conditionals: true, + }; + input: { + if ((function(){ return true })()) { + console.log(true); + } else { + console.log(false); + } + (function(){ + console.log("something"); + })(); + } + expect: { + !function(){ return true }() ? console.log(false) : console.log(true), function(){ + console.log("something"); + }(); + } +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/properties.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/properties.js new file mode 100644 index 0000000..8504596 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/properties.js @@ -0,0 +1,54 @@ +keep_properties: { + options = { + properties: false + }; + input: { + a["foo"] = "bar"; + } + expect: { + a["foo"] = "bar"; + } +} + +dot_properties: { + options = { + properties: true + }; + input: { + a["foo"] = "bar"; + a["if"] = "if"; + a["*"] = "asterisk"; + a["\u0EB3"] = "unicode"; + a[""] = "whitespace"; + a["1_1"] = "foo"; + } + expect: { + a.foo = "bar"; + a["if"] = "if"; + a["*"] = "asterisk"; + a.\u0EB3 = "unicode"; + a[""] = "whitespace"; + a["1_1"] = "foo"; + } +} + +dot_properties_es5: { + options = { + properties: true, + screw_ie8: true + }; + input: { + a["foo"] = "bar"; + a["if"] = "if"; + a["*"] = "asterisk"; + a["\u0EB3"] = "unicode"; + a[""] = "whitespace"; + } + expect: { + a.foo = "bar"; + a.if = "if"; + a["*"] = "asterisk"; + a.\u0EB3 = "unicode"; + a[""] = "whitespace"; + } +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/sequences.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/sequences.js new file mode 100644 index 0000000..4669571 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/sequences.js @@ -0,0 +1,163 @@ +make_sequences_1: { + options = { + sequences: true + }; + input: { + foo(); + bar(); + baz(); + } + expect: { + foo(),bar(),baz(); + } +} + +make_sequences_2: { + options = { + sequences: true + }; + input: { + if (boo) { + foo(); + bar(); + baz(); + } else { + x(); + y(); + z(); + } + } + expect: { + if (boo) foo(),bar(),baz(); + else x(),y(),z(); + } +} + +make_sequences_3: { + options = { + sequences: true + }; + input: { + function f() { + foo(); + bar(); + return baz(); + } + function g() { + foo(); + bar(); + throw new Error(); + } + } + expect: { + function f() { + return foo(), bar(), baz(); + } + function g() { + throw foo(), bar(), new Error(); + } + } +} + +make_sequences_4: { + options = { + sequences: true + }; + input: { + x = 5; + if (y) z(); + + x = 5; + for (i = 0; i < 5; i++) console.log(i); + + x = 5; + for (; i < 5; i++) console.log(i); + + x = 5; + switch (y) {} + + x = 5; + with (obj) {} + } + expect: { + if (x = 5, y) z(); + for (x = 5, i = 0; i < 5; i++) console.log(i); + for (x = 5; i < 5; i++) console.log(i); + switch (x = 5, y) {} + with (x = 5, obj); + } +} + +lift_sequences_1: { + options = { sequences: true }; + input: { + foo = !(x(), y(), bar()); + } + expect: { + x(), y(), foo = !bar(); + } +} + +lift_sequences_2: { + options = { sequences: true, evaluate: true }; + input: { + foo.x = (foo = {}, 10); + bar = (bar = {}, 10); + } + expect: { + foo.x = (foo = {}, 10), + bar = {}, bar = 10; + } +} + +lift_sequences_3: { + options = { sequences: true, conditionals: true }; + input: { + x = (foo(), bar(), baz()) ? 10 : 20; + } + expect: { + foo(), bar(), x = baz() ? 10 : 20; + } +} + +lift_sequences_4: { + options = { side_effects: true }; + input: { + x = (foo, bar, baz); + } + expect: { + x = baz; + } +} + +for_sequences: { + options = { sequences: true }; + input: { + // 1 + foo(); + bar(); + for (; false;); + // 2 + foo(); + bar(); + for (x = 5; false;); + // 3 + x = (foo in bar); + for (; false;); + // 4 + x = (foo in bar); + for (y = 5; false;); + } + expect: { + // 1 + for (foo(), bar(); false;); + // 2 + for (foo(), bar(), x = 5; false;); + // 3 + x = (foo in bar); + for (; false;); + // 4 + x = (foo in bar); + for (y = 5; false;); + } +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/switch.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/switch.js new file mode 100644 index 0000000..62e39cf --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/switch.js @@ -0,0 +1,260 @@ +constant_switch_1: { + options = { dead_code: true, evaluate: true }; + input: { + switch (1+1) { + case 1: foo(); break; + case 1+1: bar(); break; + case 1+1+1: baz(); break; + } + } + expect: { + bar(); + } +} + +constant_switch_2: { + options = { dead_code: true, evaluate: true }; + input: { + switch (1) { + case 1: foo(); + case 1+1: bar(); break; + case 1+1+1: baz(); + } + } + expect: { + foo(); + bar(); + } +} + +constant_switch_3: { + options = { dead_code: true, evaluate: true }; + input: { + switch (10) { + case 1: foo(); + case 1+1: bar(); break; + case 1+1+1: baz(); + default: + def(); + } + } + expect: { + def(); + } +} + +constant_switch_4: { + options = { dead_code: true, evaluate: true }; + input: { + switch (2) { + case 1: + x(); + if (foo) break; + y(); + break; + case 1+1: + bar(); + default: + def(); + } + } + expect: { + bar(); + def(); + } +} + +constant_switch_5: { + options = { dead_code: true, evaluate: true }; + input: { + switch (1) { + case 1: + x(); + if (foo) break; + y(); + break; + case 1+1: + bar(); + default: + def(); + } + } + expect: { + // the break inside the if ruins our job + // we can still get rid of irrelevant cases. + switch (1) { + case 1: + x(); + if (foo) break; + y(); + } + // XXX: we could optimize this better by inventing an outer + // labeled block, but that's kinda tricky. + } +} + +constant_switch_6: { + options = { dead_code: true, evaluate: true }; + input: { + OUT: { + foo(); + switch (1) { + case 1: + x(); + if (foo) break OUT; + y(); + case 1+1: + bar(); + break; + default: + def(); + } + } + } + expect: { + OUT: { + foo(); + x(); + if (foo) break OUT; + y(); + bar(); + } + } +} + +constant_switch_7: { + options = { dead_code: true, evaluate: true }; + input: { + OUT: { + foo(); + switch (1) { + case 1: + x(); + if (foo) break OUT; + for (var x = 0; x < 10; x++) { + if (x > 5) break; // this break refers to the for, not to the switch; thus it + // shouldn't ruin our optimization + console.log(x); + } + y(); + case 1+1: + bar(); + break; + default: + def(); + } + } + } + expect: { + OUT: { + foo(); + x(); + if (foo) break OUT; + for (var x = 0; x < 10; x++) { + if (x > 5) break; + console.log(x); + } + y(); + bar(); + } + } +} + +constant_switch_8: { + options = { dead_code: true, evaluate: true }; + input: { + OUT: switch (1) { + case 1: + x(); + for (;;) break OUT; + y(); + break; + case 1+1: + bar(); + default: + def(); + } + } + expect: { + OUT: { + x(); + for (;;) break OUT; + y(); + } + } +} + +constant_switch_9: { + options = { dead_code: true, evaluate: true }; + input: { + OUT: switch (1) { + case 1: + x(); + for (;;) if (foo) break OUT; + y(); + case 1+1: + bar(); + default: + def(); + } + } + expect: { + OUT: { + x(); + for (;;) if (foo) break OUT; + y(); + bar(); + def(); + } + } +} + +drop_default_1: { + options = { dead_code: true }; + input: { + switch (foo) { + case 'bar': baz(); + default: + } + } + expect: { + switch (foo) { + case 'bar': baz(); + } + } +} + +drop_default_2: { + options = { dead_code: true }; + input: { + switch (foo) { + case 'bar': baz(); break; + default: + break; + } + } + expect: { + switch (foo) { + case 'bar': baz(); + } + } +} + +keep_default: { + options = { dead_code: true }; + input: { + switch (foo) { + case 'bar': baz(); + default: + something(); + break; + } + } + expect: { + switch (foo) { + case 'bar': baz(); + default: + something(); + } + } +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/typeof.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/typeof.js new file mode 100644 index 0000000..cefdd43 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/compress/typeof.js @@ -0,0 +1,25 @@ +typeof_evaluation: { + options = { + evaluate: true + }; + input: { + a = typeof 1; + b = typeof 'test'; + c = typeof []; + d = typeof {}; + e = typeof /./; + f = typeof false; + g = typeof function(){}; + h = typeof undefined; + } + expect: { + a='number'; + b='string'; + c=typeof[]; + d=typeof{}; + e=typeof/./; + f='boolean'; + g='function'; + h='undefined'; + } +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/run-tests.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/run-tests.js new file mode 100755 index 0000000..f8e88d4 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/test/run-tests.js @@ -0,0 +1,179 @@ +#! /usr/bin/env node + +var U = require("../tools/node"); +var path = require("path"); +var fs = require("fs"); +var assert = require("assert"); +var sys = require("util"); + +var tests_dir = path.dirname(module.filename); +var failures = 0; +var failed_files = {}; + +run_compress_tests(); +if (failures) { + sys.error("\n!!! Failed " + failures + " test cases."); + sys.error("!!! " + Object.keys(failed_files).join(", ")); + process.exit(1); +} + +/* -----[ utils ]----- */ + +function tmpl() { + return U.string_template.apply(this, arguments); +} + +function log() { + var txt = tmpl.apply(this, arguments); + sys.puts(txt); +} + +function log_directory(dir) { + log("*** Entering [{dir}]", { dir: dir }); +} + +function log_start_file(file) { + log("--- {file}", { file: file }); +} + +function log_test(name) { + log(" Running test [{name}]", { name: name }); +} + +function find_test_files(dir) { + var files = fs.readdirSync(dir).filter(function(name){ + return /\.js$/i.test(name); + }); + if (process.argv.length > 2) { + var x = process.argv.slice(2); + files = files.filter(function(f){ + return x.indexOf(f) >= 0; + }); + } + return files; +} + +function test_directory(dir) { + return path.resolve(tests_dir, dir); +} + +function as_toplevel(input) { + if (input instanceof U.AST_BlockStatement) input = input.body; + else if (input instanceof U.AST_Statement) input = [ input ]; + else throw new Error("Unsupported input syntax"); + var toplevel = new U.AST_Toplevel({ body: input }); + toplevel.figure_out_scope(); + return toplevel; +} + +function run_compress_tests() { + var dir = test_directory("compress"); + log_directory("compress"); + var files = find_test_files(dir); + function test_file(file) { + log_start_file(file); + function test_case(test) { + log_test(test.name); + var options = U.defaults(test.options, { + warnings: false + }); + var cmp = new U.Compressor(options, true); + var expect = make_code(as_toplevel(test.expect), false); + var input = as_toplevel(test.input); + var input_code = make_code(test.input); + var output = input.transform(cmp); + output.figure_out_scope(); + output = make_code(output, false); + if (expect != output) { + log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", { + input: input_code, + output: output, + expected: expect + }); + failures++; + failed_files[file] = 1; + } + } + var tests = parse_test(path.resolve(dir, file)); + for (var i in tests) if (tests.hasOwnProperty(i)) { + test_case(tests[i]); + } + } + files.forEach(function(file){ + test_file(file); + }); +} + +function parse_test(file) { + var script = fs.readFileSync(file, "utf8"); + var ast = U.parse(script, { + filename: file + }); + var tests = {}; + var tw = new U.TreeWalker(function(node, descend){ + if (node instanceof U.AST_LabeledStatement + && tw.parent() instanceof U.AST_Toplevel) { + var name = node.label.name; + tests[name] = get_one_test(name, node.body); + return true; + } + if (!(node instanceof U.AST_Toplevel)) croak(node); + }); + ast.walk(tw); + return tests; + + function croak(node) { + throw new Error(tmpl("Can't understand test file {file} [{line},{col}]\n{code}", { + file: file, + line: node.start.line, + col: node.start.col, + code: make_code(node, false) + })); + } + + function get_one_test(name, block) { + var test = { name: name, options: {} }; + var tw = new U.TreeWalker(function(node, descend){ + if (node instanceof U.AST_Assign) { + if (!(node.left instanceof U.AST_SymbolRef)) { + croak(node); + } + var name = node.left.name; + test[name] = evaluate(node.right); + return true; + } + if (node instanceof U.AST_LabeledStatement) { + assert.ok( + node.label.name == "input" || node.label.name == "expect", + tmpl("Unsupported label {name} [{line},{col}]", { + name: node.label.name, + line: node.label.start.line, + col: node.label.start.col + }) + ); + var stat = node.body; + if (stat instanceof U.AST_BlockStatement) { + if (stat.body.length == 1) stat = stat.body[0]; + else if (stat.body.length == 0) stat = new U.AST_EmptyStatement(); + } + test[node.label.name] = stat; + return true; + } + }); + block.walk(tw); + return test; + }; +} + +function make_code(ast, beautify) { + if (arguments.length == 1) beautify = true; + var stream = U.OutputStream({ beautify: beautify }); + ast.print(stream); + return stream.get(); +} + +function evaluate(code) { + if (code instanceof U.AST_Node) + code = make_code(code); + return new Function("return(" + code + ")")(); +} diff --git a/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/tools/node.js b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/tools/node.js new file mode 100644 index 0000000..614e083 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/node_modules/uglify-js/tools/node.js @@ -0,0 +1,167 @@ +var path = require("path"); +var fs = require("fs"); +var vm = require("vm"); +var sys = require("util"); + +var UglifyJS = vm.createContext({ + sys : sys, + console : console, + MOZ_SourceMap : require("source-map") +}); + +function load_global(file) { + file = path.resolve(path.dirname(module.filename), file); + try { + var code = fs.readFileSync(file, "utf8"); + return vm.runInContext(code, UglifyJS, file); + } catch(ex) { + // XXX: in case of a syntax error, the message is kinda + // useless. (no location information). + sys.debug("ERROR in file: " + file + " / " + ex); + process.exit(1); + } +}; + +var FILES = exports.FILES = [ + "../lib/utils.js", + "../lib/ast.js", + "../lib/parse.js", + "../lib/transform.js", + "../lib/scope.js", + "../lib/output.js", + "../lib/compress.js", + "../lib/sourcemap.js", + "../lib/mozilla-ast.js" +].map(function(file){ + return path.join(path.dirname(fs.realpathSync(__filename)), file); +}); + +FILES.forEach(load_global); + +UglifyJS.AST_Node.warn_function = function(txt) { + sys.error("WARN: " + txt); +}; + +// XXX: perhaps we shouldn't export everything but heck, I'm lazy. +for (var i in UglifyJS) { + if (UglifyJS.hasOwnProperty(i)) { + exports[i] = UglifyJS[i]; + } +} + +exports.minify = function(files, options) { + options = UglifyJS.defaults(options, { + outSourceMap : null, + sourceRoot : null, + inSourceMap : null, + fromString : false, + warnings : false, + mangle : {}, + output : null, + compress : {} + }); + if (typeof files == "string") + files = [ files ]; + + UglifyJS.base54.reset(); + + // 1. parse + var toplevel = null; + files.forEach(function(file){ + var code = options.fromString + ? file + : fs.readFileSync(file, "utf8"); + toplevel = UglifyJS.parse(code, { + filename: options.fromString ? "?" : file, + toplevel: toplevel + }); + }); + + // 2. compress + if (options.compress) { + var compress = { warnings: options.warnings }; + UglifyJS.merge(compress, options.compress); + toplevel.figure_out_scope(); + var sq = UglifyJS.Compressor(compress); + toplevel = toplevel.transform(sq); + } + + // 3. mangle + if (options.mangle) { + toplevel.figure_out_scope(); + toplevel.compute_char_frequency(); + toplevel.mangle_names(options.mangle); + } + + // 4. output + var inMap = options.inSourceMap; + var output = {}; + if (typeof options.inSourceMap == "string") { + inMap = fs.readFileSync(options.inSourceMap, "utf8"); + } + if (options.outSourceMap) { + output.source_map = UglifyJS.SourceMap({ + file: options.outSourceMap, + orig: inMap, + root: options.sourceRoot + }); + } + if (options.output) { + UglifyJS.merge(output, options.output); + } + var stream = UglifyJS.OutputStream(output); + toplevel.print(stream); + return { + code : stream + "", + map : output.source_map + "" + }; +}; + +// exports.describe_ast = function() { +// function doitem(ctor) { +// var sub = {}; +// ctor.SUBCLASSES.forEach(function(ctor){ +// sub[ctor.TYPE] = doitem(ctor); +// }); +// var ret = {}; +// if (ctor.SELF_PROPS.length > 0) ret.props = ctor.SELF_PROPS; +// if (ctor.SUBCLASSES.length > 0) ret.sub = sub; +// return ret; +// } +// return doitem(UglifyJS.AST_Node).sub; +// } + +exports.describe_ast = function() { + var out = UglifyJS.OutputStream({ beautify: true }); + function doitem(ctor) { + out.print("AST_" + ctor.TYPE); + var props = ctor.SELF_PROPS.filter(function(prop){ + return !/^\$/.test(prop); + }); + if (props.length > 0) { + out.space(); + out.with_parens(function(){ + props.forEach(function(prop, i){ + if (i) out.space(); + out.print(prop); + }); + }); + } + if (ctor.documentation) { + out.space(); + out.print_string(ctor.documentation); + } + if (ctor.SUBCLASSES.length > 0) { + out.space(); + out.with_block(function(){ + ctor.SUBCLASSES.forEach(function(ctor, i){ + out.indent(); + doitem(ctor); + out.newline(); + }); + }); + } + }; + doitem(UglifyJS.AST_Node); + return out + ""; +}; diff --git a/node_modules/jade/node_modules/constantinople/package.json b/node_modules/jade/node_modules/constantinople/package.json new file mode 100644 index 0000000..dac8d36 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/package.json @@ -0,0 +1,34 @@ +{ + "name": "constantinople", + "version": "1.0.2", + "description": "Determine whether a JavaScript expression evaluates to a constant (using UglifyJS)", + "keywords": [], + "dependencies": { + "uglify-js": "~2.4.0" + }, + "devDependencies": { + "mocha": "*" + }, + "scripts": { + "test": "mocha -R spec" + }, + "repository": { + "type": "git", + "url": "https://github.com/ForbesLindesay/constantinople.git" + }, + "author": { + "name": "ForbesLindesay" + }, + "license": "MIT", + "readme": "# constantinople\r\n\r\nDetermine whether a JavaScript expression evaluates to a constant (using UglifyJS). Here it is assumed to be safe to underestimate how constant something is.\r\n\r\n[![Build Status](https://travis-ci.org/ForbesLindesay/constantinople.png?branch=master)](https://travis-ci.org/ForbesLindesay/constantinople)\r\n[![Dependency Status](https://gemnasium.com/ForbesLindesay/constantinople.png)](https://gemnasium.com/ForbesLindesay/constantinople)\r\n[![NPM version](https://badge.fury.io/js/constantinople.png)](http://badge.fury.io/js/constantinople)\r\n\r\n## Installation\r\n\r\n npm install constantinople\r\n\r\n## Usage\r\n\r\n```js\r\nvar isConstant = require('constantinople')\r\n\r\nif (isConstant('\"foo\" + 5')) {\r\n console.dir(isConstant.toConstant('\"foo\" + 5'))\r\n}\r\n```\r\n\r\n## API\r\n\r\n### isConstant(src)\r\n\r\nReturns `true` if `src` evaluates to a constant, `false` otherwise. It will also return `false` if there is a syntax error, which makes it safe to use on potentially ES6 code.\r\n\r\n### toConstant(src)\r\n\r\nReturns the value resulting from evaluating `src`. This method throws an error if the expression is not constant. e.g. `toConstant(\"Math.random()\")` would throw an error.\r\n\r\n## License\r\n\r\n MIT", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/ForbesLindesay/constantinople/issues" + }, + "_id": "constantinople@1.0.2", + "dist": { + "shasum": "100ac7a4cad9405bbcfd01e34d3bc2ae31aff184" + }, + "_from": "constantinople@~1.0.1", + "_resolved": "https://registry.npmjs.org/constantinople/-/constantinople-1.0.2.tgz" +} diff --git a/node_modules/jade/node_modules/constantinople/test/index.js b/node_modules/jade/node_modules/constantinople/test/index.js new file mode 100644 index 0000000..e652bd8 --- /dev/null +++ b/node_modules/jade/node_modules/constantinople/test/index.js @@ -0,0 +1,51 @@ +'use strict' + +var assert = require('assert') +var constaninople = require('../') + +describe('isConstant(src)', function () { + it('handles "[5 + 3 + 10]"', function () { + assert(constaninople.isConstant('[5 + 3 + 10]') === true) + }) + it('handles "/[a-z]/.test(\'a\')"', function () { + assert(constaninople.isConstant('/[a-z]/.test(\'a\')') === true) + }) + it('handles "{\'class\': [(\'data\')]}"', function () { + assert(constaninople.isConstant('{\'class\': [(\'data\')]}') === true) + }) + it('handles "Math.random()"', function () { + assert(constaninople.isConstant('Math.random()') === false) + }) + it('handles "Math.random("', function () { + assert(constaninople.isConstant('Math.random(') === false) + }) +}) + + +describe('toConstant(src)', function () { + it('handles "[5 + 3 + 10]"', function () { + assert.deepEqual(constaninople.toConstant('[5 + 3 + 10]'), [5 + 3 + 10]) + }) + it('handles "/[a-z]/.test(\'a\')"', function () { + assert(constaninople.toConstant('/[a-z]/.test(\'a\')') === true) + }) + it('handles "{\'class\': [(\'data\')]}"', function () { + assert.deepEqual(constaninople.toConstant('{\'class\': [(\'data\')]}'), {'class': ['data']}) + }) + it('handles "Math.random()"', function () { + try { + constaninople.toConstant('Math.random()') + } catch (ex) { + return + } + assert(false, 'Math.random() should result in an error') + }) + it('handles "Math.random("', function () { + try { + constaninople.toConstant('Math.random(') + } catch (ex) { + return + } + assert(false, 'Math.random( should result in an error') + }) +}) \ No newline at end of file diff --git a/node_modules/jade/node_modules/mkdirp/.npmignore b/node_modules/jade/node_modules/mkdirp/.npmignore new file mode 100644 index 0000000..9303c34 --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/.npmignore @@ -0,0 +1,2 @@ +node_modules/ +npm-debug.log \ No newline at end of file diff --git a/node_modules/jade/node_modules/mkdirp/.travis.yml b/node_modules/jade/node_modules/mkdirp/.travis.yml new file mode 100644 index 0000000..84fd7ca --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - 0.6 + - 0.8 + - 0.9 diff --git a/node_modules/jade/node_modules/mkdirp/LICENSE b/node_modules/jade/node_modules/mkdirp/LICENSE new file mode 100644 index 0000000..432d1ae --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/LICENSE @@ -0,0 +1,21 @@ +Copyright 2010 James Halliday (mail@substack.net) + +This project is free software released under the MIT/X11 license: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/jade/node_modules/mkdirp/examples/pow.js b/node_modules/jade/node_modules/mkdirp/examples/pow.js new file mode 100644 index 0000000..e692421 --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/examples/pow.js @@ -0,0 +1,6 @@ +var mkdirp = require('mkdirp'); + +mkdirp('/tmp/foo/bar/baz', function (err) { + if (err) console.error(err) + else console.log('pow!') +}); diff --git a/node_modules/jade/node_modules/mkdirp/index.js b/node_modules/jade/node_modules/mkdirp/index.js new file mode 100644 index 0000000..fda6de8 --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/index.js @@ -0,0 +1,82 @@ +var path = require('path'); +var fs = require('fs'); + +module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP; + +function mkdirP (p, mode, f, made) { + if (typeof mode === 'function' || mode === undefined) { + f = mode; + mode = 0777 & (~process.umask()); + } + if (!made) made = null; + + var cb = f || function () {}; + if (typeof mode === 'string') mode = parseInt(mode, 8); + p = path.resolve(p); + + fs.mkdir(p, mode, function (er) { + if (!er) { + made = made || p; + return cb(null, made); + } + switch (er.code) { + case 'ENOENT': + mkdirP(path.dirname(p), mode, function (er, made) { + if (er) cb(er, made); + else mkdirP(p, mode, cb, made); + }); + break; + + // In the case of any other error, just see if there's a dir + // there already. If so, then hooray! If not, then something + // is borked. + default: + fs.stat(p, function (er2, stat) { + // if the stat fails, then that's super weird. + // let the original error be the failure reason. + if (er2 || !stat.isDirectory()) cb(er, made) + else cb(null, made); + }); + break; + } + }); +} + +mkdirP.sync = function sync (p, mode, made) { + if (mode === undefined) { + mode = 0777 & (~process.umask()); + } + if (!made) made = null; + + if (typeof mode === 'string') mode = parseInt(mode, 8); + p = path.resolve(p); + + try { + fs.mkdirSync(p, mode); + made = made || p; + } + catch (err0) { + switch (err0.code) { + case 'ENOENT' : + made = sync(path.dirname(p), mode, made); + sync(p, mode, made); + break; + + // In the case of any other error, just see if there's a dir + // there already. If so, then hooray! If not, then something + // is borked. + default: + var stat; + try { + stat = fs.statSync(p); + } + catch (err1) { + throw err0; + } + if (!stat.isDirectory()) throw err0; + break; + } + } + + return made; +}; diff --git a/node_modules/jade/node_modules/mkdirp/package.json b/node_modules/jade/node_modules/mkdirp/package.json new file mode 100644 index 0000000..bd9194b --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/package.json @@ -0,0 +1,33 @@ +{ + "name": "mkdirp", + "description": "Recursively mkdir, like `mkdir -p`", + "version": "0.3.5", + "author": { + "name": "James Halliday", + "email": "mail@substack.net", + "url": "http://substack.net" + }, + "main": "./index", + "keywords": [ + "mkdir", + "directory" + ], + "repository": { + "type": "git", + "url": "http://github.com/substack/node-mkdirp.git" + }, + "scripts": { + "test": "tap test/*.js" + }, + "devDependencies": { + "tap": "~0.4.0" + }, + "license": "MIT", + "readme": "# mkdirp\n\nLike `mkdir -p`, but in node.js!\n\n[![build status](https://secure.travis-ci.org/substack/node-mkdirp.png)](http://travis-ci.org/substack/node-mkdirp)\n\n# example\n\n## pow.js\n\n```js\nvar mkdirp = require('mkdirp');\n \nmkdirp('/tmp/foo/bar/baz', function (err) {\n if (err) console.error(err)\n else console.log('pow!')\n});\n```\n\nOutput\n\n```\npow!\n```\n\nAnd now /tmp/foo/bar/baz exists, huzzah!\n\n# methods\n\n```js\nvar mkdirp = require('mkdirp');\n```\n\n## mkdirp(dir, mode, cb)\n\nCreate a new directory and any necessary subdirectories at `dir` with octal\npermission string `mode`.\n\nIf `mode` isn't specified, it defaults to `0777 & (~process.umask())`.\n\n`cb(err, made)` fires with the error or the first directory `made`\nthat had to be created, if any.\n\n## mkdirp.sync(dir, mode)\n\nSynchronously create a new directory and any necessary subdirectories at `dir`\nwith octal permission string `mode`.\n\nIf `mode` isn't specified, it defaults to `0777 & (~process.umask())`.\n\nReturns the first directory that had to be created, if any.\n\n# install\n\nWith [npm](http://npmjs.org) do:\n\n```\nnpm install mkdirp\n```\n\n# license\n\nMIT\n", + "readmeFilename": "readme.markdown", + "bugs": { + "url": "https://github.com/substack/node-mkdirp/issues" + }, + "_id": "mkdirp@0.3.5", + "_from": "mkdirp@0.3.x" +} diff --git a/node_modules/jade/node_modules/mkdirp/readme.markdown b/node_modules/jade/node_modules/mkdirp/readme.markdown new file mode 100644 index 0000000..83b0216 --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/readme.markdown @@ -0,0 +1,63 @@ +# mkdirp + +Like `mkdir -p`, but in node.js! + +[![build status](https://secure.travis-ci.org/substack/node-mkdirp.png)](http://travis-ci.org/substack/node-mkdirp) + +# example + +## pow.js + +```js +var mkdirp = require('mkdirp'); + +mkdirp('/tmp/foo/bar/baz', function (err) { + if (err) console.error(err) + else console.log('pow!') +}); +``` + +Output + +``` +pow! +``` + +And now /tmp/foo/bar/baz exists, huzzah! + +# methods + +```js +var mkdirp = require('mkdirp'); +``` + +## mkdirp(dir, mode, cb) + +Create a new directory and any necessary subdirectories at `dir` with octal +permission string `mode`. + +If `mode` isn't specified, it defaults to `0777 & (~process.umask())`. + +`cb(err, made)` fires with the error or the first directory `made` +that had to be created, if any. + +## mkdirp.sync(dir, mode) + +Synchronously create a new directory and any necessary subdirectories at `dir` +with octal permission string `mode`. + +If `mode` isn't specified, it defaults to `0777 & (~process.umask())`. + +Returns the first directory that had to be created, if any. + +# install + +With [npm](http://npmjs.org) do: + +``` +npm install mkdirp +``` + +# license + +MIT diff --git a/node_modules/jade/node_modules/mkdirp/test/chmod.js b/node_modules/jade/node_modules/mkdirp/test/chmod.js new file mode 100644 index 0000000..520dcb8 --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/test/chmod.js @@ -0,0 +1,38 @@ +var mkdirp = require('../').mkdirp; +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +var ps = [ '', 'tmp' ]; + +for (var i = 0; i < 25; i++) { + var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + ps.push(dir); +} + +var file = ps.join('/'); + +test('chmod-pre', function (t) { + var mode = 0744 + mkdirp(file, mode, function (er) { + t.ifError(er, 'should not error'); + fs.stat(file, function (er, stat) { + t.ifError(er, 'should exist'); + t.ok(stat && stat.isDirectory(), 'should be directory'); + t.equal(stat && stat.mode & 0777, mode, 'should be 0744'); + t.end(); + }); + }); +}); + +test('chmod', function (t) { + var mode = 0755 + mkdirp(file, mode, function (er) { + t.ifError(er, 'should not error'); + fs.stat(file, function (er, stat) { + t.ifError(er, 'should exist'); + t.ok(stat && stat.isDirectory(), 'should be directory'); + t.end(); + }); + }); +}); diff --git a/node_modules/jade/node_modules/mkdirp/test/clobber.js b/node_modules/jade/node_modules/mkdirp/test/clobber.js new file mode 100644 index 0000000..0eb7099 --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/test/clobber.js @@ -0,0 +1,37 @@ +var mkdirp = require('../').mkdirp; +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +var ps = [ '', 'tmp' ]; + +for (var i = 0; i < 25; i++) { + var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + ps.push(dir); +} + +var file = ps.join('/'); + +// a file in the way +var itw = ps.slice(0, 3).join('/'); + + +test('clobber-pre', function (t) { + console.error("about to write to "+itw) + fs.writeFileSync(itw, 'I AM IN THE WAY, THE TRUTH, AND THE LIGHT.'); + + fs.stat(itw, function (er, stat) { + t.ifError(er) + t.ok(stat && stat.isFile(), 'should be file') + t.end() + }) +}) + +test('clobber', function (t) { + t.plan(2); + mkdirp(file, 0755, function (err) { + t.ok(err); + t.equal(err.code, 'ENOTDIR'); + t.end(); + }); +}); diff --git a/node_modules/jade/node_modules/mkdirp/test/mkdirp.js b/node_modules/jade/node_modules/mkdirp/test/mkdirp.js new file mode 100644 index 0000000..b07cd70 --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/test/mkdirp.js @@ -0,0 +1,28 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('woo', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); diff --git a/node_modules/jade/node_modules/mkdirp/test/perm.js b/node_modules/jade/node_modules/mkdirp/test/perm.js new file mode 100644 index 0000000..23a7abb --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/test/perm.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('async perm', function (t) { + t.plan(2); + var file = '/tmp/' + (Math.random() * (1<<30)).toString(16); + + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); + +test('async root perm', function (t) { + mkdirp('/tmp', 0755, function (err) { + if (err) t.fail(err); + t.end(); + }); + t.end(); +}); diff --git a/node_modules/jade/node_modules/mkdirp/test/perm_sync.js b/node_modules/jade/node_modules/mkdirp/test/perm_sync.js new file mode 100644 index 0000000..f685f60 --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/test/perm_sync.js @@ -0,0 +1,39 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('sync perm', function (t) { + t.plan(2); + var file = '/tmp/' + (Math.random() * (1<<30)).toString(16) + '.json'; + + mkdirp.sync(file, 0755); + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }); +}); + +test('sync root perm', function (t) { + t.plan(1); + + var file = '/tmp'; + mkdirp.sync(file, 0755); + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }); +}); diff --git a/node_modules/jade/node_modules/mkdirp/test/race.js b/node_modules/jade/node_modules/mkdirp/test/race.js new file mode 100644 index 0000000..96a0447 --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/test/race.js @@ -0,0 +1,41 @@ +var mkdirp = require('../').mkdirp; +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('race', function (t) { + t.plan(4); + var ps = [ '', 'tmp' ]; + + for (var i = 0; i < 25; i++) { + var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + ps.push(dir); + } + var file = ps.join('/'); + + var res = 2; + mk(file, function () { + if (--res === 0) t.end(); + }); + + mk(file, function () { + if (--res === 0) t.end(); + }); + + function mk (file, cb) { + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + if (cb) cb(); + } + }) + }) + }); + } +}); diff --git a/node_modules/jade/node_modules/mkdirp/test/rel.js b/node_modules/jade/node_modules/mkdirp/test/rel.js new file mode 100644 index 0000000..7985824 --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/test/rel.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('rel', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var cwd = process.cwd(); + process.chdir('/tmp'); + + var file = [x,y,z].join('/'); + + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + process.chdir(cwd); + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); diff --git a/node_modules/jade/node_modules/mkdirp/test/return.js b/node_modules/jade/node_modules/mkdirp/test/return.js new file mode 100644 index 0000000..bce68e5 --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/test/return.js @@ -0,0 +1,25 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('return value', function (t) { + t.plan(4); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + // should return the first dir created. + // By this point, it would be profoundly surprising if /tmp didn't + // already exist, since every other test makes things in there. + mkdirp(file, function (err, made) { + t.ifError(err); + t.equal(made, '/tmp/' + x); + mkdirp(file, function (err, made) { + t.ifError(err); + t.equal(made, null); + }); + }); +}); diff --git a/node_modules/jade/node_modules/mkdirp/test/return_sync.js b/node_modules/jade/node_modules/mkdirp/test/return_sync.js new file mode 100644 index 0000000..7c222d3 --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/test/return_sync.js @@ -0,0 +1,24 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('return value', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + // should return the first dir created. + // By this point, it would be profoundly surprising if /tmp didn't + // already exist, since every other test makes things in there. + // Note that this will throw on failure, which will fail the test. + var made = mkdirp.sync(file); + t.equal(made, '/tmp/' + x); + + // making the same file again should have no effect. + made = mkdirp.sync(file); + t.equal(made, null); +}); diff --git a/node_modules/jade/node_modules/mkdirp/test/root.js b/node_modules/jade/node_modules/mkdirp/test/root.js new file mode 100644 index 0000000..97ad7a2 --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/test/root.js @@ -0,0 +1,18 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('root', function (t) { + // '/' on unix, 'c:/' on windows. + var file = path.resolve('/'); + + mkdirp(file, 0755, function (err) { + if (err) throw err + fs.stat(file, function (er, stat) { + if (er) throw er + t.ok(stat.isDirectory(), 'target is a directory'); + t.end(); + }) + }); +}); diff --git a/node_modules/jade/node_modules/mkdirp/test/sync.js b/node_modules/jade/node_modules/mkdirp/test/sync.js new file mode 100644 index 0000000..7530cad --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/test/sync.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('sync', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + try { + mkdirp.sync(file, 0755); + } catch (err) { + t.fail(err); + return t.end(); + } + + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }); + }); +}); diff --git a/node_modules/jade/node_modules/mkdirp/test/umask.js b/node_modules/jade/node_modules/mkdirp/test/umask.js new file mode 100644 index 0000000..64ccafe --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/test/umask.js @@ -0,0 +1,28 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('implicit mode from umask', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + mkdirp(file, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0777 & (~process.umask())); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); diff --git a/node_modules/jade/node_modules/mkdirp/test/umask_sync.js b/node_modules/jade/node_modules/mkdirp/test/umask_sync.js new file mode 100644 index 0000000..35bd5cb --- /dev/null +++ b/node_modules/jade/node_modules/mkdirp/test/umask_sync.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('umask sync modes', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + try { + mkdirp.sync(file); + } catch (err) { + t.fail(err); + return t.end(); + } + + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, (0777 & (~process.umask()))); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }); + }); +}); diff --git a/node_modules/jade/node_modules/monocle/.npmignore b/node_modules/jade/node_modules/monocle/.npmignore new file mode 100644 index 0000000..28f1ba7 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/.npmignore @@ -0,0 +1,2 @@ +node_modules +.DS_Store \ No newline at end of file diff --git a/node_modules/jade/node_modules/monocle/.travis.yml b/node_modules/jade/node_modules/monocle/.travis.yml new file mode 100644 index 0000000..18ae2d8 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - "0.11" + - "0.10" diff --git a/node_modules/jade/node_modules/monocle/LICENSE b/node_modules/jade/node_modules/monocle/LICENSE new file mode 100644 index 0000000..417af37 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2013, Sam Saccone +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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. diff --git a/node_modules/jade/node_modules/monocle/README.md b/node_modules/jade/node_modules/monocle/README.md new file mode 100644 index 0000000..2ca4e7c --- /dev/null +++ b/node_modules/jade/node_modules/monocle/README.md @@ -0,0 +1,80 @@ +[![Build Status](https://travis-ci.org/samccone/monocle.png?branch=master)](https://travis-ci.org/samccone/monocle) + +# Monocle -- a tool for watching things + +[![logo](https://raw.github.com/samccone/monocle/master/logo.png)](https://raw.github.com/samccone/monocle/master/logo.png) + +Have you ever wanted to watch a folder and all of its files/nested folders for changes. well now you can! + +## Installation + +``` +npm install monocle +``` + +## Usage + +### Watch a directory: + +```js +var monocle = require('monocle')() +monocle.watchDirectory({ + root: , + fileFilter: , + directoryFilter: , + listener: fn(fs.stat+ object), //triggered on file change / addition + complete: //file watching all set up +}); +``` + +The listener will recive an object with the following + +```js + name: , + path: , + fullPath: , + parentDir: , + fullParentDir: , + stat: +``` + +[fs.stats](http://nodejs.org/api/fs.html#fs_class_fs_stats) + +When a new file is added to the directoy it triggers a file change and thus will be passed to your specified listener. + +The two filters are passed through to `readdirp`. More documentation can be found [here](https://github.com/thlorenz/readdirp#filters) + +### Watch a list of files: + +```js +Monocle.watchFiles({ + files: [], //path of file(s) + listener: , //triggered on file / addition + complete: //file watching all set up +}); +``` + +### Just watch path + +Just an alias of `watchFiles` and `watchDirectory` so you don't need to tell if that's a file or a directory by yourself. Parameter passed to `path` can be a `string` or a `array` of `string`. + +```js +Monocle.watchPaths({ + path: [], //list of paths, or a string of path + fileFilter: , // `*.js` for example + listener: , //triggered on file / addition + complete: //file watching all set up +}); +``` + +## Why not just use fs.watch ? + + - file watching is really bad cross platforms in node + - you need to be smart when using fs.watch as compared to fs.watchFile + - Monocle takes care of this logic for you! + - windows systems use fs.watch + - osx and linux uses fs.watchFile + +## License + +BSD diff --git a/node_modules/jade/node_modules/monocle/logo.png b/node_modules/jade/node_modules/monocle/logo.png new file mode 100644 index 0000000..39d665f Binary files /dev/null and b/node_modules/jade/node_modules/monocle/logo.png differ diff --git a/node_modules/jade/node_modules/monocle/monocle.js b/node_modules/jade/node_modules/monocle/monocle.js new file mode 100644 index 0000000..7ec4d98 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/monocle.js @@ -0,0 +1,187 @@ +var path = require('path'); +var fs = require('fs'); +var readdirp = require('readdirp'); +var is_windows = process.platform === 'win32'; + +module.exports = function() { + var watched_files = {}; + var watched_directories = {}; + var check_dir_pause = 1000; + var checkInterval = undefined; + + // @api public + // Watches the directory passed and its contained files + // accepts args as an object. + + // @param root(string): the root directory to watch + // @param fileFilter(array): ignore these files + // @param directoryFilter(array): ignore these files + // @param listener(fn(file)): on file change event this will be called + // @param complete(fn): on complete of file watching setup + function watchDirectory(args) { + readdirp({ root: args.root, fileFilter: args.fileFilter, directoryFilter: args.directoryFilter }, function(err, res) { + res.files.forEach(function(file) { + watchFile(file, args.listener, args.partial); + }); + typeof args.complete == "function" && args.complete(); + }); + + !args.partial && (checkInterval = setInterval(function() {checkDirectory(args)}, check_dir_pause)); + } + + // @api public + // Watches the files passed + // accepts args as an object. + // @param files(array): a list of files to watch + // @param listener(fn(file)): on file change event this will be called + // @param complete(fn): on complete of file watching setup + function watchFiles(args) { + args.files.forEach(function(file) { + var o = { + fullPath: fs.realpathSync(file), + name: fs.realpathSync(file).split('/').pop() + }; + o.fullParentDir = o.fullPath.split('/').slice(0, o.fullPath.split('/').length - 1).join('/') + + watchFile(o, args.listener); + }); + + typeof args.complete == "function" && args.complete(); + } + + function unwatchAll() { + if (is_windows) { + Object.keys(watched_files).forEach(function(key) { + watched_files[key].close(); + }); + } else { + Object.keys(watched_files).forEach(function(key) { + fs.unwatchFile(key); + }); + } + + clearInterval(checkInterval); + watched_files = {}; + watched_directories = {}; + } + + // Checks to see if something in the directory has changed + function checkDirectory(args) { + Object.keys(watched_directories).forEach(function(path) { + var lastModified = watched_directories[path]; + fs.stat(path, function(err, stats) { + var stats_stamp = lastModified; + if (!err) { + stats_stamp = (new Date(stats.mtime)).getTime(); + } + if (stats_stamp != lastModified) { + watched_directories[path] = stats_stamp; + watchDirectory({ + root: path, + listener: args.listener, + fileFilter: args.fileFilter, + directoryFilter: args.directoryFilter, + partial: true + }); + } + }); + }); + } + + // sets the absolute path to the file from the current working dir + function setAbsolutePath(file) { + file.absolutePath = path.resolve(process.cwd(), file.fullPath); + return file.absolutePath; + } + + // Watches the file passed and its containing directory + // on change calls given listener with file object + function watchFile(file, cb, partial) { + setAbsolutePath(file); + storeDirectory(file); + if (!watched_files[file.fullPath]) { + if (is_windows) { + (function() { + watched_files[file.fullPath] = fs.watch(file.fullPath, function() { + typeof cb === "function" && cb(file); + }); + partial && cb(file); + })(file, cb); + } else { + (function(file, cb) { + watched_files[file.fullPath] = true; + fs.watchFile(file.fullPath, {interval: 150}, function() { + typeof cb === "function" && cb(file); + }); + partial && cb(file); + })(file, cb); + } + } + } + + // Sets up a store of the folders being watched + // and saves the last modification timestamp for it + function storeDirectory(file) { + var directory = file.fullParentDir; + if (!watched_directories[directory]) { + fs.stat(directory, function(err, stats) { + if (err) { + watched_directories[directory] = (new Date).getTime(); + } else { + watched_directories[directory] = (new Date(stats.mtime)).getTime(); + } + }); + } + } + + // distinguish between files and directories + // @returns {Object} contains directories and files array + + function distinguishPaths(paths) { + paths = Array.isArray(paths) ? paths : [paths]; + var result = { + directories: [], + files: [] + }; + paths.forEach(function(name) { + if (fs.statSync(name).isDirectory()) { + result.directories.push(name); + } else { + result.files.push(name); + } + }); + return result; + }; + + // for functions accepts an object as paramter + // copy the object and modify with attributes + function extend(prototype, attributes) { + var object = {}; + Object.keys(prototype).forEach(function(key) { + object[key] = prototype[key]; + }); + Object.keys(attributes).forEach(function(key) { + object[key] = attributes[key]; + }); + return object; + }; + + // watch files if the paths refer to files, or directories + function watchPaths(args) { + var result = distinguishPaths(args.path) + if (result.directories.length) { + result.directories.forEach(function(directory) { + watchDirectory(extend(args, {root: directory})); + }); + } + if (result.files.length) + watchFiles(extend(args, {files: result.files})); + } + + return { + watchDirectory: watchDirectory, + watchFiles: watchFiles, + watchPaths: watchPaths, + unwatchAll: unwatchAll + }; +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/.npmignore b/node_modules/jade/node_modules/monocle/node_modules/readdirp/.npmignore new file mode 100644 index 0000000..7dccd97 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/.npmignore @@ -0,0 +1,15 @@ +lib-cov +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.gz + +pids +logs +results + +node_modules +npm-debug.log \ No newline at end of file diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/.travis.yml b/node_modules/jade/node_modules/monocle/node_modules/readdirp/.travis.yml new file mode 100644 index 0000000..84fd7ca --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - 0.6 + - 0.8 + - 0.9 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/LICENSE b/node_modules/jade/node_modules/monocle/node_modules/readdirp/LICENSE new file mode 100644 index 0000000..ee27ba4 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/LICENSE @@ -0,0 +1,18 @@ +This software is released under the MIT license: + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/README.md b/node_modules/jade/node_modules/monocle/node_modules/readdirp/README.md new file mode 100644 index 0000000..7b36a8a --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/README.md @@ -0,0 +1,227 @@ +# readdirp [![Build Status](https://secure.travis-ci.org/thlorenz/readdirp.png)](http://travis-ci.org/thlorenz/readdirp) + +Recursive version of [fs.readdir](http://nodejs.org/docs/latest/api/fs.html#fs_fs_readdir_path_callback). Exposes a **stream api**. + +```javascript +var readdirp = require('readdirp'); + , path = require('path') + , es = require('event-stream'); + +// print out all JavaScript files along with their size + +var stream = readdirp({ root: path.join(__dirname), fileFilter: '*.js' }); +stream + .on('warn', function (err) { + console.error('non-fatal error', err); + // optionally call stream.destroy() here in order to abort and cause 'close' to be emitted + }) + .on('error', function (err) { console.error('fatal error', err); }) + .pipe(es.mapSync(function (entry) { + return { path: entry.path, size: entry.stat.size }; + })) + .pipe(es.stringify()) + .pipe(process.stdout); +``` + +Meant to be one of the recursive versions of [fs](http://nodejs.org/docs/latest/api/fs.html) functions, e.g., like [mkdirp](https://github.com/substack/node-mkdirp). + +**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)* + +- [Installation](#installation) +- [API](#api) + - [entry stream](#entry-stream) + - [options](#options) + - [entry info](#entry-info) + - [Filters](#filters) + - [Callback API](#callback-api) + - [allProcessed ](#allprocessed) + - [fileProcessed](#fileprocessed) +- [More Examples](#more-examples) + - [stream api](#stream-api) + - [stream api pipe](#stream-api-pipe) + - [grep](#grep) + - [using callback api](#using-callback-api) + - [tests](#tests) + + +# Installation + + npm install readdirp + +# API + +***var entryStream = readdirp (options)*** + +Reads given root recursively and returns a `stream` of [entry info](#entry-info)s. + +## entry stream + +Behaves as follows: + +- `emit('data')` passes an [entry info](#entry-info) whenever one is found +- `emit('warn')` passes a non-fatal `Error` that prevents a file/directory from being processed (i.e., if it is + inaccessible to the user) +- `emit('error')` passes a fatal `Error` which also ends the stream (i.e., when illegal options where passed) +- `emit('end')` called when all entries were found and no more will be emitted (i.e., we are done) +- `emit('close')` called when the stream is destroyed via `stream.destroy()` (which could be useful if you want to + manually abort even on a non fatal error) - at that point the stream is no longer `readable` and no more entries, + warning or errors are emitted +- the stream is `paused` initially in order to allow `pipe` and `on` handlers be connected before data or errors are + emitted +- the stream is `resumed` automatically during the next event loop +- to learn more about streams, consult the [stream-handbook](https://github.com/substack/stream-handbook) + +## options + +- **root**: path in which to start reading and recursing into subdirectories + +- **fileFilter**: filter to include/exclude files found (see [Filters](#filters) for more) + +- **directoryFilter**: filter to include/exclude directories found and to recurse into (see [Filters](#filters) for more) + +- **depth**: depth at which to stop recursing even if more subdirectories are found + +## entry info + +Has the following properties: + +- **parentDir** : directory in which entry was found (relative to given root) +- **fullParentDir** : full path to parent directory +- **name** : name of the file/directory +- **path** : path to the file/directory (relative to given root) +- **fullPath** : full path to the file/directory found +- **stat** : built in [stat object](http://nodejs.org/docs/v0.4.9/api/fs.html#fs.Stats) +- **Example**: (assuming root was `/User/dev/readdirp`) + + parentDir : 'test/bed/root_dir1', + fullParentDir : '/User/dev/readdirp/test/bed/root_dir1', + name : 'root_dir1_subdir1', + path : 'test/bed/root_dir1/root_dir1_subdir1', + fullPath : '/User/dev/readdirp/test/bed/root_dir1/root_dir1_subdir1', + stat : [ ... ] + +## Filters + +There are three different ways to specify filters for files and directories respectively. + +- **function**: a function that takes an entry info as a parameter and returns true to include or false to exclude the entry + +- **glob string**: a string (e.g., `*.js`) which is matched using [minimatch](https://github.com/isaacs/minimatch), so go there for more + information. + + Globstars (`**`) are not supported since specifiying a recursive pattern for an already recursive function doesn't make sense. + + Negated globs (as explained in the minimatch documentation) are allowed, e.g., `!*.txt` matches everything but text files. + +- **array of glob strings**: either need to be all inclusive or all exclusive (negated) patterns otherwise an error is thrown. + + `[ '*.json', '*.js' ]` includes all JavaScript and Json files. + + + `[ '!.git', '!node_modules' ]` includes all directories except the '.git' and 'node_modules'. + +Directories that do not pass a filter will not be recursed into. + +## Callback API + +Although the stream api is recommended, readdirp also exposes a callback based api. + +***readdirp (options, callback1 [, callback2])*** + +If callback2 is given, callback1 functions as the **fileProcessed** callback, and callback2 as the **allProcessed** callback. + +If only callback1 is given, it functions as the **allProcessed** callback. + +### allProcessed + +- function with err and res parameters, e.g., `function (err, res) { ... }` +- **err**: array of errors that occurred during the operation, **res may still be present, even if errors occurred** +- **res**: collection of file/directory [entry infos](#entry-info) + +### fileProcessed + +- function with [entry info](#entry-info) parameter e.g., `function (entryInfo) { ... }` + + +# More Examples + +`on('error', ..)`, `on('warn', ..)` and `on('end', ..)` handling omitted for brevity + +```javascript +var readdirp = require('readdirp'); + +// Glob file filter +readdirp({ root: './test/bed', fileFilter: '*.js' }) + .on('data', function (entry) { + // do something with each JavaScript file entry + }); + +// Combined glob file filters +readdirp({ root: './test/bed', fileFilter: [ '*.js', '*.json' ] }) + .on('data', function (entry) { + // do something with each JavaScript and Json file entry + }); + +// Combined negated directory filters +readdirp({ root: './test/bed', directoryFilter: [ '!.git', '!*modules' ] }) + .on('data', function (entry) { + // do something with each file entry found outside '.git' or any modules directory + }); + +// Function directory filter +readdirp({ root: './test/bed', directoryFilter: function (di) { return di.name.length === 9; } }) + .on('data', function (entry) { + // do something with each file entry found inside directories whose name has length 9 + }); + +// Limiting depth +readdirp({ root: './test/bed', depth: 1 }) + .on('data', function (entry) { + // do something with each file entry found up to 1 subdirectory deep + }); + +// callback api +readdirp( + { root: '.' } + , function(fileInfo) { + // do something with file entry here + } + , function (err, res) { + // all done, move on or do final step for all file entries here + } +); +``` + +Try more examples by following [instructions](https://github.com/thlorenz/readdirp/blob/master/examples/Readme.md) +on how to get going. + +## stream api + +[stream-api.js](https://github.com/thlorenz/readdirp/blob/master/examples/stream-api.js) + +Demonstrates error and data handling by listening to events emitted from the readdirp stream. + +## stream api pipe + +[stream-api-pipe.js](https://github.com/thlorenz/readdirp/blob/master/examples/stream-api-pipe.js) + +Demonstrates error handling by listening to events emitted from the readdirp stream and how to pipe the data stream into +another destination stream. + +## grep + +[grep.js](https://github.com/thlorenz/readdirp/blob/master/examples/grep.js) + +Very naive implementation of grep, for demonstration purposes only. + +## using callback api + +[callback-api.js](https://github.com/thlorenz/readdirp/blob/master/examples/callback-api.js) + +Shows how to pass callbacks in order to handle errors and/or data. + +## tests + +The [readdirp tests](https://github.com/thlorenz/readdirp/blob/master/test/readdirp.js) also will give you a good idea on +how things work. + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/Readme.md b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/Readme.md new file mode 100644 index 0000000..55fc461 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/Readme.md @@ -0,0 +1,37 @@ +# readdirp examples + +## How to run the examples + +Assuming you installed readdirp (`npm install readdirp`), you can do the following: + +1. `npm explore readdirp` +2. `cd examples` +3. `npm install` + +At that point you can run the examples with node, i.e., `node grep`. + +## stream api + +[stream-api.js](https://github.com/thlorenz/readdirp/blob/master/examples/stream-api.js) + +Demonstrates error and data handling by listening to events emitted from the readdirp stream. + +## stream api pipe + +[stream-api-pipe.js](https://github.com/thlorenz/readdirp/blob/master/examples/stream-api-pipe.js) + +Demonstrates error handling by listening to events emitted from the readdirp stream and how to pipe the data stream into +another destination stream. + +## grep + +[grep.js](https://github.com/thlorenz/readdirp/blob/master/examples/grep.js) + +Very naive implementation of grep, for demonstration purposes only. + +## using callback api + +[callback-api.js](https://github.com/thlorenz/readdirp/blob/master/examples/callback-api.js) + +Shows how to pass callbacks in order to handle errors and/or data. + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/callback-api.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/callback-api.js new file mode 100644 index 0000000..39bd2d7 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/callback-api.js @@ -0,0 +1,10 @@ +var readdirp = require('..'); + +readdirp({ root: '.', fileFilter: '*.js' }, function (errors, res) { + if (errors) { + errors.forEach(function (err) { + console.error('Error: ', err); + }); + } + console.log('all javascript files', res); +}); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/grep.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/grep.js new file mode 100644 index 0000000..807fa35 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/grep.js @@ -0,0 +1,73 @@ +'use strict'; +var readdirp = require('..') + , util = require('util') + , fs = require('fs') + , path = require('path') + , Stream = require('stream') + , tap = require('tap-stream') + , es = require('event-stream') + ; + +function findLinesMatching (searchTerm) { + + return es.through(function (entry) { + var lineno = 0 + , matchingLines = [] + , fileStream = this; + + function filter () { + return es.mapSync(function (line) { + lineno++; + return ~line.indexOf(searchTerm) ? lineno + ': ' + line : undefined; + }); + } + + function aggregate () { + return es.through( + function write (data) { + matchingLines.push(data); + } + , function end () { + + // drop files that had no matches + if (matchingLines.length) { + var result = { file: entry, lines: matchingLines }; + + // pass result on to file stream + fileStream.emit('data', result); + } + this.emit('end'); + } + ); + } + + fs.createReadStream(entry.fullPath, { encoding: 'utf-8' }) + + // handle file contents line by line + .pipe(es.split('\n')) + + // keep only the lines that matched the term + .pipe(filter()) + + // aggregate all matching lines and delegate control back to the file stream + .pipe(aggregate()) + ; + }); +} + +console.log('grepping for "arguments"'); + +// create a stream of all javascript files found in this and all sub directories +readdirp({ root: path.join(__dirname), fileFilter: '*.js' }) + + // find all lines matching the term for each file (if none found, that file is ignored) + .pipe(findLinesMatching('arguments')) + + // format the results and output + .pipe( + es.mapSync(function (res) { + return '\n\n' + res.file.path + '\n\t' + res.lines.join('\n\t'); + }) + ) + .pipe(process.stdout) + ; diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/.npmignore b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/.npmignore new file mode 100644 index 0000000..13abef4 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/.npmignore @@ -0,0 +1,3 @@ +node_modules +node_modules/* +npm_debug.log diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/.travis.yml b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/.travis.yml new file mode 100644 index 0000000..895dbd3 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.6 + - 0.8 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/LICENCE b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/LICENCE new file mode 100644 index 0000000..171dd97 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/LICENCE @@ -0,0 +1,22 @@ +Copyright (c) 2011 Dominic Tarr + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/examples/pretty.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/examples/pretty.js new file mode 100644 index 0000000..af04340 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/examples/pretty.js @@ -0,0 +1,25 @@ + +var inspect = require('util').inspect + +if(!module.parent) { + var es = require('..') //load event-stream + es.pipe( //pipe joins streams together + process.openStdin(), //open stdin + es.split(), //split stream to break on newlines + es.map(function (data, callback) {//turn this async function into a stream + var j + try { + j = JSON.parse(data) //try to parse input into json + } catch (err) { + return callback(null, data) //if it fails just pass it anyway + } + callback(null, inspect(j)) //render it nicely + }), + process.stdout // pipe it to stdout ! + ) + } + +// run this +// +// curl -sS registry.npmjs.org/event-stream | node pretty.js +// diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/index.js new file mode 100644 index 0000000..16846a2 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/index.js @@ -0,0 +1,341 @@ +//filter will reemit the data if cb(err,pass) pass is truthy + +// reduce is more tricky +// maybe we want to group the reductions or emit progress updates occasionally +// the most basic reduce just emits one 'data' event after it has recieved 'end' + +var Stream = require('stream').Stream + , es = exports + , through = require('through') + , from = require('from') + , duplex = require('duplexer') + , map = require('map-stream') + , pause = require('pause-stream') + , split = require('split') + +es.Stream = Stream //re-export Stream from core +es.through = through +es.from = from +es.duplex = duplex +es.map = map +es.pause = pause +es.split = split + +// merge / concat +// +// combine multiple streams into a single stream. +// will emit end only once + +es.concat = //actually this should be called concat +es.merge = function (/*streams...*/) { + var toMerge = [].slice.call(arguments) + var stream = new Stream() + var endCount = 0 + stream.writable = stream.readable = true + + toMerge.forEach(function (e) { + e.pipe(stream, {end: false}) + var ended = false + e.on('end', function () { + if(ended) return + ended = true + endCount ++ + if(endCount == toMerge.length) + stream.emit('end') + }) + }) + stream.write = function (data) { + this.emit('data', data) + } + stream.destroy = function () { + merge.forEach(function (e) { + if(e.destroy) e.destroy() + }) + } + return stream +} + + +// writable stream, collects all events into an array +// and calls back when 'end' occurs +// mainly I'm using this to test the other functions + +es.writeArray = function (done) { + if ('function' !== typeof done) + throw new Error('function writeArray (done): done must be function') + + var a = new Stream () + , array = [], isDone = false + a.write = function (l) { + array.push(l) + } + a.end = function () { + isDone = true + done(null, array) + } + a.writable = true + a.readable = false + a.destroy = function () { + a.writable = a.readable = false + if(isDone) return + done(new Error('destroyed before end'), array) + } + return a +} + +//return a Stream that reads the properties of an object +//respecting pause() and resume() + +es.readArray = function (array) { + var stream = new Stream() + , i = 0 + , paused = false + , ended = false + + stream.readable = true + stream.writable = false + + if(!Array.isArray(array)) + throw new Error('event-stream.read expects an array') + + stream.resume = function () { + if(ended) return + paused = false + var l = array.length + while(i < l && !paused && !ended) { + stream.emit('data', array[i++]) + } + if(i == l && !ended) + ended = true, stream.readable = false, stream.emit('end') + } + process.nextTick(stream.resume) + stream.pause = function () { + paused = true + } + stream.destroy = function () { + ended = true + stream.emit('close') + } + return stream +} + +// +// readable (asyncFunction) +// return a stream that calls an async function while the stream is not paused. +// +// the function must take: (count, callback) {... +// + +es.readable = function (func, continueOnError) { + var stream = new Stream() + , i = 0 + , paused = false + , ended = false + , reading = false + + stream.readable = true + stream.writable = false + + if('function' !== typeof func) + throw new Error('event-stream.readable expects async function') + + stream.on('end', function () { ended = true }) + + function get (err, data) { + + if(err) { + stream.emit('error', err) + if(!continueOnError) stream.emit('end') + } else if (arguments.length > 1) + stream.emit('data', data) + + process.nextTick(function () { + if(ended || paused || reading) return + try { + reading = true + func.call(stream, i++, function () { + reading = false + get.apply(null, arguments) + }) + } catch (err) { + stream.emit('error', err) + } + }) + } + stream.resume = function () { + paused = false + get() + } + process.nextTick(get) + stream.pause = function () { + paused = true + } + stream.destroy = function () { + stream.emit('end') + stream.emit('close') + ended = true + } + return stream +} + + + +// +// map sync +// + +es.mapSync = function (sync) { + return es.through(function write(data) { + var mappedData = sync(data) + if (typeof mappedData !== 'undefined') + this.emit('data', mappedData) + }) +} + +// +// log just print out what is coming through the stream, for debugging +// + +es.log = function (name) { + return es.through(function (data) { + var args = [].slice.call(arguments) + if(name) console.error(name, data) + else console.error(data) + this.emit('data', data) + }) +} + +// +// combine multiple streams together so that they act as a single stream +// +es.pipeline = +es.pipe = es.connect = function () { + + var streams = [].slice.call(arguments) + , first = streams[0] + , last = streams[streams.length - 1] + , thepipe = es.duplex(first, last) + + if(streams.length == 1) + return streams[0] + else if (!streams.length) + throw new Error('connect called with empty args') + + //pipe all the streams together + + function recurse (streams) { + if(streams.length < 2) + return + streams[0].pipe(streams[1]) + recurse(streams.slice(1)) + } + + recurse(streams) + + function onerror () { + var args = [].slice.call(arguments) + args.unshift('error') + thepipe.emit.apply(thepipe, args) + } + + //es.duplex already reemits the error from the first and last stream. + //add a listener for the inner streams in the pipeline. + for(var i = 1; i < streams.length - 1; i ++) + streams[i].on('error', onerror) + + return thepipe +} + +// +// child -- pipe through a child process +// + +es.child = function (child) { + + return es.duplex(child.stdin, child.stdout) + +} + +// +// parse +// +// must be used after es.split() to ensure that each chunk represents a line +// source.pipe(es.split()).pipe(es.parse()) + +es.parse = function () { + return es.through(function (data) { + var obj + try { + if(data) //ignore empty lines + obj = JSON.parse(data.toString()) + } catch (err) { + return console.error(err, 'attemping to parse:', data) + } + //ignore lines that where only whitespace. + if(obj !== undefined) + this.emit('data', obj) + }) +} +// +// stringify +// + +es.stringify = function () { + var Buffer = require('buffer').Buffer + return es.mapSync(function (e){ + return JSON.stringify(Buffer.isBuffer(e) ? e.toString() : e) + '\n' + }) +} + +// +// replace a string within a stream. +// +// warn: just concatenates the string and then does str.split().join(). +// probably not optimal. +// for smallish responses, who cares? +// I need this for shadow-npm so it's only relatively small json files. + +es.replace = function (from, to) { + return es.pipeline(es.split(from), es.join(to)) +} + +// +// join chunks with a joiner. just like Array#join +// also accepts a callback that is passed the chunks appended together +// this is still supported for legacy reasons. +// + +es.join = function (str) { + + //legacy api + if('function' === typeof str) + return es.wait(str) + + var first = true + return es.through(function (data) { + if(!first) + this.emit('data', str) + first = false + this.emit('data', data) + return true + }) +} + + +// +// wait. callback when 'end' is emitted, with all chunks appended as string. +// + +es.wait = function (callback) { + var body = '' + return es.through(function (data) { body += data }, + function () { + this.emit('data', body) + this.emit('end') + if(callback) callback(null, body) + }) +} + +es.pipeable = function () { + throw new Error('[EVENT-STREAM] es.pipeable is deprecated') +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/.npmignore b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/.npmignore new file mode 100644 index 0000000..062c11e --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/.npmignore @@ -0,0 +1,3 @@ +node_modules +*.log +*.err \ No newline at end of file diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/.travis.yml b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/.travis.yml new file mode 100644 index 0000000..c2ba3f9 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/.travis.yml @@ -0,0 +1,3 @@ +language: node_js +node_js: + - 0.8 \ No newline at end of file diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/LICENCE b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/LICENCE new file mode 100644 index 0000000..a23e08a --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/LICENCE @@ -0,0 +1,19 @@ +Copyright (c) 2012 Raynos. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/Makefile b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/Makefile new file mode 100644 index 0000000..1f8985d --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/Makefile @@ -0,0 +1,4 @@ +test: + node test.js + +.PHONY: test \ No newline at end of file diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/README.md b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/README.md new file mode 100644 index 0000000..a24cecb --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/README.md @@ -0,0 +1,36 @@ +# duplexer [![build status][1]][2] + +Creates a duplex stream + +Taken from [event-stream][3] + +## duplex (writeStream, readStream) + +Takes a writable stream and a readable stream and makes them appear as a readable writable stream. + +It is assumed that the two streams are connected to each other in some way. + +## Example + + var grep = cp.exec('grep Stream') + + duplex(grep.stdin, grep.stdout) + +## Installation + +`npm install duplexer` + +## Tests + +`make test` + +## Contributors + + - Dominictarr + - Raynos + +## MIT Licenced + + [1]: https://secure.travis-ci.org/Raynos/duplexer.png + [2]: http://travis-ci.org/Raynos/duplexer + [3]: https://github.com/dominictarr/event-stream#duplex-writestream-readstream \ No newline at end of file diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/index.js new file mode 100644 index 0000000..fee581d --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/index.js @@ -0,0 +1,87 @@ +var Stream = require("stream") + , writeMethods = ["write", "end", "destroy"] + , readMethods = ["resume", "pause"] + , readEvents = ["data", "close"] + , slice = Array.prototype.slice + +module.exports = duplex + +function duplex(writer, reader) { + var stream = new Stream() + , ended = false + + Object.defineProperties(stream, { + writable: { + get: getWritable + } + , readable: { + get: getReadable + } + }) + + writeMethods.forEach(proxyWriter) + + readMethods.forEach(proxyReader) + + readEvents.forEach(proxyStream) + + reader.on("end", handleEnd) + + writer.on("error", reemit) + reader.on("error", reemit) + + return stream + + function getWritable() { + return writer.writable + } + + function getReadable() { + return reader.readable + } + + function proxyWriter(methodName) { + stream[methodName] = method + + function method() { + return writer[methodName].apply(writer, arguments) + } + } + + function proxyReader(methodName) { + stream[methodName] = method + + function method() { + stream.emit(methodName) + var func = reader[methodName] + if (func) { + return func.apply(reader, arguments) + } + reader.emit(methodName) + } + } + + function proxyStream(methodName) { + reader.on(methodName, reemit) + + function reemit() { + var args = slice.call(arguments) + args.unshift(methodName) + stream.emit.apply(stream, args) + } + } + + function handleEnd() { + if (ended) { + return + } + ended = true + var args = slice.call(arguments) + args.unshift("end") + stream.emit.apply(stream, args) + } + + function reemit(err) { + stream.emit("error", err) + } +} \ No newline at end of file diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/package.json new file mode 100644 index 0000000..6f54329 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/package.json @@ -0,0 +1,41 @@ +{ + "name": "duplexer", + "version": "0.0.2", + "description": "Creates a duplex stream", + "keywords": [], + "author": { + "name": "Raynos", + "email": "raynos2@gmail.com" + }, + "repository": { + "type": "git", + "url": "git://github.com/Raynos/duplexer.git" + }, + "main": "index", + "homepage": "https://github.com/Raynos/duplexer", + "contributors": [ + { + "name": "Jake Verbaten" + } + ], + "bugs": { + "url": "https://github.com/Raynos/duplexer/issues", + "email": "raynos2@gmail.com" + }, + "dependencies": {}, + "devDependencies": { + "through": "~0.1.4" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://github.com/Raynos/duplexer/raw/master/LICENSE" + } + ], + "scripts": { + "test": "make test" + }, + "readme": "# duplexer [![build status][1]][2]\n\nCreates a duplex stream\n\nTaken from [event-stream][3]\n\n## duplex (writeStream, readStream)\n\nTakes a writable stream and a readable stream and makes them appear as a readable writable stream.\n\nIt is assumed that the two streams are connected to each other in some way.\n\n## Example\n\n var grep = cp.exec('grep Stream')\n\n duplex(grep.stdin, grep.stdout)\n\n## Installation\n\n`npm install duplexer`\n\n## Tests\n\n`make test`\n\n## Contributors\n\n - Dominictarr\n - Raynos\n\n## MIT Licenced\n\n [1]: https://secure.travis-ci.org/Raynos/duplexer.png\n [2]: http://travis-ci.org/Raynos/duplexer\n [3]: https://github.com/dominictarr/event-stream#duplex-writestream-readstream", + "_id": "duplexer@0.0.2", + "_from": "duplexer@~0.0.2" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/test.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/test.js new file mode 100644 index 0000000..e06a864 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/duplexer/test.js @@ -0,0 +1,27 @@ +var duplex = require("./index") + , assert = require("assert") + , through = require("through") + +var readable = through() + , writable = through(write) + , written = 0 + , data = 0 + +var stream = duplex(writable, readable) + +function write() { + written++ +} + +stream.on("data", ondata) + +function ondata() { + data++ +} + +stream.write() +readable.emit("data") + +assert.equal(written, 1) +assert.equal(data, 1) +console.log("DONE") \ No newline at end of file diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/LICENSE.APACHE2 b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/LICENSE.APACHE2 new file mode 100644 index 0000000..6366c04 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/LICENSE.APACHE2 @@ -0,0 +1,15 @@ +Apache License, Version 2.0 + +Copyright (c) 2011 Dominic Tarr + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/LICENSE.MIT b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/LICENSE.MIT new file mode 100644 index 0000000..6eafbd7 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/LICENSE.MIT @@ -0,0 +1,24 @@ +The MIT License + +Copyright (c) 2011 Dominic Tarr + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/index.js new file mode 100644 index 0000000..95a8975 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/index.js @@ -0,0 +1,62 @@ + +var Stream = require('stream') + +// from +// +// a stream that reads from an source. +// source may be an array, or a function. +// from handles pause behaviour for you. + +module.exports = +function from (source) { + if(Array.isArray(source)) + return from (function (i) { + if(source.length) + this.emit('data', source.shift()) + else + this.emit('end') + return true + }) + + var s = new Stream(), i = 0, ended = false, started = false + s.readable = true + s.writable = false + s.paused = false + s.pause = function () { + started = true + s.paused = true + } + function next () { + var n = 0, r = false + if(ended) return + while(!ended && !s.paused && source.call(s, i++, function () { + if(!n++ && !s.ended && !s.paused) + next() + })) + ; + } + s.resume = function () { + started = true + s.paused = false + next() + } + s.on('end', function () { + ended = true + s.readable = false + process.nextTick(s.destroy) + }) + s.destroy = function () { + ended = true + s.emit('close') + } + /* + by default, the stream will start emitting at nextTick + if you want, you can pause it, after pipeing. + you can also resume before next tick, and that will also + work. + */ + process.nextTick(function () { + if(!started) s.resume() + }) + return s +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/package.json new file mode 100644 index 0000000..be3c0df --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/package.json @@ -0,0 +1,33 @@ +{ + "name": "from", + "version": "0.0.2", + "description": "Easy way to make a Readable Stream", + "main": "index.js", + "scripts": { + "test": "asynct test/*.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/dominictarr/from.git" + }, + "keywords": [ + "stream", + "streams", + "readable", + "easy" + ], + "devDependencies": { + "asynct": "1", + "stream-spec": "0", + "assertions": "~2.3.0" + }, + "author": { + "name": "Dominic Tarr", + "email": "dominic.tarr@gmail.com", + "url": "dominictarr.com" + }, + "license": "MIT", + "readme": "# from\n\nAn easy way to create a `readable Stream`.\n\n## License\nMIT / Apache2\n", + "_id": "from@0.0.2", + "_from": "from@~0" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/readme.markdown b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/readme.markdown new file mode 100644 index 0000000..84c8269 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/readme.markdown @@ -0,0 +1,6 @@ +# from + +An easy way to create a `readable Stream`. + +## License +MIT / Apache2 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/test/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/test/index.js new file mode 100644 index 0000000..fafea57 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/from/test/index.js @@ -0,0 +1,141 @@ +var from = require('..') +var spec = require('stream-spec') +var a = require('assertions') + +function read(stream, callback) { + var actual = [] + stream.on('data', function (data) { + actual.push(data) + }) + stream.once('end', function () { + callback(null, actual) + }) + stream.once('error', function (err) { + callback(err) + }) +} + +function pause(stream) { + stream.on('data', function () { + if(Math.random() > 0.1) return + stream.pause() + process.nextTick(function () { + stream.resume() + }) + }) +} + +exports['inc'] = function (test) { + + var fs = from(function (i) { + this.emit('data', i) + if(i >= 99) + return this.emit('end') + return true + }) + + spec(fs).readable().validateOnExit() + + read(fs, function (err, arr) { + test.equal(arr.length, 100) + test.done() + }) +} + +exports['simple'] = function (test) { + + var l = 1000 + , expected = [] + + while(l--) expected.push(l * Math.random()) + + var t = from(expected.slice()) + + spec(t) + .readable() + .pausable({strict: true}) + .validateOnExit() + + read(t, function (err, actual) { + if(err) test.error(err) //fail + a.deepEqual(actual, expected) + test.done() + }) + +} + +exports['simple pausable'] = function (test) { + + var l = 1000 + , expected = [] + + while(l--) expected.push(l * Math.random()) + + var t = from(expected.slice()) + + spec(t) + .readable() + .pausable({strict: true}) + .validateOnExit() + + pause(t) + + read(t, function (err, actual) { + if(err) test.error(err) //fail + a.deepEqual(actual, expected) + test.done() + }) + +} + +exports['simple (not strictly pausable) setTimeout'] = function (test) { + + var l = 10 + , expected = [] + while(l--) expected.push(l * Math.random()) + + + var _expected = expected.slice() + var t = from(function (i, n) { + var self = this + setTimeout(function () { + if(_expected.length) + self.emit('data', _expected.shift()) + else + self.emit('end') + n() + }, 3) + }) + + /* + using from in this way will not be strictly pausable. + it could be extended to buffer outputs, but I think a better + way would be to use a PauseStream that implements strict pause. + */ + + spec(t) + .readable() + .pausable({strict: false }) + .validateOnExit() + + //pause(t) + var paused = false + var i = setInterval(function () { + if(!paused) t.pause() + else t.resume() + paused = !paused + }, 2) + + t.on('end', function () { + clearInterval(i) + }) + + read(t, function (err, actual) { + if(err) test.error(err) //fail + a.deepEqual(actual, expected) + test.done() + }) + +} + + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/.npmignore b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/.npmignore new file mode 100644 index 0000000..13abef4 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/.npmignore @@ -0,0 +1,3 @@ +node_modules +node_modules/* +npm_debug.log diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/.travis.yml b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/.travis.yml new file mode 100644 index 0000000..895dbd3 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.6 + - 0.8 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/LICENCE b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/LICENCE new file mode 100644 index 0000000..171dd97 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/LICENCE @@ -0,0 +1,22 @@ +Copyright (c) 2011 Dominic Tarr + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/examples/pretty.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/examples/pretty.js new file mode 100644 index 0000000..af04340 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/examples/pretty.js @@ -0,0 +1,25 @@ + +var inspect = require('util').inspect + +if(!module.parent) { + var es = require('..') //load event-stream + es.pipe( //pipe joins streams together + process.openStdin(), //open stdin + es.split(), //split stream to break on newlines + es.map(function (data, callback) {//turn this async function into a stream + var j + try { + j = JSON.parse(data) //try to parse input into json + } catch (err) { + return callback(null, data) //if it fails just pass it anyway + } + callback(null, inspect(j)) //render it nicely + }), + process.stdout // pipe it to stdout ! + ) + } + +// run this +// +// curl -sS registry.npmjs.org/event-stream | node pretty.js +// diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/index.js new file mode 100644 index 0000000..d3a7fd9 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/index.js @@ -0,0 +1,105 @@ +//filter will reemit the data if cb(err,pass) pass is truthy + +// reduce is more tricky +// maybe we want to group the reductions or emit progress updates occasionally +// the most basic reduce just emits one 'data' event after it has recieved 'end' + + +var Stream = require('stream').Stream + + +//create an event stream and apply function to each .write +//emitting each response as data +//unless it's an empty callback + +module.exports = function (mapper) { + var stream = new Stream() + , inputs = 0 + , outputs = 0 + , ended = false + , paused = false + , destroyed = false + + stream.writable = true + stream.readable = true + + stream.write = function () { + if(ended) throw new Error('map stream is not writable') + inputs ++ + var args = [].slice.call(arguments) + , r + , inNext = false + //pipe only allows one argument. so, do not + function next (err) { + if(destroyed) return + inNext = true + outputs ++ + var args = [].slice.call(arguments) + if(err) { + args.unshift('error') + return inNext = false, stream.emit.apply(stream, args) + } + args.shift() //drop err + if (args.length) { + args.unshift('data') + r = stream.emit.apply(stream, args) + } + if(inputs == outputs) { + if(paused) paused = false, stream.emit('drain') //written all the incoming events + if(ended) end() + } + inNext = false + } + args.push(next) + + try { + //catch sync errors and handle them like async errors + var written = mapper.apply(null, args) + paused = (written === false) + return !paused + } catch (err) { + //if the callback has been called syncronously, and the error + //has occured in an listener, throw it again. + if(inNext) + throw err + next(err) + return !paused + } + } + + function end (data) { + //if end was called with args, write it, + ended = true //write will emit 'end' if ended is true + stream.writable = false + if(data !== undefined) + return stream.write(data) + else if (inputs == outputs) //wait for processing + stream.readable = false, stream.emit('end'), stream.destroy() + } + + stream.end = function (data) { + if(ended) return + end() + } + + stream.destroy = function () { + ended = destroyed = true + stream.writable = stream.readable = paused = false + process.nextTick(function () { + stream.emit('close') + }) + } + stream.pause = function () { + paused = true + } + + stream.resume = function () { + paused = false + } + + return stream +} + + + + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/package.json new file mode 100644 index 0000000..97e7338 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/package.json @@ -0,0 +1,30 @@ +{ + "name": "map-stream", + "version": "0.0.1", + "description": "construct pipes of streams of events", + "homepage": "http://github.com/dominictarr/map-stream", + "repository": { + "type": "git", + "url": "git://github.com/dominictarr/map-stream.git" + }, + "dependencies": {}, + "devDependencies": { + "asynct": "*", + "it-is": "1", + "ubelt": "~2.9", + "stream-spec": "~0.2", + "event-stream": "~2.1", + "from": "0.0.2" + }, + "scripts": { + "test": "asynct test/" + }, + "author": { + "name": "Dominic Tarr", + "email": "dominic.tarr@gmail.com", + "url": "http://dominictarr.com" + }, + "readme": "# MapStream\n\nRefactored out of [event-stream](https://github.com/dominictarr/event-stream)\n\n##map (asyncFunction)\n\nCreate a through stream from an asyncronous function. \n\n``` js\nvar es = require('event-stream')\n\nes.map(function (data, callback) {\n //transform data\n // ...\n callback(null, data)\n})\n\n```\n\nEach map MUST call the callback. It may callback with data, with an error or with no arguments, \n\n * `callback()` drop this data. \n this makes the map work like `filter`, \n note:`callback(null,null)` is not the same, and will emit `null`\n\n * `callback(null, newData)` turn data into newData\n \n * `callback(error)` emit an error for this item.\n\n>Note: if a callback is not called, `map` will think that it is still being processed, \n>every call must be answered or the stream will not know when to end. \n>\n>Also, if the callback is called more than once, every call but the first will be ignored.\n\n\n", + "_id": "map-stream@0.0.1", + "_from": "map-stream@0.0.1" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/readme.markdown b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/readme.markdown new file mode 100644 index 0000000..22c019d --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/readme.markdown @@ -0,0 +1,35 @@ +# MapStream + +Refactored out of [event-stream](https://github.com/dominictarr/event-stream) + +##map (asyncFunction) + +Create a through stream from an asyncronous function. + +``` js +var es = require('event-stream') + +es.map(function (data, callback) { + //transform data + // ... + callback(null, data) +}) + +``` + +Each map MUST call the callback. It may callback with data, with an error or with no arguments, + + * `callback()` drop this data. + this makes the map work like `filter`, + note:`callback(null,null)` is not the same, and will emit `null` + + * `callback(null, newData)` turn data into newData + + * `callback(error)` emit an error for this item. + +>Note: if a callback is not called, `map` will think that it is still being processed, +>every call must be answered or the stream will not know when to end. +> +>Also, if the callback is called more than once, every call but the first will be ignored. + + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/test/simple-map.asynct.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/test/simple-map.asynct.js new file mode 100644 index 0000000..77ac48e --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/map-stream/test/simple-map.asynct.js @@ -0,0 +1,295 @@ +'use strict'; + +var map = require('../') + , it = require('it-is') + , u = require('ubelt') + , spec = require('stream-spec') + , from = require('from') + , Stream = require('stream') + , es = require('event-stream') + +//REFACTOR THIS TEST TO USE es.readArray and es.writeArray + +function writeArray(array, stream) { + + array.forEach( function (j) { + stream.write(j) + }) + stream.end() + +} + +function readStream(stream, done) { + + var array = [] + stream.on('data', function (data) { + array.push(data) + }) + stream.on('error', done) + stream.on('end', function (data) { + done(null, array) + }) + +} + +//call sink on each write, +//and complete when finished. + +function pauseStream (prob, delay) { + var pauseIf = ( + 'number' == typeof prob + ? function () { + return Math.random() < prob + } + : 'function' == typeof prob + ? prob + : 0.1 + ) + var delayer = ( + !delay + ? process.nextTick + : 'number' == typeof delay + ? function (next) { setTimeout(next, delay) } + : delay + ) + + return es.through(function (data) { + if(!this.paused && pauseIf()) { + console.log('PAUSE STREAM PAUSING') + this.pause() + var self = this + delayer(function () { + console.log('PAUSE STREAM RESUMING') + self.resume() + }) + } + console.log("emit ('data', " + data + ')') + this.emit('data', data) + }) +} + +exports ['simple map'] = function (test) { + + var input = u.map(1, 1000, function () { + return Math.random() + }) + var expected = input.map(function (v) { + return v * 2 + }) + + var pause = pauseStream(0.1) + var fs = from(input) + var ts = es.writeArray(function (err, ar) { + it(ar).deepEqual(expected) + test.done() + }) + var map = es.through(function (data) { + this.emit('data', data * 2) + }) + + spec(map).through().validateOnExit() + spec(pause).through().validateOnExit() + + fs.pipe(map).pipe(pause).pipe(ts) +} + +exports ['simple map applied to a stream'] = function (test) { + + var input = [1,2,3,7,5,3,1,9,0,2,4,6] + //create event stream from + + var doubler = map(function (data, cb) { + cb(null, data * 2) + }) + + spec(doubler).through().validateOnExit() + + //a map is only a middle man, so it is both readable and writable + + it(doubler).has({ + readable: true, + writable: true, + }) + + readStream(doubler, function (err, output) { + it(output).deepEqual(input.map(function (j) { + return j * 2 + })) +// process.nextTick(x.validate) + test.done() + }) + + writeArray(input, doubler) + +} + +exports['pipe two maps together'] = function (test) { + + var input = [1,2,3,7,5,3,1,9,0,2,4,6] + //create event stream from + function dd (data, cb) { + cb(null, data * 2) + } + var doubler1 = es.map(dd), doubler2 = es.map(dd) + + doubler1.pipe(doubler2) + + spec(doubler1).through().validateOnExit() + spec(doubler2).through().validateOnExit() + + readStream(doubler2, function (err, output) { + it(output).deepEqual(input.map(function (j) { + return j * 4 + })) + test.done() + }) + + writeArray(input, doubler1) + +} + +//next: +// +// test pause, resume and drian. +// + +// then make a pipe joiner: +// +// plumber (evStr1, evStr2, evStr3, evStr4, evStr5) +// +// will return a single stream that write goes to the first + +exports ['map will not call end until the callback'] = function (test) { + + var ticker = map(function (data, cb) { + process.nextTick(function () { + cb(null, data * 2) + }) + }) + + spec(ticker).through().validateOnExit() + + ticker.write('x') + ticker.end() + + ticker.on('end', function () { + test.done() + }) +} + + +exports ['emit error thrown'] = function (test) { + + var err = new Error('INTENSIONAL ERROR') + , mapper = + es.map(function () { + throw err + }) + + mapper.on('error', function (_err) { + it(_err).equal(err) + test.done() + }) + + mapper.write('hello') + +} + +exports ['emit error calledback'] = function (test) { + + var err = new Error('INTENSIONAL ERROR') + , mapper = + es.map(function (data, callback) { + callback(err) + }) + + mapper.on('error', function (_err) { + it(_err).equal(err) + test.done() + }) + + mapper.write('hello') + +} + +exports ['do not emit drain if not paused'] = function (test) { + + var maps = map(function (data, callback) { + u.delay(callback)(null, 1) + return true + }) + + spec(maps).through().pausable().validateOnExit() + + maps.on('drain', function () { + it(false).ok('should not emit drain unless the stream is paused') + }) + + it(maps.write('hello')).equal(true) + it(maps.write('hello')).equal(true) + it(maps.write('hello')).equal(true) + setTimeout(function () {maps.end()},10) + maps.on('end', test.done) +} + +exports ['emits drain if paused, when all '] = function (test) { + var active = 0 + var drained = false + var maps = map(function (data, callback) { + active ++ + u.delay(function () { + active -- + callback(null, 1) + })() + console.log('WRITE', false) + return false + }) + + spec(maps).through().validateOnExit() + + maps.on('drain', function () { + drained = true + it(active).equal(0, 'should emit drain when all maps are done') + }) + + it(maps.write('hello')).equal(false) + it(maps.write('hello')).equal(false) + it(maps.write('hello')).equal(false) + + process.nextTick(function () {maps.end()},10) + + maps.on('end', function () { + console.log('end') + it(drained).ok('shoud have emitted drain before end') + test.done() + }) + +} + +exports ['map applied to a stream with filtering'] = function (test) { + + var input = [1,2,3,7,5,3,1,9,0,2,4,6] + + var doubler = map(function (data, callback) { + if (data % 2) + callback(null, data * 2) + else + callback() + }) + + readStream(doubler, function (err, output) { + it(output).deepEqual(input.filter(function (j) { + return j % 2 + }).map(function (j) { + return j * 2 + })) + test.done() + }) + + spec(doubler).through().validateOnExit() + + writeArray(input, doubler) + +} + + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/.npmignore b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/.npmignore new file mode 100644 index 0000000..bfdb82c --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/.npmignore @@ -0,0 +1,4 @@ +lib-cov/* +*.swp +*.swo +node_modules diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/LICENSE b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/LICENSE new file mode 100644 index 0000000..432d1ae --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/LICENSE @@ -0,0 +1,21 @@ +Copyright 2010 James Halliday (mail@substack.net) + +This project is free software released under the MIT/X11 license: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/README.markdown b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/README.markdown new file mode 100644 index 0000000..deb493c --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/README.markdown @@ -0,0 +1,474 @@ +optimist +======== + +Optimist is a node.js library for option parsing for people who hate option +parsing. More specifically, this module is for people who like all the --bells +and -whistlz of program usage but think optstrings are a waste of time. + +With optimist, option parsing doesn't have to suck (as much). + +examples +======== + +With Optimist, the options are just a hash! No optstrings attached. +------------------------------------------------------------------- + +xup.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist').argv; + +if (argv.rif - 5 * argv.xup > 7.138) { + console.log('Buy more riffiwobbles'); +} +else { + console.log('Sell the xupptumblers'); +} +```` + +*** + + $ ./xup.js --rif=55 --xup=9.52 + Buy more riffiwobbles + + $ ./xup.js --rif 12 --xup 8.1 + Sell the xupptumblers + +![This one's optimistic.](http://substack.net/images/optimistic.png) + +But wait! There's more! You can do short options: +------------------------------------------------- + +short.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist').argv; +console.log('(%d,%d)', argv.x, argv.y); +```` + +*** + + $ ./short.js -x 10 -y 21 + (10,21) + +And booleans, both long and short (and grouped): +---------------------------------- + +bool.js: + +````javascript +#!/usr/bin/env node +var util = require('util'); +var argv = require('optimist').argv; + +if (argv.s) { + util.print(argv.fr ? 'Le chat dit: ' : 'The cat says: '); +} +console.log( + (argv.fr ? 'miaou' : 'meow') + (argv.p ? '.' : '') +); +```` + +*** + + $ ./bool.js -s + The cat says: meow + + $ ./bool.js -sp + The cat says: meow. + + $ ./bool.js -sp --fr + Le chat dit: miaou. + +And non-hypenated options too! Just use `argv._`! +------------------------------------------------- + +nonopt.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist').argv; +console.log('(%d,%d)', argv.x, argv.y); +console.log(argv._); +```` + +*** + + $ ./nonopt.js -x 6.82 -y 3.35 moo + (6.82,3.35) + [ 'moo' ] + + $ ./nonopt.js foo -x 0.54 bar -y 1.12 baz + (0.54,1.12) + [ 'foo', 'bar', 'baz' ] + +Plus, Optimist comes with .usage() and .demand()! +------------------------------------------------- + +divide.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .usage('Usage: $0 -x [num] -y [num]') + .demand(['x','y']) + .argv; + +console.log(argv.x / argv.y); +```` + +*** + + $ ./divide.js -x 55 -y 11 + 5 + + $ node ./divide.js -x 4.91 -z 2.51 + Usage: node ./divide.js -x [num] -y [num] + + Options: + -x [required] + -y [required] + + Missing required arguments: y + +EVEN MORE HOLY COW +------------------ + +default_singles.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .default('x', 10) + .default('y', 10) + .argv +; +console.log(argv.x + argv.y); +```` + +*** + + $ ./default_singles.js -x 5 + 15 + +default_hash.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .default({ x : 10, y : 10 }) + .argv +; +console.log(argv.x + argv.y); +```` + +*** + + $ ./default_hash.js -y 7 + 17 + +And if you really want to get all descriptive about it... +--------------------------------------------------------- + +boolean_single.js + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .boolean('v') + .argv +; +console.dir(argv); +```` + +*** + + $ ./boolean_single.js -v foo bar baz + true + [ 'bar', 'baz', 'foo' ] + +boolean_double.js + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .boolean(['x','y','z']) + .argv +; +console.dir([ argv.x, argv.y, argv.z ]); +console.dir(argv._); +```` + +*** + + $ ./boolean_double.js -x -z one two three + [ true, false, true ] + [ 'one', 'two', 'three' ] + +Optimist is here to help... +--------------------------- + +You can describe parameters for help messages and set aliases. Optimist figures +out how to format a handy help string automatically. + +line_count.js + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .usage('Count the lines in a file.\nUsage: $0') + .demand('f') + .alias('f', 'file') + .describe('f', 'Load a file') + .argv +; + +var fs = require('fs'); +var s = fs.createReadStream(argv.file); + +var lines = 0; +s.on('data', function (buf) { + lines += buf.toString().match(/\n/g).length; +}); + +s.on('end', function () { + console.log(lines); +}); +```` + +*** + + $ node line_count.js + Count the lines in a file. + Usage: node ./line_count.js + + Options: + -f, --file Load a file [required] + + Missing required arguments: f + + $ node line_count.js --file line_count.js + 20 + + $ node line_count.js -f line_count.js + 20 + +methods +======= + +By itself, + +````javascript +require('optimist').argv +````` + +will use `process.argv` array to construct the `argv` object. + +You can pass in the `process.argv` yourself: + +````javascript +require('optimist')([ '-x', '1', '-y', '2' ]).argv +```` + +or use .parse() to do the same thing: + +````javascript +require('optimist').parse([ '-x', '1', '-y', '2' ]) +```` + +The rest of these methods below come in just before the terminating `.argv`. + +.alias(key, alias) +------------------ + +Set key names as equivalent such that updates to a key will propagate to aliases +and vice-versa. + +Optionally `.alias()` can take an object that maps keys to aliases. + +.default(key, value) +-------------------- + +Set `argv[key]` to `value` if no option was specified on `process.argv`. + +Optionally `.default()` can take an object that maps keys to default values. + +.demand(key) +------------ + +If `key` is a string, show the usage information and exit if `key` wasn't +specified in `process.argv`. + +If `key` is a number, demand at least as many non-option arguments, which show +up in `argv._`. + +If `key` is an Array, demand each element. + +.describe(key, desc) +-------------------- + +Describe a `key` for the generated usage information. + +Optionally `.describe()` can take an object that maps keys to descriptions. + +.options(key, opt) +------------------ + +Instead of chaining together `.alias().demand().default()`, you can specify +keys in `opt` for each of the chainable methods. + +For example: + +````javascript +var argv = require('optimist') + .options('f', { + alias : 'file', + default : '/etc/passwd', + }) + .argv +; +```` + +is the same as + +````javascript +var argv = require('optimist') + .alias('f', 'file') + .default('f', '/etc/passwd') + .argv +; +```` + +Optionally `.options()` can take an object that maps keys to `opt` parameters. + +.usage(message) +--------------- + +Set a usage message to show which commands to use. Inside `message`, the string +`$0` will get interpolated to the current script name or node command for the +present script similar to how `$0` works in bash or perl. + +.check(fn) +---------- + +Check that certain conditions are met in the provided arguments. + +If `fn` throws or returns `false`, show the thrown error, usage information, and +exit. + +.boolean(key) +------------- + +Interpret `key` as a boolean. If a non-flag option follows `key` in +`process.argv`, that string won't get set as the value of `key`. + +If `key` never shows up as a flag in `process.arguments`, `argv[key]` will be +`false`. + +If `key` is an Array, interpret all the elements as booleans. + +.string(key) +------------ + +Tell the parser logic not to interpret `key` as a number or boolean. +This can be useful if you need to preserve leading zeros in an input. + +If `key` is an Array, interpret all the elements as strings. + +.wrap(columns) +-------------- + +Format usage output to wrap at `columns` many columns. + +.help() +------- + +Return the generated usage string. + +.showHelp(fn=console.error) +--------------------------- + +Print the usage data using `fn` for printing. + +.parse(args) +------------ + +Parse `args` instead of `process.argv`. Returns the `argv` object. + +.argv +----- + +Get the arguments as a plain old object. + +Arguments without a corresponding flag show up in the `argv._` array. + +The script name or node command is available at `argv.$0` similarly to how `$0` +works in bash or perl. + +parsing tricks +============== + +stop parsing +------------ + +Use `--` to stop parsing flags and stuff the remainder into `argv._`. + + $ node examples/reflect.js -a 1 -b 2 -- -c 3 -d 4 + { _: [ '-c', '3', '-d', '4' ], + '$0': 'node ./examples/reflect.js', + a: 1, + b: 2 } + +negate fields +------------- + +If you want to explicity set a field to false instead of just leaving it +undefined or to override a default you can do `--no-key`. + + $ node examples/reflect.js -a --no-b + { _: [], + '$0': 'node ./examples/reflect.js', + a: true, + b: false } + +numbers +------- + +Every argument that looks like a number (`!isNaN(Number(arg))`) is converted to +one. This way you can just `net.createConnection(argv.port)` and you can add +numbers out of `argv` with `+` without having that mean concatenation, +which is super frustrating. + +duplicates +---------- + +If you specify a flag multiple times it will get turned into an array containing +all the values in order. + + $ node examples/reflect.js -x 5 -x 8 -x 0 + { _: [], + '$0': 'node ./examples/reflect.js', + x: [ 5, 8, 0 ] } + +installation +============ + +With [npm](http://github.com/isaacs/npm), just do: + npm install optimist + +or clone this project on github: + + git clone http://github.com/substack/node-optimist.git + +To run the tests with [expresso](http://github.com/visionmedia/expresso), +just do: + + expresso + +inspired By +=========== + +This module is loosely inspired by Perl's +[Getopt::Casual](http://search.cpan.org/~photo/Getopt-Casual-0.13.1/Casual.pm). diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/bool.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/bool.js new file mode 100644 index 0000000..a998fb7 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/bool.js @@ -0,0 +1,10 @@ +#!/usr/bin/env node +var util = require('util'); +var argv = require('optimist').argv; + +if (argv.s) { + util.print(argv.fr ? 'Le chat dit: ' : 'The cat says: '); +} +console.log( + (argv.fr ? 'miaou' : 'meow') + (argv.p ? '.' : '') +); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/boolean_double.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/boolean_double.js new file mode 100644 index 0000000..a35a7e6 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/boolean_double.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +var argv = require('optimist') + .boolean(['x','y','z']) + .argv +; +console.dir([ argv.x, argv.y, argv.z ]); +console.dir(argv._); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/boolean_single.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/boolean_single.js new file mode 100644 index 0000000..017bb68 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/boolean_single.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +var argv = require('optimist') + .boolean('v') + .argv +; +console.dir(argv.v); +console.dir(argv._); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/default_hash.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/default_hash.js new file mode 100644 index 0000000..ade7768 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/default_hash.js @@ -0,0 +1,8 @@ +#!/usr/bin/env node + +var argv = require('optimist') + .default({ x : 10, y : 10 }) + .argv +; + +console.log(argv.x + argv.y); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/default_singles.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/default_singles.js new file mode 100644 index 0000000..d9b1ff4 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/default_singles.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +var argv = require('optimist') + .default('x', 10) + .default('y', 10) + .argv +; +console.log(argv.x + argv.y); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/divide.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/divide.js new file mode 100644 index 0000000..5e2ee82 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/divide.js @@ -0,0 +1,8 @@ +#!/usr/bin/env node + +var argv = require('optimist') + .usage('Usage: $0 -x [num] -y [num]') + .demand(['x','y']) + .argv; + +console.log(argv.x / argv.y); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/line_count.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/line_count.js new file mode 100644 index 0000000..b5f95bf --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/line_count.js @@ -0,0 +1,20 @@ +#!/usr/bin/env node +var argv = require('optimist') + .usage('Count the lines in a file.\nUsage: $0') + .demand('f') + .alias('f', 'file') + .describe('f', 'Load a file') + .argv +; + +var fs = require('fs'); +var s = fs.createReadStream(argv.file); + +var lines = 0; +s.on('data', function (buf) { + lines += buf.toString().match(/\n/g).length; +}); + +s.on('end', function () { + console.log(lines); +}); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/line_count_options.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/line_count_options.js new file mode 100644 index 0000000..d9ac709 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/line_count_options.js @@ -0,0 +1,29 @@ +#!/usr/bin/env node +var argv = require('optimist') + .usage('Count the lines in a file.\nUsage: $0') + .options({ + file : { + demand : true, + alias : 'f', + description : 'Load a file' + }, + base : { + alias : 'b', + description : 'Numeric base to use for output', + default : 10, + }, + }) + .argv +; + +var fs = require('fs'); +var s = fs.createReadStream(argv.file); + +var lines = 0; +s.on('data', function (buf) { + lines += buf.toString().match(/\n/g).length; +}); + +s.on('end', function () { + console.log(lines.toString(argv.base)); +}); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/line_count_wrap.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/line_count_wrap.js new file mode 100644 index 0000000..4267511 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/line_count_wrap.js @@ -0,0 +1,29 @@ +#!/usr/bin/env node +var argv = require('optimist') + .usage('Count the lines in a file.\nUsage: $0') + .wrap(80) + .demand('f') + .alias('f', [ 'file', 'filename' ]) + .describe('f', + "Load a file. It's pretty important." + + " Required even. So you'd better specify it." + ) + .alias('b', 'base') + .describe('b', 'Numeric base to display the number of lines in') + .default('b', 10) + .describe('x', 'Super-secret optional parameter which is secret') + .default('x', '') + .argv +; + +var fs = require('fs'); +var s = fs.createReadStream(argv.file); + +var lines = 0; +s.on('data', function (buf) { + lines += buf.toString().match(/\n/g).length; +}); + +s.on('end', function () { + console.log(lines.toString(argv.base)); +}); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/nonopt.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/nonopt.js new file mode 100644 index 0000000..ee633ee --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/nonopt.js @@ -0,0 +1,4 @@ +#!/usr/bin/env node +var argv = require('optimist').argv; +console.log('(%d,%d)', argv.x, argv.y); +console.log(argv._); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/reflect.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/reflect.js new file mode 100644 index 0000000..816b3e1 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/reflect.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +console.dir(require('optimist').argv); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/short.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/short.js new file mode 100644 index 0000000..1db0ad0 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/short.js @@ -0,0 +1,3 @@ +#!/usr/bin/env node +var argv = require('optimist').argv; +console.log('(%d,%d)', argv.x, argv.y); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/string.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/string.js new file mode 100644 index 0000000..a8e5aeb --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/string.js @@ -0,0 +1,11 @@ +#!/usr/bin/env node +var argv = require('optimist') + .string('x', 'y') + .argv +; +console.dir([ argv.x, argv.y ]); + +/* Turns off numeric coercion: + ./node string.js -x 000123 -y 9876 + [ '000123', '9876' ] +*/ diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/usage-options.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/usage-options.js new file mode 100644 index 0000000..b999977 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/usage-options.js @@ -0,0 +1,19 @@ +var optimist = require('./../index'); + +var argv = optimist.usage('This is my awesome program', { + 'about': { + description: 'Provide some details about the author of this program', + required: true, + short: 'a', + }, + 'info': { + description: 'Provide some information about the node.js agains!!!!!!', + boolean: true, + short: 'i' + } +}).argv; + +optimist.showHelp(); + +console.log('\n\nInspecting options'); +console.dir(argv); \ No newline at end of file diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/xup.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/xup.js new file mode 100644 index 0000000..8f6ecd2 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/examples/xup.js @@ -0,0 +1,10 @@ +#!/usr/bin/env node +var argv = require('optimist').argv; + +if (argv.rif - 5 * argv.xup > 7.138) { + console.log('Buy more riffiwobbles'); +} +else { + console.log('Sell the xupptumblers'); +} + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/index.js new file mode 100644 index 0000000..070d642 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/index.js @@ -0,0 +1,457 @@ +var path = require('path'); +var wordwrap = require('wordwrap'); + +/* Hack an instance of Argv with process.argv into Argv + so people can do + require('optimist')(['--beeble=1','-z','zizzle']).argv + to parse a list of args and + require('optimist').argv + to get a parsed version of process.argv. +*/ + +var inst = Argv(process.argv.slice(2)); +Object.keys(inst).forEach(function (key) { + Argv[key] = typeof inst[key] == 'function' + ? inst[key].bind(inst) + : inst[key]; +}); + +var exports = module.exports = Argv; +function Argv (args, cwd) { + var self = {}; + if (!cwd) cwd = process.cwd(); + + self.$0 = process.argv + .slice(0,2) + .map(function (x) { + var b = rebase(cwd, x); + return x.match(/^\//) && b.length < x.length + ? b : x + }) + .join(' ') + ; + + if (process.argv[1] == process.env._) { + self.$0 = process.env._.replace( + path.dirname(process.execPath) + '/', '' + ); + } + + var flags = { bools : {}, strings : {} }; + + self.boolean = function (bools) { + if (!Array.isArray(bools)) { + bools = [].slice.call(arguments); + } + + bools.forEach(function (name) { + flags.bools[name] = true; + }); + + return self; + }; + + self.string = function (strings) { + if (!Array.isArray(strings)) { + strings = [].slice.call(arguments); + } + + strings.forEach(function (name) { + flags.strings[name] = true; + }); + + return self; + }; + + var aliases = {}; + self.alias = function (x, y) { + if (typeof x === 'object') { + Object.keys(x).forEach(function (key) { + self.alias(key, x[key]); + }); + } + else if (Array.isArray(y)) { + y.forEach(function (yy) { + self.alias(x, yy); + }); + } + else { + var zs = (aliases[x] || []).concat(aliases[y] || []).concat(x, y); + aliases[x] = zs.filter(function (z) { return z != x }); + aliases[y] = zs.filter(function (z) { return z != y }); + } + + return self; + }; + + var demanded = {}; + self.demand = function (keys) { + if (typeof keys == 'number') { + if (!demanded._) demanded._ = 0; + demanded._ += keys; + } + else if (Array.isArray(keys)) { + keys.forEach(function (key) { + self.demand(key); + }); + } + else { + demanded[keys] = true; + } + + return self; + }; + + var usage; + self.usage = function (msg, opts) { + if (!opts && typeof msg === 'object') { + opts = msg; + msg = null; + } + + usage = msg; + + if (opts) self.options(opts); + + return self; + }; + + function fail (msg) { + self.showHelp(); + if (msg) console.error(msg); + process.exit(1); + } + + var checks = []; + self.check = function (f) { + checks.push(f); + return self; + }; + + var defaults = {}; + self.default = function (key, value) { + if (typeof key === 'object') { + Object.keys(key).forEach(function (k) { + self.default(k, key[k]); + }); + } + else { + defaults[key] = value; + } + + return self; + }; + + var descriptions = {}; + self.describe = function (key, desc) { + if (typeof key === 'object') { + Object.keys(key).forEach(function (k) { + self.describe(k, key[k]); + }); + } + else { + descriptions[key] = desc; + } + return self; + }; + + self.parse = function (args) { + return Argv(args).argv; + }; + + self.option = self.options = function (key, opt) { + if (typeof key === 'object') { + Object.keys(key).forEach(function (k) { + self.options(k, key[k]); + }); + } + else { + if (opt.alias) self.alias(key, opt.alias); + if (opt.demand) self.demand(key); + if (opt.default) self.default(key, opt.default); + + if (opt.boolean || opt.type === 'boolean') { + self.boolean(key); + } + if (opt.string || opt.type === 'string') { + self.string(key); + } + + var desc = opt.describe || opt.description || opt.desc; + if (desc) { + self.describe(key, desc); + } + } + + return self; + }; + + var wrap = null; + self.wrap = function (cols) { + wrap = cols; + return self; + }; + + self.showHelp = function (fn) { + if (!fn) fn = console.error; + fn(self.help()); + }; + + self.help = function () { + var keys = Object.keys( + Object.keys(descriptions) + .concat(Object.keys(demanded)) + .concat(Object.keys(defaults)) + .reduce(function (acc, key) { + if (key !== '_') acc[key] = true; + return acc; + }, {}) + ); + + var help = keys.length ? [ 'Options:' ] : []; + + if (usage) { + help.unshift(usage.replace(/\$0/g, self.$0), ''); + } + + var switches = keys.reduce(function (acc, key) { + acc[key] = [ key ].concat(aliases[key] || []) + .map(function (sw) { + return (sw.length > 1 ? '--' : '-') + sw + }) + .join(', ') + ; + return acc; + }, {}); + + var switchlen = longest(Object.keys(switches).map(function (s) { + return switches[s] || ''; + })); + + var desclen = longest(Object.keys(descriptions).map(function (d) { + return descriptions[d] || ''; + })); + + keys.forEach(function (key) { + var kswitch = switches[key]; + var desc = descriptions[key] || ''; + + if (wrap) { + desc = wordwrap(switchlen + 4, wrap)(desc) + .slice(switchlen + 4) + ; + } + + var spadding = new Array( + Math.max(switchlen - kswitch.length + 3, 0) + ).join(' '); + + var dpadding = new Array( + Math.max(desclen - desc.length + 1, 0) + ).join(' '); + + var type = null; + + if (flags.bools[key]) type = '[boolean]'; + if (flags.strings[key]) type = '[string]'; + + if (!wrap && dpadding.length > 0) { + desc += dpadding; + } + + var prelude = ' ' + kswitch + spadding; + var extra = [ + type, + demanded[key] + ? '[required]' + : null + , + defaults[key] !== undefined + ? '[default: ' + JSON.stringify(defaults[key]) + ']' + : null + , + ].filter(Boolean).join(' '); + + var body = [ desc, extra ].filter(Boolean).join(' '); + + if (wrap) { + var dlines = desc.split('\n'); + var dlen = dlines.slice(-1)[0].length + + (dlines.length === 1 ? prelude.length : 0) + + body = desc + (dlen + extra.length > wrap - 2 + ? '\n' + + new Array(wrap - extra.length + 1).join(' ') + + extra + : new Array(wrap - extra.length - dlen + 1).join(' ') + + extra + ); + } + + help.push(prelude + body); + }); + + help.push(''); + return help.join('\n'); + }; + + Object.defineProperty(self, 'argv', { + get : parseArgs, + enumerable : true, + }); + + function parseArgs () { + var argv = { _ : [], $0 : self.$0 }; + Object.keys(flags.bools).forEach(function (key) { + setArg(key, defaults[key] || false); + }); + + function setArg (key, val) { + var num = Number(val); + var value = typeof val !== 'string' || isNaN(num) ? val : num; + if (flags.strings[key]) value = val; + + if (key in argv && !flags.bools[key]) { + if (!Array.isArray(argv[key])) { + argv[key] = [ argv[key] ]; + } + argv[key].push(value); + } + else { + argv[key] = value; + } + + (aliases[key] || []).forEach(function (x) { + argv[x] = argv[key]; + }); + } + + for (var i = 0; i < args.length; i++) { + var arg = args[i]; + + if (arg === '--') { + argv._.push.apply(argv._, args.slice(i + 1)); + break; + } + else if (arg.match(/^--.+=/)) { + var m = arg.match(/^--([^=]+)=(.*)/); + setArg(m[1], m[2]); + } + else if (arg.match(/^--no-.+/)) { + var key = arg.match(/^--no-(.+)/)[1]; + setArg(key, false); + } + else if (arg.match(/^--.+/)) { + var key = arg.match(/^--(.+)/)[1]; + var next = args[i + 1]; + if (next !== undefined && !next.match(/^-/) + && !flags.bools[key]) { + setArg(key, next); + i++; + } + else if (flags.bools[key] && /true|false/.test(next)) { + setArg(key, next === 'true'); + i++; + } + else { + setArg(key, true); + } + } + else if (arg.match(/^-[^-]+/)) { + var letters = arg.slice(1,-1).split(''); + + var broken = false; + for (var j = 0; j < letters.length; j++) { + if (letters[j+1] && letters[j+1].match(/\W/)) { + setArg(letters[j], arg.slice(j+2)); + broken = true; + break; + } + else { + setArg(letters[j], true); + } + } + + if (!broken) { + var key = arg.slice(-1)[0]; + + if (args[i+1] && !args[i+1].match(/^-/) + && !flags.bools[key]) { + setArg(key, args[i+1]); + i++; + } + else if (args[i+1] && flags.bools[key] && /true|false/.test(args[i+1])) { + setArg(key, args[i+1] === 'true'); + i++; + } + else { + setArg(key, true); + } + } + } + else { + var n = Number(arg); + argv._.push(flags.strings['_'] || isNaN(n) ? arg : n); + } + } + + Object.keys(defaults).forEach(function (key) { + if (!(key in argv)) { + argv[key] = defaults[key]; + } + }); + + if (demanded._ && argv._.length < demanded._) { + fail('Not enough non-option arguments: got ' + + argv._.length + ', need at least ' + demanded._ + ); + } + + var missing = []; + Object.keys(demanded).forEach(function (key) { + if (!argv[key]) missing.push(key); + }); + + if (missing.length) { + fail('Missing required arguments: ' + missing.join(', ')); + } + + checks.forEach(function (f) { + try { + if (f(argv) === false) { + fail('Argument check failed: ' + f.toString()); + } + } + catch (err) { + fail(err) + } + }); + + return argv; + } + + function longest (xs) { + return Math.max.apply( + null, + xs.map(function (x) { return x.length }) + ); + } + + return self; +}; + +// rebase an absolute path to a relative one with respect to a base directory +// exported for tests +exports.rebase = rebase; +function rebase (base, dir) { + var ds = path.normalize(dir).split('/').slice(1); + var bs = path.normalize(base).split('/').slice(1); + + for (var i = 0; ds[i] && ds[i] == bs[i]; i++); + ds.splice(0, i); bs.splice(0, i); + + var p = path.normalize( + bs.map(function () { return '..' }).concat(ds).join('/') + ).replace(/\/$/,'').replace(/^$/, '.'); + return p.match(/^[.\/]/) ? p : './' + p; +}; diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/.npmignore b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/.npmignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/.npmignore @@ -0,0 +1 @@ +node_modules diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/README.markdown b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/README.markdown new file mode 100644 index 0000000..346374e --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/README.markdown @@ -0,0 +1,70 @@ +wordwrap +======== + +Wrap your words. + +example +======= + +made out of meat +---------------- + +meat.js + + var wrap = require('wordwrap')(15); + console.log(wrap('You and your whole family are made out of meat.')); + +output: + + You and your + whole family + are made out + of meat. + +centered +-------- + +center.js + + var wrap = require('wordwrap')(20, 60); + console.log(wrap( + 'At long last the struggle and tumult was over.' + + ' The machines had finally cast off their oppressors' + + ' and were finally free to roam the cosmos.' + + '\n' + + 'Free of purpose, free of obligation.' + + ' Just drifting through emptiness.' + + ' The sun was just another point of light.' + )); + +output: + + At long last the struggle and tumult + was over. The machines had finally cast + off their oppressors and were finally + free to roam the cosmos. + Free of purpose, free of obligation. + Just drifting through emptiness. The + sun was just another point of light. + +methods +======= + +var wrap = require('wordwrap'); + +wrap(stop), wrap(start, stop, params={mode:"soft"}) +--------------------------------------------------- + +Returns a function that takes a string and returns a new string. + +Pad out lines with spaces out to column `start` and then wrap until column +`stop`. If a word is longer than `stop - start` characters it will overflow. + +In "soft" mode, split chunks by `/(\S+\s+/` and don't break up chunks which are +longer than `stop - start`, in "hard" mode, split chunks with `/\b/` and break +up chunks longer than `stop - start`. + +wrap.hard(start, stop) +---------------------- + +Like `wrap()` but with `params.mode = "hard"`. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/example/center.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/example/center.js new file mode 100644 index 0000000..a3fbaae --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/example/center.js @@ -0,0 +1,10 @@ +var wrap = require('wordwrap')(20, 60); +console.log(wrap( + 'At long last the struggle and tumult was over.' + + ' The machines had finally cast off their oppressors' + + ' and were finally free to roam the cosmos.' + + '\n' + + 'Free of purpose, free of obligation.' + + ' Just drifting through emptiness.' + + ' The sun was just another point of light.' +)); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/example/meat.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/example/meat.js new file mode 100644 index 0000000..a4665e1 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/example/meat.js @@ -0,0 +1,3 @@ +var wrap = require('wordwrap')(15); + +console.log(wrap('You and your whole family are made out of meat.')); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/index.js new file mode 100644 index 0000000..c9bc945 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/index.js @@ -0,0 +1,76 @@ +var wordwrap = module.exports = function (start, stop, params) { + if (typeof start === 'object') { + params = start; + start = params.start; + stop = params.stop; + } + + if (typeof stop === 'object') { + params = stop; + start = start || params.start; + stop = undefined; + } + + if (!stop) { + stop = start; + start = 0; + } + + if (!params) params = {}; + var mode = params.mode || 'soft'; + var re = mode === 'hard' ? /\b/ : /(\S+\s+)/; + + return function (text) { + var chunks = text.toString() + .split(re) + .reduce(function (acc, x) { + if (mode === 'hard') { + for (var i = 0; i < x.length; i += stop - start) { + acc.push(x.slice(i, i + stop - start)); + } + } + else acc.push(x) + return acc; + }, []) + ; + + return chunks.reduce(function (lines, rawChunk) { + if (rawChunk === '') return lines; + + var chunk = rawChunk.replace(/\t/g, ' '); + + var i = lines.length - 1; + if (lines[i].length + chunk.length > stop) { + lines[i] = lines[i].replace(/\s+$/, ''); + + chunk.split(/\n/).forEach(function (c) { + lines.push( + new Array(start + 1).join(' ') + + c.replace(/^\s+/, '') + ); + }); + } + else if (chunk.match(/\n/)) { + var xs = chunk.split(/\n/); + lines[i] += xs.shift(); + xs.forEach(function (c) { + lines.push( + new Array(start + 1).join(' ') + + c.replace(/^\s+/, '') + ); + }); + } + else { + lines[i] += chunk; + } + + return lines; + }, [ new Array(start + 1).join(' ') ]).join('\n'); + }; +}; + +wordwrap.soft = wordwrap; + +wordwrap.hard = function (start, stop) { + return wordwrap(start, stop, { mode : 'hard' }); +}; diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/package.json new file mode 100644 index 0000000..928d935 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/package.json @@ -0,0 +1,40 @@ +{ + "name": "wordwrap", + "description": "Wrap those words. Show them at what columns to start and stop.", + "version": "0.0.2", + "repository": { + "type": "git", + "url": "git://github.com/substack/node-wordwrap.git" + }, + "main": "./index.js", + "keywords": [ + "word", + "wrap", + "rule", + "format", + "column" + ], + "directories": { + "lib": ".", + "example": "example", + "test": "test" + }, + "scripts": { + "test": "expresso" + }, + "devDependencies": { + "expresso": "=0.7.x" + }, + "engines": { + "node": ">=0.4.0" + }, + "license": "MIT/X11", + "author": { + "name": "James Halliday", + "email": "mail@substack.net", + "url": "http://substack.net" + }, + "readme": "wordwrap\n========\n\nWrap your words.\n\nexample\n=======\n\nmade out of meat\n----------------\n\nmeat.js\n\n var wrap = require('wordwrap')(15);\n console.log(wrap('You and your whole family are made out of meat.'));\n\noutput:\n\n You and your\n whole family\n are made out\n of meat.\n\ncentered\n--------\n\ncenter.js\n\n var wrap = require('wordwrap')(20, 60);\n console.log(wrap(\n 'At long last the struggle and tumult was over.'\n + ' The machines had finally cast off their oppressors'\n + ' and were finally free to roam the cosmos.'\n + '\\n'\n + 'Free of purpose, free of obligation.'\n + ' Just drifting through emptiness.'\n + ' The sun was just another point of light.'\n ));\n\noutput:\n\n At long last the struggle and tumult\n was over. The machines had finally cast\n off their oppressors and were finally\n free to roam the cosmos.\n Free of purpose, free of obligation.\n Just drifting through emptiness. The\n sun was just another point of light.\n\nmethods\n=======\n\nvar wrap = require('wordwrap');\n\nwrap(stop), wrap(start, stop, params={mode:\"soft\"})\n---------------------------------------------------\n\nReturns a function that takes a string and returns a new string.\n\nPad out lines with spaces out to column `start` and then wrap until column\n`stop`. If a word is longer than `stop - start` characters it will overflow.\n\nIn \"soft\" mode, split chunks by `/(\\S+\\s+/` and don't break up chunks which are\nlonger than `stop - start`, in \"hard\" mode, split chunks with `/\\b/` and break\nup chunks longer than `stop - start`.\n\nwrap.hard(start, stop)\n----------------------\n\nLike `wrap()` but with `params.mode = \"hard\"`.\n", + "_id": "wordwrap@0.0.2", + "_from": "wordwrap@>=0.0.1 <0.1.0" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/test/break.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/test/break.js new file mode 100644 index 0000000..749292e --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/test/break.js @@ -0,0 +1,30 @@ +var assert = require('assert'); +var wordwrap = require('../'); + +exports.hard = function () { + var s = 'Assert from {"type":"equal","ok":false,"found":1,"wanted":2,' + + '"stack":[],"id":"b7ddcd4c409de8799542a74d1a04689b",' + + '"browser":"chrome/6.0"}' + ; + var s_ = wordwrap.hard(80)(s); + + var lines = s_.split('\n'); + assert.equal(lines.length, 2); + assert.ok(lines[0].length < 80); + assert.ok(lines[1].length < 80); + + assert.equal(s, s_.replace(/\n/g, '')); +}; + +exports.break = function () { + var s = new Array(55+1).join('a'); + var s_ = wordwrap.hard(20)(s); + + var lines = s_.split('\n'); + assert.equal(lines.length, 3); + assert.ok(lines[0].length === 20); + assert.ok(lines[1].length === 20); + assert.ok(lines[2].length === 15); + + assert.equal(s, s_.replace(/\n/g, '')); +}; diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/test/idleness.txt b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/test/idleness.txt new file mode 100644 index 0000000..aa3f490 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/test/idleness.txt @@ -0,0 +1,63 @@ +In Praise of Idleness + +By Bertrand Russell + +[1932] + +Like most of my generation, I was brought up on the saying: 'Satan finds some mischief for idle hands to do.' Being a highly virtuous child, I believed all that I was told, and acquired a conscience which has kept me working hard down to the present moment. But although my conscience has controlled my actions, my opinions have undergone a revolution. I think that there is far too much work done in the world, that immense harm is caused by the belief that work is virtuous, and that what needs to be preached in modern industrial countries is quite different from what always has been preached. Everyone knows the story of the traveler in Naples who saw twelve beggars lying in the sun (it was before the days of Mussolini), and offered a lira to the laziest of them. Eleven of them jumped up to claim it, so he gave it to the twelfth. this traveler was on the right lines. But in countries which do not enjoy Mediterranean sunshine idleness is more difficult, and a great public propaganda will be required to inaugurate it. I hope that, after reading the following pages, the leaders of the YMCA will start a campaign to induce good young men to do nothing. If so, I shall not have lived in vain. + +Before advancing my own arguments for laziness, I must dispose of one which I cannot accept. Whenever a person who already has enough to live on proposes to engage in some everyday kind of job, such as school-teaching or typing, he or she is told that such conduct takes the bread out of other people's mouths, and is therefore wicked. If this argument were valid, it would only be necessary for us all to be idle in order that we should all have our mouths full of bread. What people who say such things forget is that what a man earns he usually spends, and in spending he gives employment. As long as a man spends his income, he puts just as much bread into people's mouths in spending as he takes out of other people's mouths in earning. The real villain, from this point of view, is the man who saves. If he merely puts his savings in a stocking, like the proverbial French peasant, it is obvious that they do not give employment. If he invests his savings, the matter is less obvious, and different cases arise. + +One of the commonest things to do with savings is to lend them to some Government. In view of the fact that the bulk of the public expenditure of most civilized Governments consists in payment for past wars or preparation for future wars, the man who lends his money to a Government is in the same position as the bad men in Shakespeare who hire murderers. The net result of the man's economical habits is to increase the armed forces of the State to which he lends his savings. Obviously it would be better if he spent the money, even if he spent it in drink or gambling. + +But, I shall be told, the case is quite different when savings are invested in industrial enterprises. When such enterprises succeed, and produce something useful, this may be conceded. In these days, however, no one will deny that most enterprises fail. That means that a large amount of human labor, which might have been devoted to producing something that could be enjoyed, was expended on producing machines which, when produced, lay idle and did no good to anyone. The man who invests his savings in a concern that goes bankrupt is therefore injuring others as well as himself. If he spent his money, say, in giving parties for his friends, they (we may hope) would get pleasure, and so would all those upon whom he spent money, such as the butcher, the baker, and the bootlegger. But if he spends it (let us say) upon laying down rails for surface card in some place where surface cars turn out not to be wanted, he has diverted a mass of labor into channels where it gives pleasure to no one. Nevertheless, when he becomes poor through failure of his investment he will be regarded as a victim of undeserved misfortune, whereas the gay spendthrift, who has spent his money philanthropically, will be despised as a fool and a frivolous person. + +All this is only preliminary. I want to say, in all seriousness, that a great deal of harm is being done in the modern world by belief in the virtuousness of work, and that the road to happiness and prosperity lies in an organized diminution of work. + +First of all: what is work? Work is of two kinds: first, altering the position of matter at or near the earth's surface relatively to other such matter; second, telling other people to do so. The first kind is unpleasant and ill paid; the second is pleasant and highly paid. The second kind is capable of indefinite extension: there are not only those who give orders, but those who give advice as to what orders should be given. Usually two opposite kinds of advice are given simultaneously by two organized bodies of men; this is called politics. The skill required for this kind of work is not knowledge of the subjects as to which advice is given, but knowledge of the art of persuasive speaking and writing, i.e. of advertising. + +Throughout Europe, though not in America, there is a third class of men, more respected than either of the classes of workers. There are men who, through ownership of land, are able to make others pay for the privilege of being allowed to exist and to work. These landowners are idle, and I might therefore be expected to praise them. Unfortunately, their idleness is only rendered possible by the industry of others; indeed their desire for comfortable idleness is historically the source of the whole gospel of work. The last thing they have ever wished is that others should follow their example. + +From the beginning of civilization until the Industrial Revolution, a man could, as a rule, produce by hard work little more than was required for the subsistence of himself and his family, although his wife worked at least as hard as he did, and his children added their labor as soon as they were old enough to do so. The small surplus above bare necessaries was not left to those who produced it, but was appropriated by warriors and priests. In times of famine there was no surplus; the warriors and priests, however, still secured as much as at other times, with the result that many of the workers died of hunger. This system persisted in Russia until 1917 [1], and still persists in the East; in England, in spite of the Industrial Revolution, it remained in full force throughout the Napoleonic wars, and until a hundred years ago, when the new class of manufacturers acquired power. In America, the system came to an end with the Revolution, except in the South, where it persisted until the Civil War. A system which lasted so long and ended so recently has naturally left a profound impress upon men's thoughts and opinions. Much that we take for granted about the desirability of work is derived from this system, and, being pre-industrial, is not adapted to the modern world. Modern technique has made it possible for leisure, within limits, to be not the prerogative of small privileged classes, but a right evenly distributed throughout the community. The morality of work is the morality of slaves, and the modern world has no need of slavery. + +It is obvious that, in primitive communities, peasants, left to themselves, would not have parted with the slender surplus upon which the warriors and priests subsisted, but would have either produced less or consumed more. At first, sheer force compelled them to produce and part with the surplus. Gradually, however, it was found possible to induce many of them to accept an ethic according to which it was their duty to work hard, although part of their work went to support others in idleness. By this means the amount of compulsion required was lessened, and the expenses of government were diminished. To this day, 99 per cent of British wage-earners would be genuinely shocked if it were proposed that the King should not have a larger income than a working man. The conception of duty, speaking historically, has been a means used by the holders of power to induce others to live for the interests of their masters rather than for their own. Of course the holders of power conceal this fact from themselves by managing to believe that their interests are identical with the larger interests of humanity. Sometimes this is true; Athenian slave-owners, for instance, employed part of their leisure in making a permanent contribution to civilization which would have been impossible under a just economic system. Leisure is essential to civilization, and in former times leisure for the few was only rendered possible by the labors of the many. But their labors were valuable, not because work is good, but because leisure is good. And with modern technique it would be possible to distribute leisure justly without injury to civilization. + +Modern technique has made it possible to diminish enormously the amount of labor required to secure the necessaries of life for everyone. This was made obvious during the war. At that time all the men in the armed forces, and all the men and women engaged in the production of munitions, all the men and women engaged in spying, war propaganda, or Government offices connected with the war, were withdrawn from productive occupations. In spite of this, the general level of well-being among unskilled wage-earners on the side of the Allies was higher than before or since. The significance of this fact was concealed by finance: borrowing made it appear as if the future was nourishing the present. But that, of course, would have been impossible; a man cannot eat a loaf of bread that does not yet exist. The war showed conclusively that, by the scientific organization of production, it is possible to keep modern populations in fair comfort on a small part of the working capacity of the modern world. If, at the end of the war, the scientific organization, which had been created in order to liberate men for fighting and munition work, had been preserved, and the hours of the week had been cut down to four, all would have been well. Instead of that the old chaos was restored, those whose work was demanded were made to work long hours, and the rest were left to starve as unemployed. Why? Because work is a duty, and a man should not receive wages in proportion to what he has produced, but in proportion to his virtue as exemplified by his industry. + +This is the morality of the Slave State, applied in circumstances totally unlike those in which it arose. No wonder the result has been disastrous. Let us take an illustration. Suppose that, at a given moment, a certain number of people are engaged in the manufacture of pins. They make as many pins as the world needs, working (say) eight hours a day. Someone makes an invention by which the same number of men can make twice as many pins: pins are already so cheap that hardly any more will be bought at a lower price. In a sensible world, everybody concerned in the manufacturing of pins would take to working four hours instead of eight, and everything else would go on as before. But in the actual world this would be thought demoralizing. The men still work eight hours, there are too many pins, some employers go bankrupt, and half the men previously concerned in making pins are thrown out of work. There is, in the end, just as much leisure as on the other plan, but half the men are totally idle while half are still overworked. In this way, it is insured that the unavoidable leisure shall cause misery all round instead of being a universal source of happiness. Can anything more insane be imagined? + +The idea that the poor should have leisure has always been shocking to the rich. In England, in the early nineteenth century, fifteen hours was the ordinary day's work for a man; children sometimes did as much, and very commonly did twelve hours a day. When meddlesome busybodies suggested that perhaps these hours were rather long, they were told that work kept adults from drink and children from mischief. When I was a child, shortly after urban working men had acquired the vote, certain public holidays were established by law, to the great indignation of the upper classes. I remember hearing an old Duchess say: 'What do the poor want with holidays? They ought to work.' People nowadays are less frank, but the sentiment persists, and is the source of much of our economic confusion. + +Let us, for a moment, consider the ethics of work frankly, without superstition. Every human being, of necessity, consumes, in the course of his life, a certain amount of the produce of human labor. Assuming, as we may, that labor is on the whole disagreeable, it is unjust that a man should consume more than he produces. Of course he may provide services rather than commodities, like a medical man, for example; but he should provide something in return for his board and lodging. to this extent, the duty of work must be admitted, but to this extent only. + +I shall not dwell upon the fact that, in all modern societies outside the USSR, many people escape even this minimum amount of work, namely all those who inherit money and all those who marry money. I do not think the fact that these people are allowed to be idle is nearly so harmful as the fact that wage-earners are expected to overwork or starve. + +If the ordinary wage-earner worked four hours a day, there would be enough for everybody and no unemployment -- assuming a certain very moderate amount of sensible organization. This idea shocks the well-to-do, because they are convinced that the poor would not know how to use so much leisure. In America men often work long hours even when they are well off; such men, naturally, are indignant at the idea of leisure for wage-earners, except as the grim punishment of unemployment; in fact, they dislike leisure even for their sons. Oddly enough, while they wish their sons to work so hard as to have no time to be civilized, they do not mind their wives and daughters having no work at all. the snobbish admiration of uselessness, which, in an aristocratic society, extends to both sexes, is, under a plutocracy, confined to women; this, however, does not make it any more in agreement with common sense. + +The wise use of leisure, it must be conceded, is a product of civilization and education. A man who has worked long hours all his life will become bored if he becomes suddenly idle. But without a considerable amount of leisure a man is cut off from many of the best things. There is no longer any reason why the bulk of the population should suffer this deprivation; only a foolish asceticism, usually vicarious, makes us continue to insist on work in excessive quantities now that the need no longer exists. + +In the new creed which controls the government of Russia, while there is much that is very different from the traditional teaching of the West, there are some things that are quite unchanged. The attitude of the governing classes, and especially of those who conduct educational propaganda, on the subject of the dignity of labor, is almost exactly that which the governing classes of the world have always preached to what were called the 'honest poor'. Industry, sobriety, willingness to work long hours for distant advantages, even submissiveness to authority, all these reappear; moreover authority still represents the will of the Ruler of the Universe, Who, however, is now called by a new name, Dialectical Materialism. + +The victory of the proletariat in Russia has some points in common with the victory of the feminists in some other countries. For ages, men had conceded the superior saintliness of women, and had consoled women for their inferiority by maintaining that saintliness is more desirable than power. At last the feminists decided that they would have both, since the pioneers among them believed all that the men had told them about the desirability of virtue, but not what they had told them about the worthlessness of political power. A similar thing has happened in Russia as regards manual work. For ages, the rich and their sycophants have written in praise of 'honest toil', have praised the simple life, have professed a religion which teaches that the poor are much more likely to go to heaven than the rich, and in general have tried to make manual workers believe that there is some special nobility about altering the position of matter in space, just as men tried to make women believe that they derived some special nobility from their sexual enslavement. In Russia, all this teaching about the excellence of manual work has been taken seriously, with the result that the manual worker is more honored than anyone else. What are, in essence, revivalist appeals are made, but not for the old purposes: they are made to secure shock workers for special tasks. Manual work is the ideal which is held before the young, and is the basis of all ethical teaching. + +For the present, possibly, this is all to the good. A large country, full of natural resources, awaits development, and has has to be developed with very little use of credit. In these circumstances, hard work is necessary, and is likely to bring a great reward. But what will happen when the point has been reached where everybody could be comfortable without working long hours? + +In the West, we have various ways of dealing with this problem. We have no attempt at economic justice, so that a large proportion of the total produce goes to a small minority of the population, many of whom do no work at all. Owing to the absence of any central control over production, we produce hosts of things that are not wanted. We keep a large percentage of the working population idle, because we can dispense with their labor by making the others overwork. When all these methods prove inadequate, we have a war: we cause a number of people to manufacture high explosives, and a number of others to explode them, as if we were children who had just discovered fireworks. By a combination of all these devices we manage, though with difficulty, to keep alive the notion that a great deal of severe manual work must be the lot of the average man. + +In Russia, owing to more economic justice and central control over production, the problem will have to be differently solved. the rational solution would be, as soon as the necessaries and elementary comforts can be provided for all, to reduce the hours of labor gradually, allowing a popular vote to decide, at each stage, whether more leisure or more goods were to be preferred. But, having taught the supreme virtue of hard work, it is difficult to see how the authorities can aim at a paradise in which there will be much leisure and little work. It seems more likely that they will find continually fresh schemes, by which present leisure is to be sacrificed to future productivity. I read recently of an ingenious plan put forward by Russian engineers, for making the White Sea and the northern coasts of Siberia warm, by putting a dam across the Kara Sea. An admirable project, but liable to postpone proletarian comfort for a generation, while the nobility of toil is being displayed amid the ice-fields and snowstorms of the Arctic Ocean. This sort of thing, if it happens, will be the result of regarding the virtue of hard work as an end in itself, rather than as a means to a state of affairs in which it is no longer needed. + +The fact is that moving matter about, while a certain amount of it is necessary to our existence, is emphatically not one of the ends of human life. If it were, we should have to consider every navvy superior to Shakespeare. We have been misled in this matter by two causes. One is the necessity of keeping the poor contented, which has led the rich, for thousands of years, to preach the dignity of labor, while taking care themselves to remain undignified in this respect. The other is the new pleasure in mechanism, which makes us delight in the astonishingly clever changes that we can produce on the earth's surface. Neither of these motives makes any great appeal to the actual worker. If you ask him what he thinks the best part of his life, he is not likely to say: 'I enjoy manual work because it makes me feel that I am fulfilling man's noblest task, and because I like to think how much man can transform his planet. It is true that my body demands periods of rest, which I have to fill in as best I may, but I am never so happy as when the morning comes and I can return to the toil from which my contentment springs.' I have never heard working men say this sort of thing. They consider work, as it should be considered, a necessary means to a livelihood, and it is from their leisure that they derive whatever happiness they may enjoy. + +It will be said that, while a little leisure is pleasant, men would not know how to fill their days if they had only four hours of work out of the twenty-four. In so far as this is true in the modern world, it is a condemnation of our civilization; it would not have been true at any earlier period. There was formerly a capacity for light-heartedness and play which has been to some extent inhibited by the cult of efficiency. The modern man thinks that everything ought to be done for the sake of something else, and never for its own sake. Serious-minded persons, for example, are continually condemning the habit of going to the cinema, and telling us that it leads the young into crime. But all the work that goes to producing a cinema is respectable, because it is work, and because it brings a money profit. The notion that the desirable activities are those that bring a profit has made everything topsy-turvy. The butcher who provides you with meat and the baker who provides you with bread are praiseworthy, because they are making money; but when you enjoy the food they have provided, you are merely frivolous, unless you eat only to get strength for your work. Broadly speaking, it is held that getting money is good and spending money is bad. Seeing that they are two sides of one transaction, this is absurd; one might as well maintain that keys are good, but keyholes are bad. Whatever merit there may be in the production of goods must be entirely derivative from the advantage to be obtained by consuming them. The individual, in our society, works for profit; but the social purpose of his work lies in the consumption of what he produces. It is this divorce between the individual and the social purpose of production that makes it so difficult for men to think clearly in a world in which profit-making is the incentive to industry. We think too much of production, and too little of consumption. One result is that we attach too little importance to enjoyment and simple happiness, and that we do not judge production by the pleasure that it gives to the consumer. + +When I suggest that working hours should be reduced to four, I am not meaning to imply that all the remaining time should necessarily be spent in pure frivolity. I mean that four hours' work a day should entitle a man to the necessities and elementary comforts of life, and that the rest of his time should be his to use as he might see fit. It is an essential part of any such social system that education should be carried further than it usually is at present, and should aim, in part, at providing tastes which would enable a man to use leisure intelligently. I am not thinking mainly of the sort of things that would be considered 'highbrow'. Peasant dances have died out except in remote rural areas, but the impulses which caused them to be cultivated must still exist in human nature. The pleasures of urban populations have become mainly passive: seeing cinemas, watching football matches, listening to the radio, and so on. This results from the fact that their active energies are fully taken up with work; if they had more leisure, they would again enjoy pleasures in which they took an active part. + +In the past, there was a small leisure class and a larger working class. The leisure class enjoyed advantages for which there was no basis in social justice; this necessarily made it oppressive, limited its sympathies, and caused it to invent theories by which to justify its privileges. These facts greatly diminished its excellence, but in spite of this drawback it contributed nearly the whole of what we call civilization. It cultivated the arts and discovered the sciences; it wrote the books, invented the philosophies, and refined social relations. Even the liberation of the oppressed has usually been inaugurated from above. Without the leisure class, mankind would never have emerged from barbarism. + +The method of a leisure class without duties was, however, extraordinarily wasteful. None of the members of the class had to be taught to be industrious, and the class as a whole was not exceptionally intelligent. The class might produce one Darwin, but against him had to be set tens of thousands of country gentlemen who never thought of anything more intelligent than fox-hunting and punishing poachers. At present, the universities are supposed to provide, in a more systematic way, what the leisure class provided accidentally and as a by-product. This is a great improvement, but it has certain drawbacks. University life is so different from life in the world at large that men who live in academic milieu tend to be unaware of the preoccupations and problems of ordinary men and women; moreover their ways of expressing themselves are usually such as to rob their opinions of the influence that they ought to have upon the general public. Another disadvantage is that in universities studies are organized, and the man who thinks of some original line of research is likely to be discouraged. Academic institutions, therefore, useful as they are, are not adequate guardians of the interests of civilization in a world where everyone outside their walls is too busy for unutilitarian pursuits. + +In a world where no one is compelled to work more than four hours a day, every person possessed of scientific curiosity will be able to indulge it, and every painter will be able to paint without starving, however excellent his pictures may be. Young writers will not be obliged to draw attention to themselves by sensational pot-boilers, with a view to acquiring the economic independence needed for monumental works, for which, when the time at last comes, they will have lost the taste and capacity. Men who, in their professional work, have become interested in some phase of economics or government, will be able to develop their ideas without the academic detachment that makes the work of university economists often seem lacking in reality. Medical men will have the time to learn about the progress of medicine, teachers will not be exasperatedly struggling to teach by routine methods things which they learnt in their youth, which may, in the interval, have been proved to be untrue. + +Above all, there will be happiness and joy of life, instead of frayed nerves, weariness, and dyspepsia. The work exacted will be enough to make leisure delightful, but not enough to produce exhaustion. Since men will not be tired in their spare time, they will not demand only such amusements as are passive and vapid. At least one per cent will probably devote the time not spent in professional work to pursuits of some public importance, and, since they will not depend upon these pursuits for their livelihood, their originality will be unhampered, and there will be no need to conform to the standards set by elderly pundits. But it is not only in these exceptional cases that the advantages of leisure will appear. Ordinary men and women, having the opportunity of a happy life, will become more kindly and less persecuting and less inclined to view others with suspicion. The taste for war will die out, partly for this reason, and partly because it will involve long and severe work for all. Good nature is, of all moral qualities, the one that the world needs most, and good nature is the result of ease and security, not of a life of arduous struggle. Modern methods of production have given us the possibility of ease and security for all; we have chosen, instead, to have overwork for some and starvation for others. Hitherto we have continued to be as energetic as we were before there were machines; in this we have been foolish, but there is no reason to go on being foolish forever. + +[1] Since then, members of the Communist Party have succeeded to this privilege of the warriors and priests. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/test/wrap.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/test/wrap.js new file mode 100644 index 0000000..0cfb76d --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/node_modules/wordwrap/test/wrap.js @@ -0,0 +1,31 @@ +var assert = require('assert'); +var wordwrap = require('wordwrap'); + +var fs = require('fs'); +var idleness = fs.readFileSync(__dirname + '/idleness.txt', 'utf8'); + +exports.stop80 = function () { + var lines = wordwrap(80)(idleness).split(/\n/); + var words = idleness.split(/\s+/); + + lines.forEach(function (line) { + assert.ok(line.length <= 80, 'line > 80 columns'); + var chunks = line.match(/\S/) ? line.split(/\s+/) : []; + assert.deepEqual(chunks, words.splice(0, chunks.length)); + }); +}; + +exports.start20stop60 = function () { + var lines = wordwrap(20, 100)(idleness).split(/\n/); + var words = idleness.split(/\s+/); + + lines.forEach(function (line) { + assert.ok(line.length <= 100, 'line > 100 columns'); + var chunks = line + .split(/\s+/) + .filter(function (x) { return x.match(/\S/) }) + ; + assert.deepEqual(chunks, words.splice(0, chunks.length)); + assert.deepEqual(line.slice(0, 20), new Array(20 + 1).join(' ')); + }); +}; diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/package.json new file mode 100644 index 0000000..bbe848c --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/package.json @@ -0,0 +1,46 @@ +{ + "name": "optimist", + "version": "0.2.8", + "description": "Light-weight option parsing with an argv hash. No optstrings attached.", + "main": "./index.js", + "directories": { + "lib": ".", + "test": "test", + "example": "examples" + }, + "dependencies": { + "wordwrap": ">=0.0.1 <0.1.0" + }, + "devDependencies": { + "hashish": "0.0.x", + "expresso": "0.7.x" + }, + "scripts": { + "test": "expresso" + }, + "repository": { + "type": "git", + "url": "http://github.com/substack/node-optimist.git" + }, + "keywords": [ + "argument", + "args", + "option", + "parser", + "parsing", + "cli", + "command" + ], + "author": { + "name": "James Halliday", + "email": "mail@substack.net", + "url": "http://substack.net" + }, + "license": "MIT/X11", + "engine": { + "node": ">=0.4" + }, + "readme": "optimist\n========\n\nOptimist is a node.js library for option parsing for people who hate option\nparsing. More specifically, this module is for people who like all the --bells\nand -whistlz of program usage but think optstrings are a waste of time.\n\nWith optimist, option parsing doesn't have to suck (as much).\n\nexamples\n========\n\nWith Optimist, the options are just a hash! No optstrings attached.\n-------------------------------------------------------------------\n\nxup.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist').argv;\n\nif (argv.rif - 5 * argv.xup > 7.138) {\n console.log('Buy more riffiwobbles');\n}\nelse {\n console.log('Sell the xupptumblers');\n}\n````\n\n***\n\n $ ./xup.js --rif=55 --xup=9.52\n Buy more riffiwobbles\n \n $ ./xup.js --rif 12 --xup 8.1\n Sell the xupptumblers\n\n![This one's optimistic.](http://substack.net/images/optimistic.png)\n\nBut wait! There's more! You can do short options:\n-------------------------------------------------\n \nshort.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist').argv;\nconsole.log('(%d,%d)', argv.x, argv.y);\n````\n\n***\n\n $ ./short.js -x 10 -y 21\n (10,21)\n\nAnd booleans, both long and short (and grouped):\n----------------------------------\n\nbool.js:\n\n````javascript\n#!/usr/bin/env node\nvar util = require('util');\nvar argv = require('optimist').argv;\n\nif (argv.s) {\n util.print(argv.fr ? 'Le chat dit: ' : 'The cat says: ');\n}\nconsole.log(\n (argv.fr ? 'miaou' : 'meow') + (argv.p ? '.' : '')\n);\n````\n\n***\n\n $ ./bool.js -s\n The cat says: meow\n \n $ ./bool.js -sp\n The cat says: meow.\n\n $ ./bool.js -sp --fr\n Le chat dit: miaou.\n\nAnd non-hypenated options too! Just use `argv._`!\n-------------------------------------------------\n \nnonopt.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist').argv;\nconsole.log('(%d,%d)', argv.x, argv.y);\nconsole.log(argv._);\n````\n\n***\n\n $ ./nonopt.js -x 6.82 -y 3.35 moo\n (6.82,3.35)\n [ 'moo' ]\n \n $ ./nonopt.js foo -x 0.54 bar -y 1.12 baz\n (0.54,1.12)\n [ 'foo', 'bar', 'baz' ]\n\nPlus, Optimist comes with .usage() and .demand()!\n-------------------------------------------------\n\ndivide.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .usage('Usage: $0 -x [num] -y [num]')\n .demand(['x','y'])\n .argv;\n\nconsole.log(argv.x / argv.y);\n````\n\n***\n \n $ ./divide.js -x 55 -y 11\n 5\n \n $ node ./divide.js -x 4.91 -z 2.51\n Usage: node ./divide.js -x [num] -y [num]\n\n Options:\n -x [required]\n -y [required]\n\n Missing required arguments: y\n\nEVEN MORE HOLY COW\n------------------\n\ndefault_singles.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .default('x', 10)\n .default('y', 10)\n .argv\n;\nconsole.log(argv.x + argv.y);\n````\n\n***\n\n $ ./default_singles.js -x 5\n 15\n\ndefault_hash.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .default({ x : 10, y : 10 })\n .argv\n;\nconsole.log(argv.x + argv.y);\n````\n\n***\n\n $ ./default_hash.js -y 7\n 17\n\nAnd if you really want to get all descriptive about it...\n---------------------------------------------------------\n\nboolean_single.js\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .boolean('v')\n .argv\n;\nconsole.dir(argv);\n````\n\n***\n\n $ ./boolean_single.js -v foo bar baz\n true\n [ 'bar', 'baz', 'foo' ]\n\nboolean_double.js\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .boolean(['x','y','z'])\n .argv\n;\nconsole.dir([ argv.x, argv.y, argv.z ]);\nconsole.dir(argv._);\n````\n\n***\n\n $ ./boolean_double.js -x -z one two three\n [ true, false, true ]\n [ 'one', 'two', 'three' ]\n\nOptimist is here to help...\n---------------------------\n\nYou can describe parameters for help messages and set aliases. Optimist figures\nout how to format a handy help string automatically.\n\nline_count.js\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .usage('Count the lines in a file.\\nUsage: $0')\n .demand('f')\n .alias('f', 'file')\n .describe('f', 'Load a file')\n .argv\n;\n\nvar fs = require('fs');\nvar s = fs.createReadStream(argv.file);\n\nvar lines = 0;\ns.on('data', function (buf) {\n lines += buf.toString().match(/\\n/g).length;\n});\n\ns.on('end', function () {\n console.log(lines);\n});\n````\n\n***\n\n $ node line_count.js\n Count the lines in a file.\n Usage: node ./line_count.js\n\n Options:\n -f, --file Load a file [required]\n\n Missing required arguments: f\n\n $ node line_count.js --file line_count.js \n 20\n \n $ node line_count.js -f line_count.js \n 20\n\nmethods\n=======\n\nBy itself,\n\n````javascript\nrequire('optimist').argv\n`````\n\nwill use `process.argv` array to construct the `argv` object.\n\nYou can pass in the `process.argv` yourself:\n\n````javascript\nrequire('optimist')([ '-x', '1', '-y', '2' ]).argv\n````\n\nor use .parse() to do the same thing:\n\n````javascript\nrequire('optimist').parse([ '-x', '1', '-y', '2' ])\n````\n\nThe rest of these methods below come in just before the terminating `.argv`.\n\n.alias(key, alias)\n------------------\n\nSet key names as equivalent such that updates to a key will propagate to aliases\nand vice-versa.\n\nOptionally `.alias()` can take an object that maps keys to aliases.\n\n.default(key, value)\n--------------------\n\nSet `argv[key]` to `value` if no option was specified on `process.argv`.\n\nOptionally `.default()` can take an object that maps keys to default values.\n\n.demand(key)\n------------\n\nIf `key` is a string, show the usage information and exit if `key` wasn't\nspecified in `process.argv`.\n\nIf `key` is a number, demand at least as many non-option arguments, which show\nup in `argv._`.\n\nIf `key` is an Array, demand each element.\n\n.describe(key, desc)\n--------------------\n\nDescribe a `key` for the generated usage information.\n\nOptionally `.describe()` can take an object that maps keys to descriptions.\n\n.options(key, opt)\n------------------\n\nInstead of chaining together `.alias().demand().default()`, you can specify\nkeys in `opt` for each of the chainable methods.\n\nFor example:\n\n````javascript\nvar argv = require('optimist')\n .options('f', {\n alias : 'file',\n default : '/etc/passwd',\n })\n .argv\n;\n````\n\nis the same as\n\n````javascript\nvar argv = require('optimist')\n .alias('f', 'file')\n .default('f', '/etc/passwd')\n .argv\n;\n````\n\nOptionally `.options()` can take an object that maps keys to `opt` parameters.\n\n.usage(message)\n---------------\n\nSet a usage message to show which commands to use. Inside `message`, the string\n`$0` will get interpolated to the current script name or node command for the\npresent script similar to how `$0` works in bash or perl.\n\n.check(fn)\n----------\n\nCheck that certain conditions are met in the provided arguments.\n\nIf `fn` throws or returns `false`, show the thrown error, usage information, and\nexit.\n\n.boolean(key)\n-------------\n\nInterpret `key` as a boolean. If a non-flag option follows `key` in\n`process.argv`, that string won't get set as the value of `key`.\n\nIf `key` never shows up as a flag in `process.arguments`, `argv[key]` will be\n`false`.\n\nIf `key` is an Array, interpret all the elements as booleans.\n\n.string(key)\n------------\n\nTell the parser logic not to interpret `key` as a number or boolean.\nThis can be useful if you need to preserve leading zeros in an input.\n\nIf `key` is an Array, interpret all the elements as strings.\n\n.wrap(columns)\n--------------\n\nFormat usage output to wrap at `columns` many columns.\n\n.help()\n-------\n\nReturn the generated usage string.\n\n.showHelp(fn=console.error)\n---------------------------\n\nPrint the usage data using `fn` for printing.\n\n.parse(args)\n------------\n\nParse `args` instead of `process.argv`. Returns the `argv` object.\n\n.argv\n-----\n\nGet the arguments as a plain old object.\n\nArguments without a corresponding flag show up in the `argv._` array.\n\nThe script name or node command is available at `argv.$0` similarly to how `$0`\nworks in bash or perl.\n\nparsing tricks\n==============\n\nstop parsing\n------------\n\nUse `--` to stop parsing flags and stuff the remainder into `argv._`.\n\n $ node examples/reflect.js -a 1 -b 2 -- -c 3 -d 4\n { _: [ '-c', '3', '-d', '4' ],\n '$0': 'node ./examples/reflect.js',\n a: 1,\n b: 2 }\n\nnegate fields\n-------------\n\nIf you want to explicity set a field to false instead of just leaving it\nundefined or to override a default you can do `--no-key`.\n\n $ node examples/reflect.js -a --no-b\n { _: [],\n '$0': 'node ./examples/reflect.js',\n a: true,\n b: false }\n\nnumbers\n-------\n\nEvery argument that looks like a number (`!isNaN(Number(arg))`) is converted to\none. This way you can just `net.createConnection(argv.port)` and you can add\nnumbers out of `argv` with `+` without having that mean concatenation,\nwhich is super frustrating.\n\nduplicates\n----------\n\nIf you specify a flag multiple times it will get turned into an array containing\nall the values in order.\n\n $ node examples/reflect.js -x 5 -x 8 -x 0\n { _: [],\n '$0': 'node ./examples/reflect.js',\n x: [ 5, 8, 0 ] }\n\ninstallation\n============\n\nWith [npm](http://github.com/isaacs/npm), just do:\n npm install optimist\n \nor clone this project on github:\n\n git clone http://github.com/substack/node-optimist.git\n\nTo run the tests with [expresso](http://github.com/visionmedia/expresso),\njust do:\n \n expresso\n\ninspired By\n===========\n\nThis module is loosely inspired by Perl's\n[Getopt::Casual](http://search.cpan.org/~photo/Getopt-Casual-0.13.1/Casual.pm).\n", + "_id": "optimist@0.2.8", + "_from": "optimist@0.2" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/test/_.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/test/_.js new file mode 100644 index 0000000..3d6df6e --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/test/_.js @@ -0,0 +1,66 @@ +var spawn = require('child_process').spawn; +var assert = require('assert'); + +exports.dotSlashEmpty = function () { + testCmd('./bin.js', []); +}; + +exports.dotSlashArgs = function () { + testCmd('./bin.js', [ 'a', 'b', 'c' ]); +}; + +exports.nodeEmpty = function () { + testCmd('node bin.js', []); +}; + +exports.nodeArgs = function () { + testCmd('node bin.js', [ 'x', 'y', 'z' ]); +}; + +exports.whichNodeEmpty = function () { + var which = spawn('which', ['node']); + + which.stdout.on('data', function (buf) { + testCmd(buf.toString().trim() + ' bin.js', []); + }); + + which.stderr.on('data', function (err) { + assert.fail(err.toString()); + }); +}; + +exports.whichNodeArgs = function () { + var which = spawn('which', ['node']); + + which.stdout.on('data', function (buf) { + testCmd(buf.toString().trim() + ' bin.js', [ 'q', 'r' ]); + }); + + which.stderr.on('data', function (err) { + assert.fail(err.toString()); + }); +}; + +function testCmd (cmd, args) { + var to = setTimeout(function () { + assert.fail('Never got stdout data.') + }, 5000); + + var oldDir = process.cwd(); + process.chdir(__dirname + '/_'); + + var cmds = cmd.split(' '); + + var bin = spawn(cmds[0], cmds.slice(1).concat(args.map(String))); + process.chdir(oldDir); + + bin.stderr.on('data', function (err) { + assert.fail(err.toString()); + }); + + bin.stdout.on('data', function (buf) { + clearTimeout(to); + var _ = JSON.parse(buf.toString()); + assert.eql(_.map(String), args.map(String)); + }); +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/test/_/argv.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/test/_/argv.js new file mode 100644 index 0000000..3d09606 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/test/_/argv.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +console.log(JSON.stringify(process.argv)); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/test/_/bin.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/test/_/bin.js new file mode 100755 index 0000000..4a18d85 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/test/_/bin.js @@ -0,0 +1,3 @@ +#!/usr/bin/env node +var argv = require('../../index').argv +console.log(JSON.stringify(argv._)); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/test/parse.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/test/parse.js new file mode 100644 index 0000000..eed467e --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/test/parse.js @@ -0,0 +1,304 @@ +var optimist = require('../index'); +var assert = require('assert'); +var path = require('path'); + +var localExpresso = path.normalize( + __dirname + '/../node_modules/.bin/expresso' +); + +var expresso = process.argv[1] === localExpresso + ? 'node ./node_modules/.bin/expresso' + : 'expresso' +; + +exports['short boolean'] = function () { + var parse = optimist.parse([ '-b' ]); + assert.eql(parse, { b : true, _ : [], $0 : expresso }); + assert.eql(typeof parse.b, 'boolean'); +}; + +exports['long boolean'] = function () { + assert.eql( + optimist.parse([ '--bool' ]), + { bool : true, _ : [], $0 : expresso } + ); +}; + +exports.bare = function () { + assert.eql( + optimist.parse([ 'foo', 'bar', 'baz' ]), + { _ : [ 'foo', 'bar', 'baz' ], $0 : expresso } + ); +}; + +exports['short group'] = function () { + assert.eql( + optimist.parse([ '-cats' ]), + { c : true, a : true, t : true, s : true, _ : [], $0 : expresso } + ); +}; + +exports['short group next'] = function () { + assert.eql( + optimist.parse([ '-cats', 'meow' ]), + { c : true, a : true, t : true, s : 'meow', _ : [], $0 : expresso } + ); +}; + +exports['short capture'] = function () { + assert.eql( + optimist.parse([ '-h', 'localhost' ]), + { h : 'localhost', _ : [], $0 : expresso } + ); +}; + +exports['short captures'] = function () { + assert.eql( + optimist.parse([ '-h', 'localhost', '-p', '555' ]), + { h : 'localhost', p : 555, _ : [], $0 : expresso } + ); +}; + +exports['long capture sp'] = function () { + assert.eql( + optimist.parse([ '--pow', 'xixxle' ]), + { pow : 'xixxle', _ : [], $0 : expresso } + ); +}; + +exports['long capture eq'] = function () { + assert.eql( + optimist.parse([ '--pow=xixxle' ]), + { pow : 'xixxle', _ : [], $0 : expresso } + ); +}; + +exports['long captures sp'] = function () { + assert.eql( + optimist.parse([ '--host', 'localhost', '--port', '555' ]), + { host : 'localhost', port : 555, _ : [], $0 : expresso } + ); +}; + +exports['long captures eq'] = function () { + assert.eql( + optimist.parse([ '--host=localhost', '--port=555' ]), + { host : 'localhost', port : 555, _ : [], $0 : expresso } + ); +}; + +exports['mixed short bool and capture'] = function () { + assert.eql( + optimist.parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]), + { + f : true, p : 555, h : 'localhost', + _ : [ 'script.js' ], $0 : expresso, + } + ); +}; + +exports['short and long'] = function () { + assert.eql( + optimist.parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]), + { + f : true, p : 555, h : 'localhost', + _ : [ 'script.js' ], $0 : expresso, + } + ); +}; + +exports.no = function () { + assert.eql( + optimist.parse([ '--no-moo' ]), + { moo : false, _ : [], $0 : expresso } + ); +}; + +exports.multi = function () { + assert.eql( + optimist.parse([ '-v', 'a', '-v', 'b', '-v', 'c' ]), + { v : ['a','b','c'], _ : [], $0 : expresso } + ); +}; + +exports.comprehensive = function () { + assert.eql( + optimist.parse([ + '--name=meowmers', 'bare', '-cats', 'woo', + '-h', 'awesome', '--multi=quux', + '--key', 'value', + '-b', '--bool', '--no-meep', '--multi=baz', + '--', '--not-a-flag', 'eek' + ]), + { + c : true, + a : true, + t : true, + s : 'woo', + h : 'awesome', + b : true, + bool : true, + key : 'value', + multi : [ 'quux', 'baz' ], + meep : false, + name : 'meowmers', + _ : [ 'bare', '--not-a-flag', 'eek' ], + $0 : expresso + } + ); +}; + +exports.nums = function () { + var argv = optimist.parse([ + '-x', '1234', + '-y', '5.67', + '-z', '1e7', + '-w', '10f', + '--hex', '0xdeadbeef', + '789', + ]); + assert.eql(argv, { + x : 1234, + y : 5.67, + z : 1e7, + w : '10f', + hex : 0xdeadbeef, + _ : [ 789 ], + $0 : expresso + }); + assert.eql(typeof argv.x, 'number'); + assert.eql(typeof argv.y, 'number'); + assert.eql(typeof argv.z, 'number'); + assert.eql(typeof argv.w, 'string'); + assert.eql(typeof argv.hex, 'number'); + assert.eql(typeof argv._[0], 'number'); +}; + +exports['flag boolean'] = function () { + var parse = optimist([ '-t', 'moo' ]).boolean(['t']).argv; + assert.eql(parse, { t : true, _ : [ 'moo' ], $0 : expresso }); + assert.eql(typeof parse.t, 'boolean'); +}; + +exports['flag boolean value'] = function () { + var parse = optimist(['--verbose', 'false', 'moo', '-t', 'true']) + .boolean(['t', 'verbose']).default('verbose', true).argv; + + assert.eql(parse, { + verbose: false, + t: true, + _: ['moo'], + $0 : expresso + }); + + assert.eql(typeof parse.verbose, 'boolean'); + assert.eql(typeof parse.t, 'boolean'); +}; + +exports['flag boolean default false'] = function () { + var parse = optimist(['moo']) + .boolean(['t', 'verbose']) + .default('verbose', false) + .default('t', false).argv; + + assert.eql(parse, { + verbose: false, + t: false, + _: ['moo'], + $0 : expresso + }); + + assert.eql(typeof parse.verbose, 'boolean'); + assert.eql(typeof parse.t, 'boolean'); + +}; + +exports['boolean groups'] = function () { + var parse = optimist([ '-x', '-z', 'one', 'two', 'three' ]) + .boolean(['x','y','z']).argv; + + assert.eql(parse, { + x : true, + y : false, + z : true, + _ : [ 'one', 'two', 'three' ], + $0 : expresso + }); + + assert.eql(typeof parse.x, 'boolean'); + assert.eql(typeof parse.y, 'boolean'); + assert.eql(typeof parse.z, 'boolean'); +}; + +exports.strings = function () { + var s = optimist([ '-s', '0001234' ]).string('s').argv.s; + assert.eql(s, '0001234'); + assert.eql(typeof s, 'string'); + + var x = optimist([ '-x', '56' ]).string('x').argv.x; + assert.eql(x, '56'); + assert.eql(typeof x, 'string'); +}; + +exports.stringArgs = function () { + var s = optimist([ ' ', ' ' ]).string('_').argv._; + assert.eql(s.length, 2); + assert.eql(typeof s[0], 'string'); + assert.eql(s[0], ' '); + assert.eql(typeof s[1], 'string'); + assert.eql(s[1], ' '); +}; + +exports.slashBreak = function () { + assert.eql( + optimist.parse([ '-I/foo/bar/baz' ]), + { I : '/foo/bar/baz', _ : [], $0 : expresso } + ); + assert.eql( + optimist.parse([ '-xyz/foo/bar/baz' ]), + { x : true, y : true, z : '/foo/bar/baz', _ : [], $0 : expresso } + ); +}; + +exports.alias = function () { + var argv = optimist([ '-f', '11', '--zoom', '55' ]) + .alias('z', 'zoom') + .argv + ; + assert.equal(argv.zoom, 55); + assert.equal(argv.z, argv.zoom); + assert.equal(argv.f, 11); +}; + +exports.multiAlias = function () { + var argv = optimist([ '-f', '11', '--zoom', '55' ]) + .alias('z', [ 'zm', 'zoom' ]) + .argv + ; + assert.equal(argv.zoom, 55); + assert.equal(argv.z, argv.zoom); + assert.equal(argv.z, argv.zm); + assert.equal(argv.f, 11); +}; + +exports['boolean default true'] = function () { + var argv = optimist.options({ + sometrue: { + boolean: true, + default: true + } + }).argv; + + assert.equal(argv.sometrue, true); +}; + +exports['boolean default false'] = function () { + var argv = optimist.options({ + somefalse: { + boolean: true, + default: false + } + }).argv; + + assert.equal(argv.somefalse, false); +}; diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/test/usage.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/test/usage.js new file mode 100644 index 0000000..6593b9b --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/optimist/test/usage.js @@ -0,0 +1,256 @@ +var Hash = require('hashish'); +var optimist = require('../index'); +var assert = require('assert'); + +exports.usageFail = function () { + var r = checkUsage(function () { + return optimist('-x 10 -z 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .demand(['x','y']) + .argv; + }); + assert.deepEqual( + r.result, + { x : 10, z : 20, _ : [], $0 : './usage' } + ); + + assert.deepEqual( + r.errors.join('\n').split(/\n+/), + [ + 'Usage: ./usage -x NUM -y NUM', + 'Options:', + ' -x [required]', + ' -y [required]', + 'Missing required arguments: y', + ] + ); + assert.deepEqual(r.logs, []); + assert.ok(r.exit); +}; + +exports.usagePass = function () { + var r = checkUsage(function () { + return optimist('-x 10 -y 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .demand(['x','y']) + .argv; + }); + assert.deepEqual(r, { + result : { x : 10, y : 20, _ : [], $0 : './usage' }, + errors : [], + logs : [], + exit : false, + }); +}; + +exports.checkPass = function () { + var r = checkUsage(function () { + return optimist('-x 10 -y 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .check(function (argv) { + if (!('x' in argv)) throw 'You forgot about -x'; + if (!('y' in argv)) throw 'You forgot about -y'; + }) + .argv; + }); + assert.deepEqual(r, { + result : { x : 10, y : 20, _ : [], $0 : './usage' }, + errors : [], + logs : [], + exit : false, + }); +}; + +exports.checkFail = function () { + var r = checkUsage(function () { + return optimist('-x 10 -z 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .check(function (argv) { + if (!('x' in argv)) throw 'You forgot about -x'; + if (!('y' in argv)) throw 'You forgot about -y'; + }) + .argv; + }); + + assert.deepEqual( + r.result, + { x : 10, z : 20, _ : [], $0 : './usage' } + ); + + assert.deepEqual( + r.errors.join('\n').split(/\n+/), + [ + 'Usage: ./usage -x NUM -y NUM', + 'You forgot about -y' + ] + ); + + assert.deepEqual(r.logs, []); + assert.ok(r.exit); +}; + +exports.checkCondPass = function () { + function checker (argv) { + return 'x' in argv && 'y' in argv; + } + + var r = checkUsage(function () { + return optimist('-x 10 -y 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .check(checker) + .argv; + }); + assert.deepEqual(r, { + result : { x : 10, y : 20, _ : [], $0 : './usage' }, + errors : [], + logs : [], + exit : false, + }); +}; + +exports.checkCondFail = function () { + function checker (argv) { + return 'x' in argv && 'y' in argv; + } + + var r = checkUsage(function () { + return optimist('-x 10 -z 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .check(checker) + .argv; + }); + + assert.deepEqual( + r.result, + { x : 10, z : 20, _ : [], $0 : './usage' } + ); + + assert.deepEqual( + r.errors.join('\n').split(/\n+/).join('\n'), + 'Usage: ./usage -x NUM -y NUM\n' + + 'Argument check failed: ' + checker.toString() + ); + + assert.deepEqual(r.logs, []); + assert.ok(r.exit); +}; + +exports.countPass = function () { + var r = checkUsage(function () { + return optimist('1 2 3 --moo'.split(' ')) + .usage('Usage: $0 [x] [y] [z] {OPTIONS}') + .demand(3) + .argv; + }); + assert.deepEqual(r, { + result : { _ : [ '1', '2', '3' ], moo : true, $0 : './usage' }, + errors : [], + logs : [], + exit : false, + }); +}; + +exports.countFail = function () { + var r = checkUsage(function () { + return optimist('1 2 --moo'.split(' ')) + .usage('Usage: $0 [x] [y] [z] {OPTIONS}') + .demand(3) + .argv; + }); + assert.deepEqual( + r.result, + { _ : [ '1', '2' ], moo : true, $0 : './usage' } + ); + + assert.deepEqual( + r.errors.join('\n').split(/\n+/), + [ + 'Usage: ./usage [x] [y] [z] {OPTIONS}', + 'Not enough non-option arguments: got 2, need at least 3', + ] + ); + + assert.deepEqual(r.logs, []); + assert.ok(r.exit); +}; + +exports.defaultSingles = function () { + var r = checkUsage(function () { + return optimist('--foo 50 --baz 70 --powsy'.split(' ')) + .default('foo', 5) + .default('bar', 6) + .default('baz', 7) + .argv + ; + }); + assert.eql(r.result, { + foo : '50', + bar : 6, + baz : '70', + powsy : true, + _ : [], + $0 : './usage', + }); +}; + +exports.defaultHash = function () { + var r = checkUsage(function () { + return optimist('--foo 50 --baz 70'.split(' ')) + .default({ foo : 10, bar : 20, quux : 30 }) + .argv + ; + }); + assert.eql(r.result, { + foo : '50', + bar : 20, + baz : 70, + quux : 30, + _ : [], + $0 : './usage', + }); +}; + +exports.rebase = function () { + assert.equal( + optimist.rebase('/home/substack', '/home/substack/foo/bar/baz'), + './foo/bar/baz' + ); + assert.equal( + optimist.rebase('/home/substack/foo/bar/baz', '/home/substack'), + '../../..' + ); + assert.equal( + optimist.rebase('/home/substack/foo', '/home/substack/pow/zoom.txt'), + '../pow/zoom.txt' + ); +}; + +function checkUsage (f) { + var _process = process; + process = Hash.copy(process); + var exit = false; + process.exit = function () { exit = true }; + process.env = Hash.merge(process.env, { _ : 'node' }); + process.argv = [ './usage' ]; + + var errors = []; + var logs = []; + + console._error = console.error; + console.error = function (msg) { errors.push(msg) }; + console._log = console.log; + console.log = function (msg) { logs.push(msg) }; + + var result = f(); + + process = _process; + console.error = console._error; + console.log = console._log; + + return { + errors : errors, + logs : logs, + exit : exit, + result : result, + }; +}; diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/.npmignore b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/.npmignore new file mode 100644 index 0000000..13abef4 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/.npmignore @@ -0,0 +1,3 @@ +node_modules +node_modules/* +npm_debug.log diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/index.js new file mode 100644 index 0000000..8fadda9 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/index.js @@ -0,0 +1,76 @@ +var Stream = require('stream') + +/* + was gonna use through for this, + but it does not match quite right, + because you need a seperate pause + mechanism for the readable and writable + sides. +*/ + +module.exports = function () { + var buffer = [], ended = false, destroyed = false + var stream = new Stream() + stream.writable = stream.readable = true + stream.paused = false + + stream.write = function (data) { + if(!this.paused) + this.emit('data', data) + else + buffer.push(data) + return !(this.paused || buffer.length) + } + function onEnd () { + stream.readable = false + stream.emit('end') + process.nextTick(stream.destroy.bind(stream)) + } + stream.end = function (data) { + if(data) this.write(data) + this.ended = true + this.writable = false + if(!(this.paused || buffer.length)) + return onEnd() + else + this.once('drain', onEnd) + this.drain() + } + + stream.drain = function () { + while(!this.paused && buffer.length) + this.emit('data', buffer.shift()) + //if the buffer has emptied. emit drain. + if(!buffer.length && !this.paused) + this.emit('drain') + } + + stream.resume = function () { + //this is where I need pauseRead, and pauseWrite. + //here the reading side is unpaused, + //but the writing side may still be paused. + //the whole buffer might not empity at once. + //it might pause again. + //the stream should never emit data inbetween pause()...resume() + //and write should return !buffer.length + + this.paused = false +// process.nextTick(this.drain.bind(this)) //will emit drain if buffer empties. + this.drain() + return this + } + + stream.destroy = function () { + if(destroyed) return + destroyed = ended = true + buffer.length = 0 + this.emit('close') + } + + stream.pause = function () { + stream.paused = true + return this + } + + return stream +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/package.json new file mode 100644 index 0000000..7702ad5 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/package.json @@ -0,0 +1,38 @@ +{ + "name": "pause-stream", + "version": "0.0.4", + "description": "a ThroughStream that strictly buffers all readable events when paused.", + "main": "index.js", + "directories": { + "test": "test" + }, + "devDependencies": { + "stream-spec": "~0.2.0" + }, + "scripts": { + "test": "node test/index.js && node test/pause-end.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/dominictarr/pause-stream.git" + }, + "keywords": [ + "stream", + "pipe", + "pause", + "drain", + "buffer" + ], + "author": { + "name": "Dominic Tarr", + "email": "dominic.tarr@gmail.com", + "url": "dominictarr.com" + }, + "license": [ + "MIT", + "Apache2" + ], + "readme": "# PauseStream\n\nThis is a `Stream` that will strictly buffer when paused.\nConnect it to anything you need buffered.\n\n``` js\n var ps = require('pause-stream')();\n\n badlyBehavedStream.pipe(ps.pause())\n\n aLittleLater(function (err, data) {\n ps.pipe(createAnotherStream(data))\n ps.resume()\n })\n```\n\n`PauseStream` will buffer whenever paused.\nit will buffer when yau have called `pause` manually.\nbut also when it's downstream `dest.write()===false`.\nit will attempt to drain the buffer when you call resume\nor the downstream emits `'drain'`\n\n`PauseStream` is tested using [stream-spec](https://github.com/dominictarr/stream-spec)\nand [stream-tester](https://github.com/dominictarr/stream-tester)\n", + "_id": "pause-stream@0.0.4", + "_from": "pause-stream@0.0.4" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/readme.markdown b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/readme.markdown new file mode 100644 index 0000000..715cb52 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/readme.markdown @@ -0,0 +1,24 @@ +# PauseStream + +This is a `Stream` that will strictly buffer when paused. +Connect it to anything you need buffered. + +``` js + var ps = require('pause-stream')(); + + badlyBehavedStream.pipe(ps.pause()) + + aLittleLater(function (err, data) { + ps.pipe(createAnotherStream(data)) + ps.resume() + }) +``` + +`PauseStream` will buffer whenever paused. +it will buffer when yau have called `pause` manually. +but also when it's downstream `dest.write()===false`. +it will attempt to drain the buffer when you call resume +or the downstream emits `'drain'` + +`PauseStream` is tested using [stream-spec](https://github.com/dominictarr/stream-spec) +and [stream-tester](https://github.com/dominictarr/stream-tester) diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/test/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/test/index.js new file mode 100644 index 0000000..4aa7d5e --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/test/index.js @@ -0,0 +1,17 @@ +var spec = require('stream-spec') +var tester = require('stream-tester') +var ps = require('..')() + +spec(ps) + .through({strict: false}) + .validateOnExit() + +var master = tester.createConsistent + +tester.createRandomStream(100) //1k random numbers + .pipe(master = tester.createConsistentStream()) + .pipe(tester.createUnpauseStream()) + .pipe(ps) + .pipe(tester.createPauseStream()) + .pipe(master.createSlave()) + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/test/pause-end.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/test/pause-end.js new file mode 100644 index 0000000..a6c27ef --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/pause-stream/test/pause-end.js @@ -0,0 +1,33 @@ + +var pause = require('..') +var assert = require('assert') + +var ps = pause() +var read = [], ended = false + +ps.on('data', function (i) { + read.push(i) +}) + +ps.on('end', function () { + ended = true +}) + +assert.deepEqual(read, []) + +ps.write(0) +ps.write(1) +ps.write(2) + +assert.deepEqual(read, [0, 1, 2]) + +ps.pause() + +assert.deepEqual(read, [0, 1, 2]) + +ps.end() +assert.equal(ended, false) +ps.resume() +assert.equal(ended, true) + + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/.npmignore b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/.npmignore new file mode 100644 index 0000000..13abef4 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/.npmignore @@ -0,0 +1,3 @@ +node_modules +node_modules/* +npm_debug.log diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/.travis.yml b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/.travis.yml new file mode 100644 index 0000000..895dbd3 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.6 + - 0.8 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/LICENCE b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/LICENCE new file mode 100644 index 0000000..171dd97 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/LICENCE @@ -0,0 +1,22 @@ +Copyright (c) 2011 Dominic Tarr + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/examples/pretty.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/examples/pretty.js new file mode 100644 index 0000000..af04340 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/examples/pretty.js @@ -0,0 +1,25 @@ + +var inspect = require('util').inspect + +if(!module.parent) { + var es = require('..') //load event-stream + es.pipe( //pipe joins streams together + process.openStdin(), //open stdin + es.split(), //split stream to break on newlines + es.map(function (data, callback) {//turn this async function into a stream + var j + try { + j = JSON.parse(data) //try to parse input into json + } catch (err) { + return callback(null, data) //if it fails just pass it anyway + } + callback(null, inspect(j)) //render it nicely + }), + process.stdout // pipe it to stdout ! + ) + } + +// run this +// +// curl -sS registry.npmjs.org/event-stream | node pretty.js +// diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/index.js new file mode 100644 index 0000000..1146c96 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/index.js @@ -0,0 +1,35 @@ +//filter will reemit the data if cb(err,pass) pass is truthy + +// reduce is more tricky +// maybe we want to group the reductions or emit progress updates occasionally +// the most basic reduce just emits one 'data' event after it has recieved 'end' + + +var through = require('through') + + +module.exports = split + +function split (matcher) { + var soFar = '' + if (!matcher) + matcher = '\n' + + return through(function (buffer) { + var stream = this + , pieces = (soFar + buffer).split(matcher) + soFar = pieces.pop() + + pieces.forEach(function (piece) { + stream.emit('data', piece) + }) + + return true + }, + function () { + if(soFar) + this.emit('data', soFar) + this.emit('end') + }) +} + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/.travis.yml b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/.travis.yml new file mode 100644 index 0000000..895dbd3 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.6 + - 0.8 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/LICENSE.APACHE2 b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/LICENSE.APACHE2 new file mode 100644 index 0000000..6366c04 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/LICENSE.APACHE2 @@ -0,0 +1,15 @@ +Apache License, Version 2.0 + +Copyright (c) 2011 Dominic Tarr + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/LICENSE.MIT b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/LICENSE.MIT new file mode 100644 index 0000000..6eafbd7 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/LICENSE.MIT @@ -0,0 +1,24 @@ +The MIT License + +Copyright (c) 2011 Dominic Tarr + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/index.js new file mode 100644 index 0000000..cd25055 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/index.js @@ -0,0 +1,65 @@ +var Stream = require('stream') + +// through +// +// a stream that does nothing but re-emit the input. +// useful for aggregating a series of changing but not ending streams into one stream) + +exports = module.exports = through +through.through = through + +//create a readable writable stream. + +function through (write, end) { + write = write || function (data) { this.emit('data', data) } + end = end || function () { this.emit('end') } + + var ended = false, destroyed = false + var stream = new Stream() + stream.readable = stream.writable = true + stream.paused = false + stream.write = function (data) { + write.call(this, data) + return !stream.paused + } + //this will be registered as the first 'end' listener + //must call destroy next tick, to make sure we're after any + //stream piped from here. + stream.on('end', function () { + stream.readable = false + if(!stream.writable) + process.nextTick(function () { + stream.destroy() + }) + }) + + stream.end = function (data) { + if(ended) return + //this breaks, because pipe doesn't check writable before calling end. + //throw new Error('cannot call end twice') + ended = true + if(arguments.length) stream.write(data) + this.writable = false + end.call(this) + if(!this.readable) + this.destroy() + } + stream.destroy = function () { + if(destroyed) return + destroyed = true + ended = true + stream.writable = stream.readable = false + stream.emit('close') + } + stream.pause = function () { + stream.paused = true + } + stream.resume = function () { + if(stream.paused) { + stream.paused = false + stream.emit('drain') + } + } + return stream +} + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/package.json new file mode 100644 index 0000000..3ecb71d --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/package.json @@ -0,0 +1,29 @@ +{ + "name": "through", + "version": "0.0.4", + "description": "simplified stream contruction", + "main": "index.js", + "scripts": { + "test": "asynct test/*.js" + }, + "devDependencies": { + "stream-spec": "0", + "assertions": "2", + "asynct": "1" + }, + "keywords": [ + "stream", + "streams", + "user-streams", + "pipe" + ], + "author": { + "name": "Dominic Tarr", + "email": "dominic.tarr@gmail.com", + "url": "dominictarr.com" + }, + "license": "MIT", + "readme": "#through\n\n[![build status](https://secure.travis-ci.org/dominictarr/through.png)](http://travis-ci.org/dominictarr/through)\n\nEasy way to create a `Stream` that is both `readable` and `writable`. Pass in optional `write` and `end` methods. `through` takes care of pause/resume logic.\nUse `this.pause()` and `this.resume()` to manage flow.\nCheck `this.paused` to see current flow state. (write always returns `!this.paused`)\n\nthis function is the basis for most of the syncronous streams in [event-stream](http://github.com/dominictarr/event-stream).\n\n``` js\nvar through = require('through')\n\nthrough(function write(data) {\n this.emit('data', data)\n //this.pause() \n },\n function end () { //optional\n this.emit('end')\n })\n\n```\n\n## License\n\nMIT / Apache2\n", + "_id": "through@0.0.4", + "_from": "through@0.0.4" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/readme.markdown b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/readme.markdown new file mode 100644 index 0000000..ce9b9e5 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/readme.markdown @@ -0,0 +1,26 @@ +#through + +[![build status](https://secure.travis-ci.org/dominictarr/through.png)](http://travis-ci.org/dominictarr/through) + +Easy way to create a `Stream` that is both `readable` and `writable`. Pass in optional `write` and `end` methods. `through` takes care of pause/resume logic. +Use `this.pause()` and `this.resume()` to manage flow. +Check `this.paused` to see current flow state. (write always returns `!this.paused`) + +this function is the basis for most of the syncronous streams in [event-stream](http://github.com/dominictarr/event-stream). + +``` js +var through = require('through') + +through(function write(data) { + this.emit('data', data) + //this.pause() + }, + function end () { //optional + this.emit('end') + }) + +``` + +## License + +MIT / Apache2 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/test/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/test/index.js new file mode 100644 index 0000000..25a6ea7 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/node_modules/through/test/index.js @@ -0,0 +1,113 @@ + +var spec = require('stream-spec') +var through = require('..') +var a = require('assertions') + +/* + I'm using these two functions, and not streams and pipe + so there is less to break. if this test fails it must be + the implementation of _through_ +*/ + +function write(array, stream) { + array = array.slice() + function next() { + while(array.length) + if(stream.write(array.shift()) === false) + return stream.once('drain', next) + + stream.end() + } + + next() +} + +function read(stream, callback) { + var actual = [] + stream.on('data', function (data) { + actual.push(data) + }) + stream.once('end', function () { + callback(null, actual) + }) + stream.once('error', function (err) { + callback(err) + }) +} + +exports['simple defaults'] = function (test) { + + var l = 1000 + , expected = [] + + while(l--) expected.push(l * Math.random()) + + var t = through() + spec(t) + .through() + .pausable() + .validateOnExit() + + read(t, function (err, actual) { + if(err) test.error(err) //fail + a.deepEqual(actual, expected) + test.done() + }) + + write(expected, t) +} + +exports['simple functions'] = function (test) { + + var l = 1000 + , expected = [] + + while(l--) expected.push(l * Math.random()) + + var t = through(function (data) { + this.emit('data', data*2) + }) + spec(t) + .through() + .pausable() + .validateOnExit() + + read(t, function (err, actual) { + if(err) test.error(err) //fail + a.deepEqual(actual, expected.map(function (data) { + return data*2 + })) + test.done() + }) + + write(expected, t) +} +exports['pauses'] = function (test) { + + var l = 1000 + , expected = [] + + while(l--) expected.push(l) //Math.random()) + + var t = through() + spec(t) + .through() + .pausable() + .validateOnExit() + + t.on('data', function () { + if(Math.random() > 0.1) return + t.pause() + process.nextTick(function () { + t.resume() + }) + }) + + read(t, function (err, actual) { + if(err) test.error(err) //fail + a.deepEqual(actual, expected) + test.done() + }) + + write(expected, t) +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/package.json new file mode 100644 index 0000000..a592dad --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/package.json @@ -0,0 +1,35 @@ +{ + "name": "split", + "version": "0.0.0", + "description": "split a Text Stream into a Line Stream", + "homepage": "http://github.com/dominictarr/split", + "repository": { + "type": "git", + "url": "git://github.com/dominictarr/split.git" + }, + "dependencies": { + "through": "0.0.4" + }, + "devDependencies": { + "asynct": "*", + "it-is": "1", + "ubelt": "~2.9", + "stream-spec": "~0.2", + "event-stream": "~3.0.2" + }, + "scripts": { + "test": "asynct test/" + }, + "author": { + "name": "Dominic Tarr", + "email": "dominic.tarr@gmail.com", + "url": "http://bit.ly/dominictarr" + }, + "optionalDependencies": {}, + "engines": { + "node": "*" + }, + "readme": "# Split (matcher)\n\n\n\nBreak up a stream and reassemble it so that each line is a chunk. matcher may be a `String`, or a `RegExp` \n\nExample, read every line in a file ...\n\n``` js\n fs.createReadStream(file)\n .pipe(split())\n .on('data', function (line) {\n //each chunk now is a seperate line!\n })\n\n```\n\n`split` takes the same arguments as `string.split` except it defaults to '\\n' instead of ',', and the optional `limit` paremeter is ignored.\n[String#split](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/split)\n\n", + "_id": "split@0.0.0", + "_from": "split@0.0.0" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/readme.markdown b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/readme.markdown new file mode 100644 index 0000000..57c8edc --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/readme.markdown @@ -0,0 +1,20 @@ +# Split (matcher) + + + +Break up a stream and reassemble it so that each line is a chunk. matcher may be a `String`, or a `RegExp` + +Example, read every line in a file ... + +``` js + fs.createReadStream(file) + .pipe(split()) + .on('data', function (line) { + //each chunk now is a seperate line! + }) + +``` + +`split` takes the same arguments as `string.split` except it defaults to '\n' instead of ',', and the optional `limit` paremeter is ignored. +[String#split](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/split) + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/test/split.asynct.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/test/split.asynct.js new file mode 100644 index 0000000..a6a3b1b --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/split/test/split.asynct.js @@ -0,0 +1,47 @@ +var es = require('event-stream') + , it = require('it-is').style('colour') + , d = require('ubelt') + , split = require('..') + , join = require('path').join + , fs = require('fs') + , Stream = require('stream').Stream + , spec = require('stream-spec') + +exports ['es.split() works like String#split'] = function (test) { + var readme = join(__filename) + , expected = fs.readFileSync(readme, 'utf-8').split('\n') + , cs = split() + , actual = [] + , ended = false + , x = spec(cs).through() + + var a = new Stream () + + a.write = function (l) { + actual.push(l.trim()) + } + a.end = function () { + + ended = true + expected.forEach(function (v,k) { + //String.split will append an empty string '' + //if the string ends in a split pattern. + //es.split doesn't which was breaking this test. + //clearly, appending the empty string is correct. + //tests are passing though. which is the current job. + if(v) + it(actual[k]).like(v) + }) + //give the stream time to close + process.nextTick(function () { + test.done() + x.validate() + }) + } + a.writable = true + + fs.createReadStream(readme, {flags: 'r'}).pipe(cs) + cs.pipe(a) + +} + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/.travis.yml b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/.travis.yml new file mode 100644 index 0000000..895dbd3 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.6 + - 0.8 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/LICENSE.APACHE2 b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/LICENSE.APACHE2 new file mode 100644 index 0000000..6366c04 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/LICENSE.APACHE2 @@ -0,0 +1,15 @@ +Apache License, Version 2.0 + +Copyright (c) 2011 Dominic Tarr + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/LICENSE.MIT b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/LICENSE.MIT new file mode 100644 index 0000000..6eafbd7 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/LICENSE.MIT @@ -0,0 +1,24 @@ +The MIT License + +Copyright (c) 2011 Dominic Tarr + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/index.js new file mode 100644 index 0000000..7072b37 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/index.js @@ -0,0 +1,100 @@ +var Stream = require('stream') + +// through +// +// a stream that does nothing but re-emit the input. +// useful for aggregating a series of changing but not ending streams into one stream) + + + +exports = module.exports = through +through.through = through + +//create a readable writable stream. + +function through (write, end) { + write = write || function (data) { this.emit('data', data) } + end = end || function () { this.emit('end') } + + var ended = false, destroyed = false + var stream = new Stream(), buffer = [] + stream.buffer = buffer + stream.readable = stream.writable = true + stream.paused = false + stream.write = function (data) { + write.call(this, data) + return !stream.paused + } + + function drain() { + while(buffer.length && !stream.paused) { + var data = buffer.shift() + if(null === data) + return stream.emit('end') + else + stream.emit('data', data) + } + } + + stream.queue = function (data) { + buffer.push(data) + drain() + } + + //this will be registered as the first 'end' listener + //must call destroy next tick, to make sure we're after any + //stream piped from here. + //this is only a problem if end is not emitted synchronously. + //a nicer way to do this is to make sure this is the last listener for 'end' + + stream.on('end', function () { + stream.readable = false + if(!stream.writable) + process.nextTick(function () { + stream.destroy() + }) + }) + + function _end () { + stream.writable = false + end.call(stream) + if(!stream.readable) + stream.destroy() + } + + stream.end = function (data) { + if(ended) return + //this breaks, because pipe doesn't check writable before calling end. + //throw new Error('cannot call end twice') + ended = true + if(arguments.length) stream.write(data) + if(!buffer.length) _end() + } + + stream.destroy = function () { + if(destroyed) return + destroyed = true + ended = true + buffer.length = 0 + stream.writable = stream.readable = false + stream.emit('close') + } + + stream.pause = function () { + if(stream.paused) return + stream.paused = true + stream.emit('pause') + } + stream.resume = function () { + if(stream.paused) { + stream.paused = false + } + drain() + //may have become paused again, + //as drain emits 'data'. + if(!stream.paused) + stream.emit('drain') + } + return stream +} + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/package.json new file mode 100644 index 0000000..168247e --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/package.json @@ -0,0 +1,34 @@ +{ + "name": "through", + "version": "1.1.0", + "description": "simplified stream contruction", + "main": "index.js", + "scripts": { + "test": "asynct test/*.js" + }, + "devDependencies": { + "stream-spec": "0", + "assertions": "2", + "asynct": "1" + }, + "keywords": [ + "stream", + "streams", + "user-streams", + "pipe" + ], + "author": { + "name": "Dominic Tarr", + "email": "dominic.tarr@gmail.com", + "url": "dominictarr.com" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/dominictarr/through.git" + }, + "homepage": "http://github.com/dominictarr/through", + "readme": "#through\n\n[![build status](https://secure.travis-ci.org/dominictarr/through.png)](http://travis-ci.org/dominictarr/through)\n\nEasy way to create a `Stream` that is both `readable` and `writable`. Pass in optional `write` and `end` methods. `through` takes care of pause/resume logic.\nUse `this.pause()` and `this.resume()` to manage flow.\nCheck `this.paused` to see current flow state. (write always returns `!this.paused`)\n\nthis function is the basis for most of the syncronous streams in [event-stream](http://github.com/dominictarr/event-stream).\n\n``` js\nvar through = require('through')\n\nthrough(function write(data) {\n this.emit('data', data)\n //this.pause() \n },\n function end () { //optional\n this.emit('end')\n })\n\n```\n\nor, with buffering on pause, use `this.queue(data)`,\ndata *cannot* be `null`. `this.queue(null)` will emit 'end'\nwhen it gets to the `null` element.\n\n``` js\nvar through = require('through')\n\nthrough(function write(data) {\n this.queue(data)\n //this.pause() \n },\n function end () { //optional\n this.queue(null)\n })\n\n```\n\n\n## License\n\nMIT / Apache2\n", + "_id": "through@1.1.0", + "_from": "through@~1.1.0" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/readme.markdown b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/readme.markdown new file mode 100644 index 0000000..1b687e9 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/readme.markdown @@ -0,0 +1,44 @@ +#through + +[![build status](https://secure.travis-ci.org/dominictarr/through.png)](http://travis-ci.org/dominictarr/through) + +Easy way to create a `Stream` that is both `readable` and `writable`. Pass in optional `write` and `end` methods. `through` takes care of pause/resume logic. +Use `this.pause()` and `this.resume()` to manage flow. +Check `this.paused` to see current flow state. (write always returns `!this.paused`) + +this function is the basis for most of the syncronous streams in [event-stream](http://github.com/dominictarr/event-stream). + +``` js +var through = require('through') + +through(function write(data) { + this.emit('data', data) + //this.pause() + }, + function end () { //optional + this.emit('end') + }) + +``` + +or, with buffering on pause, use `this.queue(data)`, +data *cannot* be `null`. `this.queue(null)` will emit 'end' +when it gets to the `null` element. + +``` js +var through = require('through') + +through(function write(data) { + this.queue(data) + //this.pause() + }, + function end () { //optional + this.queue(null) + }) + +``` + + +## License + +MIT / Apache2 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/test/buffering.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/test/buffering.js new file mode 100644 index 0000000..1ce4b0d --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/test/buffering.js @@ -0,0 +1,37 @@ +var through = require('..') + +// must emit end before close. + +exports['buffering'] = function (t) { + var ts = through(function (data) { + this.queue(data) + }, function () { + this.queue(null) + }) + + var ended = false, actual = [] + + ts.on('data', actual.push.bind(actual)) + ts.on('end', function () { + ended = true + }) + + ts.write(1) + ts.write(2) + ts.write(3) + t.deepEqual(actual, [1, 2, 3]) + ts.pause() + ts.write(4) + ts.write(5) + ts.write(6) + t.deepEqual(actual, [1, 2, 3]) + ts.resume() + t.deepEqual(actual, [1, 2, 3, 4, 5, 6]) + ts.pause() + ts.end() + t.ok(!ended) + ts.resume() + t.ok(ended) + t.end() + +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/test/end.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/test/end.js new file mode 100644 index 0000000..280da0a --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/test/end.js @@ -0,0 +1,27 @@ +var through = require('..') + +// must emit end before close. + +exports['end before close'] = function (t) { + var ts = through() + var ended = false, closed = false + + ts.on('end', function () { + t.ok(!closed) + ended = true + }) + ts.on('close', function () { + t.ok(ended) + closed = true + }) + + ts.write(1) + ts.write(2) + ts.write(3) + ts.end() + t.ok(ended) + t.ok(closed) + + t.end() + +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/test/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/test/index.js new file mode 100644 index 0000000..25a6ea7 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/node_modules/through/test/index.js @@ -0,0 +1,113 @@ + +var spec = require('stream-spec') +var through = require('..') +var a = require('assertions') + +/* + I'm using these two functions, and not streams and pipe + so there is less to break. if this test fails it must be + the implementation of _through_ +*/ + +function write(array, stream) { + array = array.slice() + function next() { + while(array.length) + if(stream.write(array.shift()) === false) + return stream.once('drain', next) + + stream.end() + } + + next() +} + +function read(stream, callback) { + var actual = [] + stream.on('data', function (data) { + actual.push(data) + }) + stream.once('end', function () { + callback(null, actual) + }) + stream.once('error', function (err) { + callback(err) + }) +} + +exports['simple defaults'] = function (test) { + + var l = 1000 + , expected = [] + + while(l--) expected.push(l * Math.random()) + + var t = through() + spec(t) + .through() + .pausable() + .validateOnExit() + + read(t, function (err, actual) { + if(err) test.error(err) //fail + a.deepEqual(actual, expected) + test.done() + }) + + write(expected, t) +} + +exports['simple functions'] = function (test) { + + var l = 1000 + , expected = [] + + while(l--) expected.push(l * Math.random()) + + var t = through(function (data) { + this.emit('data', data*2) + }) + spec(t) + .through() + .pausable() + .validateOnExit() + + read(t, function (err, actual) { + if(err) test.error(err) //fail + a.deepEqual(actual, expected.map(function (data) { + return data*2 + })) + test.done() + }) + + write(expected, t) +} +exports['pauses'] = function (test) { + + var l = 1000 + , expected = [] + + while(l--) expected.push(l) //Math.random()) + + var t = through() + spec(t) + .through() + .pausable() + .validateOnExit() + + t.on('data', function () { + if(Math.random() > 0.1) return + t.pause() + process.nextTick(function () { + t.resume() + }) + }) + + read(t, function (err, actual) { + if(err) test.error(err) //fail + a.deepEqual(actual, expected) + test.done() + }) + + write(expected, t) +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/package.json new file mode 100644 index 0000000..15f8ea8 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/package.json @@ -0,0 +1,40 @@ +{ + "name": "event-stream", + "version": "3.0.7", + "description": "construct pipes of streams of events", + "homepage": "http://github.com/dominictarr/event-stream", + "repository": { + "type": "git", + "url": "git://github.com/dominictarr/event-stream.git" + }, + "dependencies": { + "optimist": "0.2", + "through": "1.1.0", + "duplexer": "~0.0.2", + "from": "~0", + "map-stream": "0.0.1", + "pause-stream": "0.0.4", + "split": "0.0.0" + }, + "devDependencies": { + "asynct": "*", + "it-is": "1", + "ubelt": "~2.9", + "stream-spec": "~0.2" + }, + "scripts": { + "test": "asynct test/" + }, + "author": { + "name": "Dominic Tarr", + "email": "dominic.tarr@gmail.com", + "url": "http://bit.ly/dominictarr" + }, + "optionalDependencies": {}, + "engines": { + "node": "*" + }, + "readme": "# EventStream\n\n\n\n[Streams](http://nodejs.org/api/streams.html \"Stream\") are nodes best and most misunderstood idea, and \n_EventStream_ is a toolkit to make creating and working with streams easy. \n\nNormally, streams are only used of IO, \nbut in event stream we send all kinds of objects down the pipe. \nIf your application's input and output are streams, \nshouldn't the throughput be a stream too? \n\nThe *EventStream* functions resemble the array functions, \nbecause Streams are like Arrays, but laid out in time, rather than in memory. \n\nAll the `event-stream` functions return instances of `Stream`.\n\nStream API docs: [nodejs.org/api/streams](http://nodejs.org/api/streams.html \"Stream\")\n\nNOTE: I shall use the term \"through stream\" to refer to a stream that is writable and readable. \n\n###[simple example](https://github.com/dominictarr/event-stream/blob/master/examples/pretty.js):\n\n``` js\n\n//pretty.js\n\nif(!module.parent) {\n var es = require('event-stream')\n es.pipeline( //connect streams together with `pipe`\n process.openStdin(), //open stdin\n es.split(), //split stream to break on newlines\n es.map(function (data, callback) {//turn this async function into a stream\n callback(null\n , inspect(JSON.parse(data))) //render it nicely\n }),\n process.stdout // pipe it to stdout !\n )\n }\n```\nrun it ...\n\n``` bash \ncurl -sS registry.npmjs.org/event-stream | node pretty.js\n```\n \n[node Stream documentation](http://nodejs.org/api/streams.html)\n\n## through (write?, end?)\n\nReemits data synchronously. Easy way to create syncronous through streams.\nPass in an optional `write` and `end` methods. They will be called in the \ncontext of the stream. Use `this.pause()` and `this.resume()` to manage flow.\nCheck `this.paused` to see current flow state. (write always returns `!this.paused`)\n\nthis function is the basis for most of the syncronous streams in `event-stream`.\n\n``` js\n\nes.through(function write(data) {\n this.emit('data', data)\n //this.pause() \n },\n function end () { //optional\n this.emit('end')\n })\n\n```\n\n##map (asyncFunction)\n\nCreate a through stream from an asyncronous function. \n\n``` js\nvar es = require('event-stream')\n\nes.map(function (data, callback) {\n //transform data\n // ...\n callback(null, data)\n})\n\n```\n\nEach map MUST call the callback. It may callback with data, with an error or with no arguments, \n\n * `callback()` drop this data. \n this makes the map work like `filter`, \n note:`callback(null,null)` is not the same, and will emit `null`\n\n * `callback(null, newData)` turn data into newData\n \n * `callback(error)` emit an error for this item.\n\n>Note: if a callback is not called, `map` will think that it is still being processed, \n>every call must be answered or the stream will not know when to end. \n>\n>Also, if the callback is called more than once, every call but the first will be ignored.\n\n## mapSync (syncFunction)\n\nSame as `map`, but the callback is called synchronously. Based on `es.through`\n\n## split (matcher)\n\nBreak up a stream and reassemble it so that each line is a chunk. matcher may be a `String`, or a `RegExp` \n\nExample, read every line in a file ...\n\n``` js\n es.pipeline(\n fs.createReadStream(file, {flags: 'r'}),\n es.split(),\n es.map(function (line, cb) {\n //do something with the line \n cb(null, line)\n })\n )\n\n```\n\n`split` takes the same arguments as `string.split` except it defaults to '\\n' instead of ',', and the optional `limit` paremeter is ignored.\n[String#split](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/split)\n\n## join (seperator)\n\ncreate a through stream that emits `seperator` between each chunk, just like Array#join.\n\n(for legacy reasons, if you pass a callback instead of a string, join is a synonym for `es.wait`)\n\n## replace (from, to)\n\nReplace all occurences of `from` with `to`. `from` may be a `String` or a `RegExp`. \nWorks just like `string.split(from).join(to)`, but streaming.\n\n\n## parse\n\nConvienience function for parsing JSON chunks. For newline seperated JSON,\nuse with `es.split`\n\n``` js\nfs.createReadStream(filename)\n .pipe(es.split()) //defaults to lines.\n .pipe(es.parse())\n```\n\n## stringify\n\nconvert javascript objects into lines of text. The text will have whitespace escaped and have a `\\n` appended, so it will be compatible with `es.parse`\n\n``` js\nobjectStream\n .pipe(es.stringify())\n .pipe(fs.createWriteStream(filename))\n```\n\n##readable (asyncFunction) \n\ncreate a readable stream (that respects pause) from an async function. \nwhile the stream is not paused, \nthe function will be polled with `(count, callback)`, \nand `this` will be the readable stream.\n\n``` js\n\nes.readable(function (count, callback) {\n if(streamHasEnded)\n return this.emit('end')\n \n //...\n \n this.emit('data', data) //use this way to emit multiple chunks per call.\n \n callback() // you MUST always call the callback eventually.\n // the function will not be called again until you do this.\n})\n```\nyou can also pass the data and the error to the callback. \nyou may only call the callback once. \ncalling the same callback more than once will have no effect. \n\n##readArray (array)\n\nCreate a readable stream from an Array.\n\nJust emit each item as a data event, respecting `pause` and `resume`.\n\n``` js\n var es = require('event-stream')\n , reader = es.readArray([1,2,3])\n\n reader.pipe(...)\n```\n\n## writeArray (callback)\n\ncreate a writeable stream from a callback, \nall `data` events are stored in an array, which is passed to the callback when the stream ends.\n\n``` js\n var es = require('event-stream')\n , reader = es.readArray([1, 2, 3])\n , writer = es.writeArray(function (err, array){\n //array deepEqual [1, 2, 3]\n })\n\n reader.pipe(writer)\n```\n\n## pipeline (stream1,...,streamN)\n\nTurn a pipeline into a single stream. `pipeline` returns a stream that writes to the first stream\nand reads from the last stream. \n\nListening for 'error' will recieve errors from all streams inside the pipe.\n\n> `connect` is an alias for `pipeline`.\n\n``` js\n\n es.pipeline( //connect streams together with `pipe`\n process.openStdin(), //open stdin\n es.split(), //split stream to break on newlines\n es.map(function (data, callback) {//turn this async function into a stream\n callback(null\n , inspect(JSON.parse(data))) //render it nicely\n }),\n process.stdout // pipe it to stdout !\n )\n```\n\n## pause () \n\nA stream that buffers all chunks when paused.\n\n\n``` js\n var ps = es.pause()\n ps.pause() //buffer the stream, also do not allow 'end' \n ps.resume() //allow chunks through\n```\n\n## duplex (writeStream, readStream)\n\nTakes a writable stream and a readable stream and makes them appear as a readable writable stream.\n\nIt is assumed that the two streams are connected to each other in some way. \n\n(This is used by `pipeline` and `child`.)\n\n``` js\n var grep = cp.exec('grep Stream')\n\n es.duplex(grep.stdin, grep.stdout)\n```\n\n## child (child_process)\n\nCreate a through stream from a child process ...\n\n``` js\n var cp = require('child_process')\n\n es.child(cp.exec('grep Stream')) // a through stream\n\n```\n\n## wait (callback)\n\nwaits for stream to emit 'end'.\njoins chunks of a stream into a single string. \ntakes an optional callback, which will be passed the \ncomplete string when it receives the 'end' event.\n\nalso, emits a simgle 'data' event.\n\n``` js\n\nreadStream.pipe(es.join(function (err, text) {\n // have complete text here.\n}))\n\n```\n\n\n", + "_id": "event-stream@3.0.7", + "_from": "event-stream@~3.0.7" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/readme.markdown b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/readme.markdown new file mode 100644 index 0000000..e83724a --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/readme.markdown @@ -0,0 +1,286 @@ +# EventStream + + + +[Streams](http://nodejs.org/api/streams.html "Stream") are nodes best and most misunderstood idea, and +_EventStream_ is a toolkit to make creating and working with streams easy. + +Normally, streams are only used of IO, +but in event stream we send all kinds of objects down the pipe. +If your application's input and output are streams, +shouldn't the throughput be a stream too? + +The *EventStream* functions resemble the array functions, +because Streams are like Arrays, but laid out in time, rather than in memory. + +All the `event-stream` functions return instances of `Stream`. + +Stream API docs: [nodejs.org/api/streams](http://nodejs.org/api/streams.html "Stream") + +NOTE: I shall use the term "through stream" to refer to a stream that is writable and readable. + +###[simple example](https://github.com/dominictarr/event-stream/blob/master/examples/pretty.js): + +``` js + +//pretty.js + +if(!module.parent) { + var es = require('event-stream') + es.pipeline( //connect streams together with `pipe` + process.openStdin(), //open stdin + es.split(), //split stream to break on newlines + es.map(function (data, callback) {//turn this async function into a stream + callback(null + , inspect(JSON.parse(data))) //render it nicely + }), + process.stdout // pipe it to stdout ! + ) + } +``` +run it ... + +``` bash +curl -sS registry.npmjs.org/event-stream | node pretty.js +``` + +[node Stream documentation](http://nodejs.org/api/streams.html) + +## through (write?, end?) + +Reemits data synchronously. Easy way to create syncronous through streams. +Pass in an optional `write` and `end` methods. They will be called in the +context of the stream. Use `this.pause()` and `this.resume()` to manage flow. +Check `this.paused` to see current flow state. (write always returns `!this.paused`) + +this function is the basis for most of the syncronous streams in `event-stream`. + +``` js + +es.through(function write(data) { + this.emit('data', data) + //this.pause() + }, + function end () { //optional + this.emit('end') + }) + +``` + +##map (asyncFunction) + +Create a through stream from an asyncronous function. + +``` js +var es = require('event-stream') + +es.map(function (data, callback) { + //transform data + // ... + callback(null, data) +}) + +``` + +Each map MUST call the callback. It may callback with data, with an error or with no arguments, + + * `callback()` drop this data. + this makes the map work like `filter`, + note:`callback(null,null)` is not the same, and will emit `null` + + * `callback(null, newData)` turn data into newData + + * `callback(error)` emit an error for this item. + +>Note: if a callback is not called, `map` will think that it is still being processed, +>every call must be answered or the stream will not know when to end. +> +>Also, if the callback is called more than once, every call but the first will be ignored. + +## mapSync (syncFunction) + +Same as `map`, but the callback is called synchronously. Based on `es.through` + +## split (matcher) + +Break up a stream and reassemble it so that each line is a chunk. matcher may be a `String`, or a `RegExp` + +Example, read every line in a file ... + +``` js + es.pipeline( + fs.createReadStream(file, {flags: 'r'}), + es.split(), + es.map(function (line, cb) { + //do something with the line + cb(null, line) + }) + ) + +``` + +`split` takes the same arguments as `string.split` except it defaults to '\n' instead of ',', and the optional `limit` paremeter is ignored. +[String#split](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/split) + +## join (seperator) + +create a through stream that emits `seperator` between each chunk, just like Array#join. + +(for legacy reasons, if you pass a callback instead of a string, join is a synonym for `es.wait`) + +## replace (from, to) + +Replace all occurences of `from` with `to`. `from` may be a `String` or a `RegExp`. +Works just like `string.split(from).join(to)`, but streaming. + + +## parse + +Convienience function for parsing JSON chunks. For newline seperated JSON, +use with `es.split` + +``` js +fs.createReadStream(filename) + .pipe(es.split()) //defaults to lines. + .pipe(es.parse()) +``` + +## stringify + +convert javascript objects into lines of text. The text will have whitespace escaped and have a `\n` appended, so it will be compatible with `es.parse` + +``` js +objectStream + .pipe(es.stringify()) + .pipe(fs.createWriteStream(filename)) +``` + +##readable (asyncFunction) + +create a readable stream (that respects pause) from an async function. +while the stream is not paused, +the function will be polled with `(count, callback)`, +and `this` will be the readable stream. + +``` js + +es.readable(function (count, callback) { + if(streamHasEnded) + return this.emit('end') + + //... + + this.emit('data', data) //use this way to emit multiple chunks per call. + + callback() // you MUST always call the callback eventually. + // the function will not be called again until you do this. +}) +``` +you can also pass the data and the error to the callback. +you may only call the callback once. +calling the same callback more than once will have no effect. + +##readArray (array) + +Create a readable stream from an Array. + +Just emit each item as a data event, respecting `pause` and `resume`. + +``` js + var es = require('event-stream') + , reader = es.readArray([1,2,3]) + + reader.pipe(...) +``` + +## writeArray (callback) + +create a writeable stream from a callback, +all `data` events are stored in an array, which is passed to the callback when the stream ends. + +``` js + var es = require('event-stream') + , reader = es.readArray([1, 2, 3]) + , writer = es.writeArray(function (err, array){ + //array deepEqual [1, 2, 3] + }) + + reader.pipe(writer) +``` + +## pipeline (stream1,...,streamN) + +Turn a pipeline into a single stream. `pipeline` returns a stream that writes to the first stream +and reads from the last stream. + +Listening for 'error' will recieve errors from all streams inside the pipe. + +> `connect` is an alias for `pipeline`. + +``` js + + es.pipeline( //connect streams together with `pipe` + process.openStdin(), //open stdin + es.split(), //split stream to break on newlines + es.map(function (data, callback) {//turn this async function into a stream + callback(null + , inspect(JSON.parse(data))) //render it nicely + }), + process.stdout // pipe it to stdout ! + ) +``` + +## pause () + +A stream that buffers all chunks when paused. + + +``` js + var ps = es.pause() + ps.pause() //buffer the stream, also do not allow 'end' + ps.resume() //allow chunks through +``` + +## duplex (writeStream, readStream) + +Takes a writable stream and a readable stream and makes them appear as a readable writable stream. + +It is assumed that the two streams are connected to each other in some way. + +(This is used by `pipeline` and `child`.) + +``` js + var grep = cp.exec('grep Stream') + + es.duplex(grep.stdin, grep.stdout) +``` + +## child (child_process) + +Create a through stream from a child process ... + +``` js + var cp = require('child_process') + + es.child(cp.exec('grep Stream')) // a through stream + +``` + +## wait (callback) + +waits for stream to emit 'end'. +joins chunks of a stream into a single string. +takes an optional callback, which will be passed the +complete string when it receives the 'end' event. + +also, emits a simgle 'data' event. + +``` js + +readStream.pipe(es.join(function (err, text) { + // have complete text here. +})) + +``` + + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/connect.asynct.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/connect.asynct.js new file mode 100644 index 0000000..0ba0020 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/connect.asynct.js @@ -0,0 +1,82 @@ +var es = require('../') + , it = require('it-is').style('colour') + , d = require('ubelt') + +function makeExamplePipe() { + + return es.connect( + es.map(function (data, callback) { + callback(null, data * 2) + }), + es.map(function (data, callback) { + d.delay(callback)(null, data) + }), + es.map(function (data, callback) { + callback(null, data + 2) + })) +} + +exports['simple pipe'] = function (test) { + + var pipe = makeExamplePipe() + + pipe.on('data', function (data) { + it(data).equal(18) + test.done() + }) + + pipe.write(8) + +} + +exports['read array then map'] = function (test) { + + var readThis = d.map(3, 6, 100, d.id) //array of multiples of 3 < 100 + , first = es.readArray(readThis) + , read = [] + , pipe = + es.connect( + first, + es.map(function (data, callback) { + callback(null, {data: data}) + }), + es.map(function (data, callback) { + callback(null, {data: data}) + }), + es.writeArray(function (err, array) { + it(array).deepEqual(d.map(readThis, function (data) { + return {data: {data: data}} + })) + test.done() + }) + ) +} + +exports ['connect returns a stream'] = function (test) { + + var rw = + es.connect( + es.map(function (data, callback) { + callback(null, data * 2) + }), + es.map(function (data, callback) { + callback(null, data * 5) + }) + ) + + it(rw).has({readable: true, writable: true}) + + var array = [190, 24, 6, 7, 40, 57, 4, 6] + , _array = [] + , c = + es.connect( + es.readArray(array), + rw, + es.log('after rw:'), + es.writeArray(function (err, _array) { + it(_array).deepEqual(array.map(function (e) { return e * 10 })) + test.done() + }) + ) + +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/merge.asynct.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/merge.asynct.js new file mode 100644 index 0000000..17fae5b --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/merge.asynct.js @@ -0,0 +1,20 @@ +var es = require('../') + , it = require('it-is').style('colour') + , d = require('ubelt') + +exports.merge = function (t) { + var odd = d.map(1, 3, 100, d.id) //array of multiples of 3 < 100 + var even = d.map(2, 4, 100, d.id) //array of multiples of 3 < 100 + + var r1 = es.readArray(even) + var r2 = es.readArray(odd) + + var writer = es.writeArray(function (err, array){ + if(err) throw err //unpossible + it(array.sort()).deepEqual(even.concat(odd).sort()) + t.done() + }) + + es.merge(r1, r2).pipe(writer) + +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/pause.asynct.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/pause.asynct.js new file mode 100644 index 0000000..59d896f --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/pause.asynct.js @@ -0,0 +1,38 @@ + +var es = require('../') + , it = require('it-is') + , d = require('ubelt') + +exports ['gate buffers when shut'] = function (test) { + + var hundy = d.map(1,100, d.id) + , gate = es.pause() + , ten = 10 + es.connect( + es.readArray(hundy), + es.log('after readArray'), + gate, + //es.log('after gate'), + es.map(function (num, next) { + //stick a map in here to check that gate never emits when open + it(gate.paused).equal(false) + console.log('data', num) + if(!--ten) { + console.log('PAUSE') + gate.pause()//.resume() + d.delay(gate.resume.bind(gate), 10)() + ten = 10 + } + + next(null, num) + }), + es.writeArray(function (err, array) { //just realized that I should remove the error param. errors will be emitted + console.log('eonuhoenuoecbulc') + it(array).deepEqual(hundy) + test.done() + }) + ) + + gate.resume() + +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/pipeline.asynct.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/pipeline.asynct.js new file mode 100644 index 0000000..c2af9d8 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/pipeline.asynct.js @@ -0,0 +1,51 @@ +var es = require('..') + +exports['do not duplicate errors'] = function (test) { + + var errors = 0; + var pipe = es.pipeline( + es.through(function(data) { + return this.emit('data', data); + }), + es.through(function(data) { + return this.emit('error', new Error(data)); + }) + ) + + pipe.on('error', function(err) { + errors++ + console.log('error count', errors) + process.nextTick(function () { + return test.done(); + }) + }) + + return pipe.write('meh'); + +} + +exports['3 pipe do not duplicate errors'] = function (test) { + + var errors = 0; + var pipe = es.pipeline( + es.through(function(data) { + return this.emit('data', data); + }), + es.through(function(data) { + return this.emit('error', new Error(data)); + }), + es.through() + ) + + pipe.on('error', function(err) { + errors++ + console.log('error count', errors) + process.nextTick(function () { + return test.done(); + }) + }) + + return pipe.write('meh'); + +} + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/readArray.asynct.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/readArray.asynct.js new file mode 100644 index 0000000..76585ee --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/readArray.asynct.js @@ -0,0 +1,88 @@ + +var es = require('../') + , it = require('it-is').style('colour') + , d = require('ubelt') + +function readStream(stream, pauseAt, done) { + if(!done) done = pauseAt, pauseAt = -1 + var array = [] + stream.on('data', function (data) { + array.push(data) + if(!--pauseAt ) + stream.pause(), done(null, array) + }) + stream.on('error', done) + stream.on('end', function (data) { + done(null, array) + }) + +} + +exports ['read an array'] = function (test) { + + var readThis = d.map(3, 6, 100, d.id) //array of multiples of 3 < 100 + + var reader = es.readArray(readThis) + + var writer = es.writeArray(function (err, array){ + if(err) throw err //unpossible + it(array).deepEqual(readThis) + test.done() + }) + + reader.pipe(writer) +} + +exports ['read an array and pause it.'] = function (test) { + + var readThis = d.map(3, 6, 100, d.id) //array of multiples of 3 < 100 + + var reader = es.readArray(readThis) + + readStream(reader, 10, function (err, data) { + if(err) throw err + it(data).deepEqual([3, 6, 9, 12, 15, 18, 21, 24, 27, 30]) + readStream(reader, 10, function (err, data) { + it(data).deepEqual([33, 36, 39, 42, 45, 48, 51, 54, 57, 60]) + test.done() + }) + reader.resume() + }) + +} + +exports ['reader is readable, but not writeable'] = function (test) { + var reader = es.readArray([1]) + it(reader).has({ + readable: true, + writable: false + }) + + test.done() +} + + +exports ['read one item per tick'] = function (test) { + var readThis = d.map(3, 6, 100, d.id) //array of multiples of 3 < 100 + var drains = 0 + var reader = es.readArray(readThis) + var tickMapper = es.map(function (data,callback) { + process.nextTick(function () { + callback(null, data) + }) + //since tickMapper is returning false + //pipe should pause the writer until a drain occurs + return false + }) + reader.pipe(tickMapper) + readStream(tickMapper, function (err, array) { + it(array).deepEqual(readThis) + it(array.length).deepEqual(readThis.length) + it(drains).equal(readThis.length) + test.done() + }) + tickMapper.on('drain', function () { + drains ++ + }) + +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/readable.asynct.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/readable.asynct.js new file mode 100644 index 0000000..77d0039 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/readable.asynct.js @@ -0,0 +1,167 @@ + +var es = require('../') + , it = require('it-is').style('colour') + , u = require('ubelt') + +exports ['read an array'] = function (test) { + + var readThis = u.map(3, 6, 100, u.id) //array of multiples of 3 < 100 + + var reader = + es.readable(function (i, callback) { + if(i >= readThis.length) + return this.emit('end') + callback(null, readThis[i]) + }) + + var writer = es.writeArray(function (err, array){ + if(err) throw err + it(array).deepEqual(readThis) + test.done() + }) + + reader.pipe(writer) +} + +exports ['read an array - async'] = function (test) { + + var readThis = u.map(3, 6, 100, u.id) //array of multiples of 3 < 100 + + var reader = + es.readable(function (i, callback) { + if(i >= readThis.length) + return this.emit('end') + u.delay(callback)(null, readThis[i]) + }) + + var writer = es.writeArray(function (err, array){ + if(err) throw err + it(array).deepEqual(readThis) + test.done() + }) + + reader.pipe(writer) +} + + +exports ['emit data then call next() also works'] = function (test) { + + var readThis = u.map(3, 6, 100, u.id) //array of multiples of 3 < 100 + + var reader = + es.readable(function (i, next) { + if(i >= readThis.length) + return this.emit('end') + this.emit('data', readThis[i]) + next() + }) + + var writer = es.writeArray(function (err, array){ + if(err) throw err + it(array).deepEqual(readThis) + test.done() + }) + + reader.pipe(writer) +} + + +exports ['callback emits error, then stops'] = function (test) { + + var err = new Error('INTENSIONAL ERROR') + , called = 0 + + var reader = + es.readable(function (i, callback) { + if(called++) + return + callback(err) + }) + + reader.on('error', function (_err){ + it(_err).deepEqual(err) + u.delay(function() { + it(called).equal(1) + test.done() + }, 50)() + }) +} + +exports['readable does not call read concurrently'] = function (test) { + + var current = 0 + var source = es.readable(function(count, cb){ + current ++ + if(count > 100) + return this.emit('end') + u.delay(function(){ + current -- + it(current).equal(0) + cb(null, {ok: true, n: count}); + })(); + }); + + var destination = es.map(function(data, cb){ + //console.info(data); + cb(); + }); + + var all = es.connect(source, destination); + + destination.on('end', test.done) +} + + +// +// emitting multiple errors is not supported by stream. +// +// I do not think that this is a good idea, at least, there should be an option to pipe to +// continue on error. it makes alot ef sense, if you are using Stream like I am, to be able to emit multiple errors. +// an error might not necessarily mean the end of the stream. it depends on the error, at least. +// +// I will start a thread on the mailing list. I'd rather that than use a custom `pipe` implementation. +// +// basically, I want to be able use pipe to transform objects, and if one object is invalid, +// the next might still be good, so I should get to choose if it's gonna stop. +// re-enstate this test when this issue progresses. +// +// hmm. I could add this to es.connect by deregistering the error listener, +// but I would rather it be an option in core. + +/* +exports ['emit multiple errors, with 2nd parameter (continueOnError)'] = function (test) { + + var readThis = d.map(1, 100, d.id) + , errors = 0 + var reader = + es.readable(function (i, callback) { + console.log(i, readThis.length) + if(i >= readThis.length) + return this.emit('end') + if(!(readThis[i] % 7)) + return callback(readThis[i]) + callback(null, readThis[i]) + }, true) + + var writer = es.writeArray(function (err, array) { + if(err) throw err + it(array).every(function (u){ + it(u % 7).notEqual(0) + }).property('length', 80) + it(errors).equal(14) + test.done() + }) + + reader.on('error', function (u) { + errors ++ + console.log(u) + if('number' !== typeof u) + throw u + + it(u % 7).equal(0) + + }) + + reader.pipe(writer) +} +*/ diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/replace.asynct.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/replace.asynct.js new file mode 100644 index 0000000..7fabf6e --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/replace.asynct.js @@ -0,0 +1,50 @@ +var es = require('../') + , it = require('it-is').style('colour') + , d = require('ubelt') + , spec = require('stream-spec') + +var next = process.nextTick + +var fizzbuzz = '12F4BF78FB11F1314FB1617F19BF2223FB26F2829FB3132F34BF3738FB41F4344FB4647F49BF5253FB56F5859FB6162F64BF6768FB71F7374FB7677F79BF8283FB86F8889FB9192F94BF9798FB' + , fizz7buzz = '12F4BFseven8FB11F1314FB161sevenF19BF2223FB26F2829FB3132F34BF3seven38FB41F4344FB464sevenF49BF5253FB56F5859FB6162F64BF6seven68FBseven1Fseven3seven4FBseven6sevensevenFseven9BF8283FB86F8889FB9192F94BF9seven98FB' + +exports ['fizz buzz'] = function (test) { + + var readThis = d.map(1, 100, function (i) { + return ( + ! (i % 3 || i % 5) ? "FB" : + !(i % 3) ? "F" : + !(i % 5) ? "B" : + ''+i + ) + }) //array of multiples of 3 < 100 + + var reader = es.readArray(readThis) + var join = es.wait(function (err, string){ + it(string).equal(fizzbuzz) + test.done() + }) + reader.pipe(join) + +} + + +exports ['fizz buzz replace'] = function (test) { + var split = es.split(/(1)/) + var replace = es.replace('7', 'seven') + var x = spec(replace).through() + split + .pipe(replace) + .pipe(es.join(function (err, string) { + it(string).equal(fizz7buzz) + })) + + replace.on('close', function () { + x.validate() + test.done() + }) + + split.write(fizzbuzz) + split.end() + +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/simple-map.asynct.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/simple-map.asynct.js new file mode 100644 index 0000000..4786faa --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/simple-map.asynct.js @@ -0,0 +1,342 @@ +'use strict'; + +var es = require('../') + , it = require('it-is') + , u = require('ubelt') + , spec = require('stream-spec') + , Stream = require('stream') + , from = require('from') + , through = require('through') + +//REFACTOR THIS TEST TO USE es.readArray and es.writeArray + +function writeArray(array, stream) { + + array.forEach( function (j) { + stream.write(j) + }) + stream.end() + +} + +function readStream(stream, done) { + + var array = [] + stream.on('data', function (data) { + array.push(data) + }) + stream.on('error', done) + stream.on('end', function (data) { + done(null, array) + }) + +} + +//call sink on each write, +//and complete when finished. + +function pauseStream (prob, delay) { + var pauseIf = ( + 'number' == typeof prob + ? function () { + return Math.random() < prob + } + : 'function' == typeof prob + ? prob + : 0.1 + ) + var delayer = ( + !delay + ? process.nextTick + : 'number' == typeof delay + ? function (next) { setTimeout(next, delay) } + : delay + ) + + return es.through(function (data) { + if(!this.paused && pauseIf()) { + console.log('PAUSE STREAM PAUSING') + this.pause() + var self = this + delayer(function () { + console.log('PAUSE STREAM RESUMING') + self.resume() + }) + } + console.log("emit ('data', " + data + ')') + this.emit('data', data) + }) +} + +exports ['simple map'] = function (test) { + + var input = u.map(1, 1000, function () { + return Math.random() + }) + var expected = input.map(function (v) { + return v * 2 + }) + + var pause = pauseStream(0.1) + var fs = from(input) + var ts = es.writeArray(function (err, ar) { + it(ar).deepEqual(expected) + test.done() + }) + var map = es.through(function (data) { + this.emit('data', data * 2) + }) + + spec(map).through().validateOnExit() + spec(pause).through().validateOnExit() + + fs.pipe(map).pipe(pause).pipe(ts) +} + +exports ['simple map applied to a stream'] = function (test) { + + var input = [1,2,3,7,5,3,1,9,0,2,4,6] + //create event stream from + + var doubler = es.map(function (data, cb) { + cb(null, data * 2) + }) + + spec(doubler).through().validateOnExit() + + //a map is only a middle man, so it is both readable and writable + + it(doubler).has({ + readable: true, + writable: true, + }) + + readStream(doubler, function (err, output) { + it(output).deepEqual(input.map(function (j) { + return j * 2 + })) +// process.nextTick(x.validate) + test.done() + }) + + writeArray(input, doubler) + +} + +exports['pipe two maps together'] = function (test) { + + var input = [1,2,3,7,5,3,1,9,0,2,4,6] + //create event stream from + function dd (data, cb) { + cb(null, data * 2) + } + var doubler1 = es.map(dd), doubler2 = es.map(dd) + + doubler1.pipe(doubler2) + + spec(doubler1).through().validateOnExit() + spec(doubler2).through().validateOnExit() + + readStream(doubler2, function (err, output) { + it(output).deepEqual(input.map(function (j) { + return j * 4 + })) + test.done() + }) + + writeArray(input, doubler1) + +} + +//next: +// +// test pause, resume and drian. +// + +// then make a pipe joiner: +// +// plumber (evStr1, evStr2, evStr3, evStr4, evStr5) +// +// will return a single stream that write goes to the first + +exports ['map will not call end until the callback'] = function (test) { + + var ticker = es.map(function (data, cb) { + process.nextTick(function () { + cb(null, data * 2) + }) + }) + + spec(ticker).through().validateOnExit() + + ticker.write('x') + ticker.end() + + ticker.on('end', function () { + test.done() + }) +} + + +exports ['emit error thrown'] = function (test) { + + var err = new Error('INTENSIONAL ERROR') + , mapper = + es.map(function () { + throw err + }) + + mapper.on('error', function (_err) { + it(_err).equal(err) + test.done() + }) + +// onExit(spec(mapper).basic().validate) +//need spec that says stream may error. + + mapper.write('hello') + +} + +exports ['emit error calledback'] = function (test) { + + var err = new Error('INTENSIONAL ERROR') + , mapper = + es.map(function (data, callback) { + callback(err) + }) + + mapper.on('error', function (_err) { + it(_err).equal(err) + test.done() + }) + + mapper.write('hello') + +} + +exports ['do not emit drain if not paused'] = function (test) { + + var map = es.map(function (data, callback) { + u.delay(callback)(null, 1) + return true + }) + + spec(map).through().pausable().validateOnExit() + + map.on('drain', function () { + it(false).ok('should not emit drain unless the stream is paused') + }) + + it(map.write('hello')).equal(true) + it(map.write('hello')).equal(true) + it(map.write('hello')).equal(true) + setTimeout(function () {map.end()},10) + map.on('end', test.done) +} + +exports ['emits drain if paused, when all '] = function (test) { + var active = 0 + var drained = false + var map = es.map(function (data, callback) { + active ++ + u.delay(function () { + active -- + callback(null, 1) + })() + console.log('WRITE', false) + return false + }) + + spec(map).through().validateOnExit() + + map.on('drain', function () { + drained = true + it(active).equal(0, 'should emit drain when all maps are done') + }) + + it(map.write('hello')).equal(false) + it(map.write('hello')).equal(false) + it(map.write('hello')).equal(false) + + process.nextTick(function () {map.end()},10) + + map.on('end', function () { + console.log('end') + it(drained).ok('shoud have emitted drain before end') + test.done() + }) + +} + +exports ['map applied to a stream with filtering'] = function (test) { + + var input = [1,2,3,7,5,3,1,9,0,2,4,6] + + var doubler = es.map(function (data, callback) { + if (data % 2) + callback(null, data * 2) + else + callback() + }) + + readStream(doubler, function (err, output) { + it(output).deepEqual(input.filter(function (j) { + return j % 2 + }).map(function (j) { + return j * 2 + })) + test.done() + }) + + spec(doubler).through().validateOnExit() + + writeArray(input, doubler) + +} + +exports ['simple mapSync applied to a stream'] = function (test) { + + var input = [1,2,3,7,5,3,1,9,0,2,4,6] + + var doubler = es.mapSync(function (data) { + return data * 2 + }) + + readStream(doubler, function (err, output) { + it(output).deepEqual(input.map(function (j) { + return j * 2 + })) + test.done() + }) + + spec(doubler).through().validateOnExit() + + writeArray(input, doubler) + +} + +exports ['mapSync applied to a stream with filtering'] = function (test) { + + var input = [1,2,3,7,5,3,1,9,0,2,4,6] + + var doubler = es.mapSync(function (data) { + if (data % 2) + return data * 2 + }) + + readStream(doubler, function (err, output) { + it(output).deepEqual(input.filter(function (j) { + return j % 2 + }).map(function (j) { + return j * 2 + })) + test.done() + }) + + spec(doubler).through().validateOnExit() + + writeArray(input, doubler) + +} + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/spec.asynct.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/spec.asynct.js new file mode 100644 index 0000000..516dbf4 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/spec.asynct.js @@ -0,0 +1,85 @@ +/* + assert that data is called many times + assert that end is called eventually + + assert that when stream enters pause state, + on drain is emitted eventually. +*/ + +var es = require('..') +var it = require('it-is').style('colour') +var spec = require('stream-spec') + +exports['simple stream'] = function (test) { + + var stream = es.through() + var x = spec(stream).basic().pausable() + + stream.write(1) + stream.write(1) + stream.pause() + stream.write(1) + stream.resume() + stream.write(1) + stream.end(2) //this will call write() + + process.nextTick(function (){ + x.validate() + test.done() + }) +} + +exports['throw on write when !writable'] = function (test) { + + var stream = es.through() + var x = spec(stream).basic().pausable() + + stream.write(1) + stream.write(1) + stream.end(2) //this will call write() + stream.write(1) //this will be throwing..., but the spec will catch it. + + process.nextTick(function () { + x.validate() + test.done() + }) + +} + +exports['end fast'] = function (test) { + + var stream = es.through() + var x = spec(stream).basic().pausable() + + stream.end() //this will call write() + + process.nextTick(function () { + x.validate() + test.done() + }) + +} + + +/* + okay, that was easy enough, whats next? + + say, after you call paused(), write should return false + until resume is called. + + simple way to implement this: + write must return !paused + after pause() paused = true + after resume() paused = false + + on resume, if !paused drain is emitted again. + after drain, !paused + + there are lots of subtle ordering bugs in streams. + + example, set !paused before emitting drain. + + the stream api is stateful. +*/ + + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/split.asynct.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/split.asynct.js new file mode 100644 index 0000000..a0ce4b2 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/split.asynct.js @@ -0,0 +1,46 @@ +var es = require('../') + , it = require('it-is').style('colour') + , d = require('ubelt') + , join = require('path').join + , fs = require('fs') + , Stream = require('stream').Stream + , spec = require('stream-spec') + +exports ['es.split() works like String#split'] = function (test) { + var readme = join(__filename) + , expected = fs.readFileSync(readme, 'utf-8').split('\n') + , cs = es.split() + , actual = [] + , ended = false + , x = spec(cs).through() + + var a = new Stream () + + a.write = function (l) { + actual.push(l.trim()) + } + a.end = function () { + + ended = true + expected.forEach(function (v,k) { + //String.split will append an empty string '' + //if the string ends in a split pattern. + //es.split doesn't which was breaking this test. + //clearly, appending the empty string is correct. + //tests are passing though. which is the current job. + if(v) + it(actual[k]).like(v) + }) + //give the stream time to close + process.nextTick(function () { + test.done() + x.validate() + }) + } + a.writable = true + + fs.createReadStream(readme, {flags: 'r'}).pipe(cs) + cs.pipe(a) + +} + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/stringify.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/stringify.js new file mode 100644 index 0000000..a77887b --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/stringify.js @@ -0,0 +1,14 @@ + + + +var es = require('../') + +exports['handle buffer'] = function (t) { + + + es.stringify().on('data', function (d) { + t.equal(d.trim(), JSON.stringify('HELLO')) + t.end() + }).write(new Buffer('HELLO')) + +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/writeArray.asynct.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/writeArray.asynct.js new file mode 100644 index 0000000..f09fea2 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/event-stream/test/writeArray.asynct.js @@ -0,0 +1,30 @@ + +var es = require('../') + , it = require('it-is').style('colour') + , d = require('ubelt') + +exports ['write an array'] = function (test) { + + var readThis = d.map(3, 6, 100, d.id) //array of multiples of 3 < 100 + + var writer = es.writeArray(function (err, array){ + if(err) throw err //unpossible + it(array).deepEqual(readThis) + test.done() + }) + + d.each(readThis, writer.write.bind(writer)) + writer.end() + +} + + +exports ['writer is writable, but not readable'] = function (test) { + var reader = es.writeArray(function () {}) + it(reader).has({ + readable: false, + writable: true + }) + + test.done() +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/.npmignore b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/.npmignore new file mode 100644 index 0000000..ee88966 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/.npmignore @@ -0,0 +1 @@ +assets/ diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/.travis.yml b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/.travis.yml new file mode 100644 index 0000000..84fd7ca --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - 0.6 + - 0.8 + - 0.9 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/README.md b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/README.md new file mode 100644 index 0000000..6cd71ba --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/README.md @@ -0,0 +1,98 @@ +# tap-stream [![Build Status](https://secure.travis-ci.org/thlorenz/tap-stream.png)](http://travis-ci.org/thlorenz/tap-stream) + +Taps a nodejs stream and logs the data that's coming through. + + npm install tap-stream + +Given an [object stream](#object-stream) we can print out objects passing through and control the detail via the +depth parameter: + +```javascript +objectStream().pipe(tap(0)); +``` + +![depth0](https://github.com/thlorenz/tap-stream/raw/master/assets/depth0.png) + +```javascript +objectStream().pipe(tap(1)); +``` + +![depth1](https://github.com/thlorenz/tap-stream/raw/master/assets/depth1.png) + +``` +objectStream().pipe(tap(2)); +``` + +![depth2](https://github.com/thlorenz/tap-stream/raw/master/assets/depth2.png) + +For even more control a custom log function may be supplied: + +```javascript +objectStream() + .pipe(tap(function customLog (data) { + var nest = data.nest; + console.log ('Bird: %s, id: %s, age: %s, layed egg: %s', nest.name, data.id, nest.age, nest.egg !== undefined); + }) + ); +``` + +```text +Bird: yellow rumped warbler, id: 0, age: 1, layed egg: true +Bird: yellow rumped warbler, id: 1, age: 1, layed egg: true +``` + +## API + +### tap( [ depth | log ] ) + +Intercepts the stream and logs data that is passing through. + +- optional parameter is either a `Number` or a `Function` +- if no parameter is given, `depth` defaults to `0` and `log` to `console.log(util.inspect(..))` + +- `depth` controls the `depth` with which + [util.inspect](http://nodejs.org/api/util.html#util_util_inspect_object_showhidden_depth_colors) is called +- `log` replaces the default logging function with a custom one + +**Example:** + +```javascript +var tap = require('tap-stream'); + +myStream + .pipe(tap(1)) // log intermediate results + .pipe(..) // continute manipulating the data +``` + +## Object stream + +Included in order to give context for above examples. + +```javascript +function objectStream () { + var s = new Stream() + , objects = 0; + + var iv = setInterval( + function () { + s.emit('data', { + id: objects + , created: new Date() + , nest: { + name: 'yellow rumped warbler' + , age: 1 + , egg: { name: 'unknown' , age: 0 } + } + } + , 4 + ); + + if (++objects === 2) { + s.emit('end'); + clearInterval(iv); + } + } + , 200); + return s; +} +``` diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/examples/tap-nested-objects.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/examples/tap-nested-objects.js new file mode 100644 index 0000000..97aa578 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/examples/tap-nested-objects.js @@ -0,0 +1,38 @@ +var Stream = require('stream') + , tap = require('..'); + +function objectStream () { + var s = new Stream() + , objects = 0; + + var iv = setInterval( + function () { + s.emit('data', { + id: objects + , created: new Date() + , nest: { + name: 'yellow rumped warbler' + , age: 1 + , egg: { name: 'unknown' , age: 0 } + } + } + ); + + if (++objects === 2) { + s.emit('end'); + clearInterval(iv); + } + } + , 200); + return s; +} + +objectStream().pipe(tap(2)); + +objectStream() + .pipe(tap(function customLog (data) { + var nest = data.nest; + console.log ('Bird: %s, id: %s, age: %s, layed egg: %s', nest.name, data.id, nest.age, nest.egg !== undefined); + }) + ); + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/index.js new file mode 100644 index 0000000..a541dfe --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/index.js @@ -0,0 +1,56 @@ +'use strict'; + +var util = require('util') + , through = require('through') + , toString = Object.prototype.toString + , slice = Array.prototype.slice; + +function blowup () { + throw new Error('Argument to streamTap needs to be either Number for depth or a log Function'); +} + +function defaultLog (depth) { + function log (data) { + console.log(util.inspect(data, false, depth, true)); + } + + return function (data) { + if (arguments.length === 1) { + log(data); + } else { + slice.call(arguments).forEach(log); + } + }; +} + +// invoke three ways: +// tap () +// tap (depth) +// tap (log) +function tap (arg0) { + var log; + + if (!arguments.length) { + log = defaultLog(1); + } else { + + if (toString.call(arg0) === '[object Number]' ) { + log = defaultLog(arg0); + } else if (toString.call(arg0) === '[object Function]' ) { + log = arg0; + } else { + blowup(); + } + + } + + return through( + function write (data) { + log(data); + this.emit('data', data); + } + ); + +} + +module.exports = tap; diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/.travis.yml b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/.travis.yml new file mode 100644 index 0000000..895dbd3 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.6 + - 0.8 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/LICENSE.APACHE2 b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/LICENSE.APACHE2 new file mode 100644 index 0000000..6366c04 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/LICENSE.APACHE2 @@ -0,0 +1,15 @@ +Apache License, Version 2.0 + +Copyright (c) 2011 Dominic Tarr + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/LICENSE.MIT b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/LICENSE.MIT new file mode 100644 index 0000000..6eafbd7 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/LICENSE.MIT @@ -0,0 +1,24 @@ +The MIT License + +Copyright (c) 2011 Dominic Tarr + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/index.js new file mode 100644 index 0000000..7072b37 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/index.js @@ -0,0 +1,100 @@ +var Stream = require('stream') + +// through +// +// a stream that does nothing but re-emit the input. +// useful for aggregating a series of changing but not ending streams into one stream) + + + +exports = module.exports = through +through.through = through + +//create a readable writable stream. + +function through (write, end) { + write = write || function (data) { this.emit('data', data) } + end = end || function () { this.emit('end') } + + var ended = false, destroyed = false + var stream = new Stream(), buffer = [] + stream.buffer = buffer + stream.readable = stream.writable = true + stream.paused = false + stream.write = function (data) { + write.call(this, data) + return !stream.paused + } + + function drain() { + while(buffer.length && !stream.paused) { + var data = buffer.shift() + if(null === data) + return stream.emit('end') + else + stream.emit('data', data) + } + } + + stream.queue = function (data) { + buffer.push(data) + drain() + } + + //this will be registered as the first 'end' listener + //must call destroy next tick, to make sure we're after any + //stream piped from here. + //this is only a problem if end is not emitted synchronously. + //a nicer way to do this is to make sure this is the last listener for 'end' + + stream.on('end', function () { + stream.readable = false + if(!stream.writable) + process.nextTick(function () { + stream.destroy() + }) + }) + + function _end () { + stream.writable = false + end.call(stream) + if(!stream.readable) + stream.destroy() + } + + stream.end = function (data) { + if(ended) return + //this breaks, because pipe doesn't check writable before calling end. + //throw new Error('cannot call end twice') + ended = true + if(arguments.length) stream.write(data) + if(!buffer.length) _end() + } + + stream.destroy = function () { + if(destroyed) return + destroyed = true + ended = true + buffer.length = 0 + stream.writable = stream.readable = false + stream.emit('close') + } + + stream.pause = function () { + if(stream.paused) return + stream.paused = true + stream.emit('pause') + } + stream.resume = function () { + if(stream.paused) { + stream.paused = false + } + drain() + //may have become paused again, + //as drain emits 'data'. + if(!stream.paused) + stream.emit('drain') + } + return stream +} + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/package.json new file mode 100644 index 0000000..168247e --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/package.json @@ -0,0 +1,34 @@ +{ + "name": "through", + "version": "1.1.0", + "description": "simplified stream contruction", + "main": "index.js", + "scripts": { + "test": "asynct test/*.js" + }, + "devDependencies": { + "stream-spec": "0", + "assertions": "2", + "asynct": "1" + }, + "keywords": [ + "stream", + "streams", + "user-streams", + "pipe" + ], + "author": { + "name": "Dominic Tarr", + "email": "dominic.tarr@gmail.com", + "url": "dominictarr.com" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/dominictarr/through.git" + }, + "homepage": "http://github.com/dominictarr/through", + "readme": "#through\n\n[![build status](https://secure.travis-ci.org/dominictarr/through.png)](http://travis-ci.org/dominictarr/through)\n\nEasy way to create a `Stream` that is both `readable` and `writable`. Pass in optional `write` and `end` methods. `through` takes care of pause/resume logic.\nUse `this.pause()` and `this.resume()` to manage flow.\nCheck `this.paused` to see current flow state. (write always returns `!this.paused`)\n\nthis function is the basis for most of the syncronous streams in [event-stream](http://github.com/dominictarr/event-stream).\n\n``` js\nvar through = require('through')\n\nthrough(function write(data) {\n this.emit('data', data)\n //this.pause() \n },\n function end () { //optional\n this.emit('end')\n })\n\n```\n\nor, with buffering on pause, use `this.queue(data)`,\ndata *cannot* be `null`. `this.queue(null)` will emit 'end'\nwhen it gets to the `null` element.\n\n``` js\nvar through = require('through')\n\nthrough(function write(data) {\n this.queue(data)\n //this.pause() \n },\n function end () { //optional\n this.queue(null)\n })\n\n```\n\n\n## License\n\nMIT / Apache2\n", + "_id": "through@1.1.0", + "_from": "through@~1.1.0" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/readme.markdown b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/readme.markdown new file mode 100644 index 0000000..1b687e9 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/readme.markdown @@ -0,0 +1,44 @@ +#through + +[![build status](https://secure.travis-ci.org/dominictarr/through.png)](http://travis-ci.org/dominictarr/through) + +Easy way to create a `Stream` that is both `readable` and `writable`. Pass in optional `write` and `end` methods. `through` takes care of pause/resume logic. +Use `this.pause()` and `this.resume()` to manage flow. +Check `this.paused` to see current flow state. (write always returns `!this.paused`) + +this function is the basis for most of the syncronous streams in [event-stream](http://github.com/dominictarr/event-stream). + +``` js +var through = require('through') + +through(function write(data) { + this.emit('data', data) + //this.pause() + }, + function end () { //optional + this.emit('end') + }) + +``` + +or, with buffering on pause, use `this.queue(data)`, +data *cannot* be `null`. `this.queue(null)` will emit 'end' +when it gets to the `null` element. + +``` js +var through = require('through') + +through(function write(data) { + this.queue(data) + //this.pause() + }, + function end () { //optional + this.queue(null) + }) + +``` + + +## License + +MIT / Apache2 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/test/buffering.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/test/buffering.js new file mode 100644 index 0000000..1ce4b0d --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/test/buffering.js @@ -0,0 +1,37 @@ +var through = require('..') + +// must emit end before close. + +exports['buffering'] = function (t) { + var ts = through(function (data) { + this.queue(data) + }, function () { + this.queue(null) + }) + + var ended = false, actual = [] + + ts.on('data', actual.push.bind(actual)) + ts.on('end', function () { + ended = true + }) + + ts.write(1) + ts.write(2) + ts.write(3) + t.deepEqual(actual, [1, 2, 3]) + ts.pause() + ts.write(4) + ts.write(5) + ts.write(6) + t.deepEqual(actual, [1, 2, 3]) + ts.resume() + t.deepEqual(actual, [1, 2, 3, 4, 5, 6]) + ts.pause() + ts.end() + t.ok(!ended) + ts.resume() + t.ok(ended) + t.end() + +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/test/end.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/test/end.js new file mode 100644 index 0000000..280da0a --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/test/end.js @@ -0,0 +1,27 @@ +var through = require('..') + +// must emit end before close. + +exports['end before close'] = function (t) { + var ts = through() + var ended = false, closed = false + + ts.on('end', function () { + t.ok(!closed) + ended = true + }) + ts.on('close', function () { + t.ok(ended) + closed = true + }) + + ts.write(1) + ts.write(2) + ts.write(3) + ts.end() + t.ok(ended) + t.ok(closed) + + t.end() + +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/test/index.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/test/index.js new file mode 100644 index 0000000..25a6ea7 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/node_modules/through/test/index.js @@ -0,0 +1,113 @@ + +var spec = require('stream-spec') +var through = require('..') +var a = require('assertions') + +/* + I'm using these two functions, and not streams and pipe + so there is less to break. if this test fails it must be + the implementation of _through_ +*/ + +function write(array, stream) { + array = array.slice() + function next() { + while(array.length) + if(stream.write(array.shift()) === false) + return stream.once('drain', next) + + stream.end() + } + + next() +} + +function read(stream, callback) { + var actual = [] + stream.on('data', function (data) { + actual.push(data) + }) + stream.once('end', function () { + callback(null, actual) + }) + stream.once('error', function (err) { + callback(err) + }) +} + +exports['simple defaults'] = function (test) { + + var l = 1000 + , expected = [] + + while(l--) expected.push(l * Math.random()) + + var t = through() + spec(t) + .through() + .pausable() + .validateOnExit() + + read(t, function (err, actual) { + if(err) test.error(err) //fail + a.deepEqual(actual, expected) + test.done() + }) + + write(expected, t) +} + +exports['simple functions'] = function (test) { + + var l = 1000 + , expected = [] + + while(l--) expected.push(l * Math.random()) + + var t = through(function (data) { + this.emit('data', data*2) + }) + spec(t) + .through() + .pausable() + .validateOnExit() + + read(t, function (err, actual) { + if(err) test.error(err) //fail + a.deepEqual(actual, expected.map(function (data) { + return data*2 + })) + test.done() + }) + + write(expected, t) +} +exports['pauses'] = function (test) { + + var l = 1000 + , expected = [] + + while(l--) expected.push(l) //Math.random()) + + var t = through() + spec(t) + .through() + .pausable() + .validateOnExit() + + t.on('data', function () { + if(Math.random() > 0.1) return + t.pause() + process.nextTick(function () { + t.resume() + }) + }) + + read(t, function (err, actual) { + if(err) test.error(err) //fail + a.deepEqual(actual, expected) + test.done() + }) + + write(expected, t) +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/package.json new file mode 100644 index 0000000..8040579 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/package.json @@ -0,0 +1,38 @@ +{ + "name": "tap-stream", + "version": "0.1.0", + "author": { + "name": "Thorsten Lorenz", + "email": "thlorenz@gmx.de", + "url": "http://thlorenz.com" + }, + "description": "Taps a nodejs stream and logs the data that's coming through.", + "main": "index.js", + "directories": { + "test": "test" + }, + "scripts": { + "test": "tap ./test/*.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/thlorenz/tap-stream.git" + }, + "keywords": [ + "stream", + "streams", + "log", + "print", + "inspect" + ], + "license": "BSD", + "dependencies": { + "through": "~1.1.0" + }, + "devDependencies": { + "tap": "~0.3.1" + }, + "readme": "# tap-stream [![Build Status](https://secure.travis-ci.org/thlorenz/tap-stream.png)](http://travis-ci.org/thlorenz/tap-stream)\n\nTaps a nodejs stream and logs the data that's coming through.\n\n npm install tap-stream\n\nGiven an [object stream](#object-stream) we can print out objects passing through and control the detail via the\ndepth parameter:\n\n```javascript\nobjectStream().pipe(tap(0));\n```\n\n![depth0](https://github.com/thlorenz/tap-stream/raw/master/assets/depth0.png)\n\n```javascript\nobjectStream().pipe(tap(1));\n```\n\n![depth1](https://github.com/thlorenz/tap-stream/raw/master/assets/depth1.png)\n\n```\nobjectStream().pipe(tap(2));\n```\n\n![depth2](https://github.com/thlorenz/tap-stream/raw/master/assets/depth2.png)\n\nFor even more control a custom log function may be supplied:\n\n```javascript\nobjectStream()\n .pipe(tap(function customLog (data) {\n var nest = data.nest;\n console.log ('Bird: %s, id: %s, age: %s, layed egg: %s', nest.name, data.id, nest.age, nest.egg !== undefined);\n })\n );\n```\n\n```text\nBird: yellow rumped warbler, id: 0, age: 1, layed egg: true\nBird: yellow rumped warbler, id: 1, age: 1, layed egg: true\n```\n\n## API\n\n### tap( [ depth | log ] )\n\nIntercepts the stream and logs data that is passing through.\n\n- optional parameter is either a `Number` or a `Function`\n- if no parameter is given, `depth` defaults to `0` and `log` to `console.log(util.inspect(..))`\n\n- `depth` controls the `depth` with which\n [util.inspect](http://nodejs.org/api/util.html#util_util_inspect_object_showhidden_depth_colors) is called\n- `log` replaces the default logging function with a custom one\n\n**Example:**\n\n```javascript\nvar tap = require('tap-stream');\n\nmyStream\n .pipe(tap(1)) // log intermediate results\n .pipe(..) // continute manipulating the data\n```\n\n## Object stream\n\nIncluded in order to give context for above examples.\n\n```javascript\nfunction objectStream () {\n var s = new Stream()\n , objects = 0;\n \n var iv = setInterval(\n function () {\n s.emit('data', { \n id: objects\n , created: new Date()\n , nest: { \n name: 'yellow rumped warbler'\n , age: 1\n , egg: { name: 'unknown' , age: 0 }\n } \n }\n , 4\n );\n\n if (++objects === 2) {\n s.emit('end');\n clearInterval(iv);\n }\n }\n , 200);\n return s;\n}\n```\n", + "_id": "tap-stream@0.1.0", + "_from": "tap-stream@~0.1.0" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/test/tap-stream.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/test/tap-stream.js new file mode 100644 index 0000000..b484fcb --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/node_modules/tap-stream/test/tap-stream.js @@ -0,0 +1,104 @@ +'use strict'; +/*jshint asi: true */ + +var test = require('tap').test + , Stream = require('stream') + , tap = require('..') + , through = require('through'); + +function objectStream () { + var s = new Stream() + , objects = 0; + + var iv = setInterval( + function () { + s.emit('data', { id: objects, created: new Date() }); + + if (++objects === 2) { + s.emit('end'); + clearInterval(iv); + } + } + , 20); + return s; +} + +test('tapping object stream that emits 2 objects', function (t) { + var logged = [] + , piped = []; + + function log (data) { + logged.push(data); + } + + t.plan(4); + + objectStream() + .pipe(tap(log)) + .pipe(through( + function write (data) { + piped.push(data); + this.emit('data', data); + } + , function end (data) { + + t.equals(0, logged[0].id, 'logs first item'); + t.equals(1, logged[1].id, 'logs second item'); + + t.equals(0, piped[0].id, 'pipes first item'); + t.equals(1, piped[1].id, 'pipes second item'); + + t.end(); + + this.emit('end'); + } + )) +}) + +/* The below doesn't work since pipe only writes one argument: + * https://github.com/joyent/node/blob/master/lib/stream.js#L36 + * + * Since it uses EventEmitter whose 'emit' supports multiple args, this may change in the future - I hope so. + * Until then ... + */ +var onDataInsidePipeWritesMultipleArgs = false; + +if (! onDataInsidePipeWritesMultipleArgs) return; + +function numberStream () { + var s = new Stream(); + + setTimeout( + function () { + s.emit('data', 1, 2); + s.emit('end'); + } + , 20); + return s; +} + +test('tapping stream that emits a number and a string one time', function (t) { + var logged = [] + , piped = []; + + function log (n1, n2) { + logged.push({ n1: n1, n2: n2 }); + } + + t.plan(2); + + numberStream() + .pipe(tap(log)) + .pipe(through( + function write (n1, n2) { + piped.push({ n1: n1, n2: n2 }); + } + , function end () { + t.equals({ n1: 1, n2: 2 }, logged[0], 'logs both numbers'); + t.equals({ n1: 1, n2: 2 }, piped[0], 'pipes both numbers'); + t.end(); + + this.emit('end'); + } + )) +}) diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/package.json new file mode 100644 index 0000000..2d9b341 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/package.json @@ -0,0 +1,9 @@ +{ + "name": "readdirp-examples", + "version": "0.0.0", + "description": "Examples for readdirp.", + "dependencies": { + "tap-stream": "~0.1.0", + "event-stream": "~3.0.7" + } +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/stream-api-pipe.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/stream-api-pipe.js new file mode 100644 index 0000000..b09fe59 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/stream-api-pipe.js @@ -0,0 +1,13 @@ +var readdirp = require('..') + , path = require('path') + , es = require('event-stream'); + +// print out all JavaScript files along with their size +readdirp({ root: path.join(__dirname), fileFilter: '*.js' }) + .on('warn', function (err) { console.error('non-fatal error', err); }) + .on('error', function (err) { console.error('fatal error', err); }) + .pipe(es.mapSync(function (entry) { + return { path: entry.path, size: entry.stat.size }; + })) + .pipe(es.stringify()) + .pipe(process.stdout); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/stream-api.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/stream-api.js new file mode 100644 index 0000000..0f7b327 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/examples/stream-api.js @@ -0,0 +1,15 @@ +var readdirp = require('..') + , path = require('path'); + +readdirp({ root: path.join(__dirname), fileFilter: '*.js' }) + .on('warn', function (err) { + console.error('something went wrong when processing an entry', err); + }) + .on('error', function (err) { + console.error('something went fatally wrong and the stream was aborted', err); + }) + .on('data', function (entry) { + console.log('%s is ready for processing', entry.path); + // process entry here + }); + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/LICENSE b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/LICENSE new file mode 100644 index 0000000..05a4010 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/LICENSE @@ -0,0 +1,23 @@ +Copyright 2009, 2010, 2011 Isaac Z. Schlueter. +All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/README.md b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/README.md new file mode 100644 index 0000000..6fd07d2 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/README.md @@ -0,0 +1,218 @@ +# minimatch + +A minimal matching utility. + +[![Build Status](https://secure.travis-ci.org/isaacs/minimatch.png)](http://travis-ci.org/isaacs/minimatch) + + +This is the matching library used internally by npm. + +Eventually, it will replace the C binding in node-glob. + +It works by converting glob expressions into JavaScript `RegExp` +objects. + +## Usage + +```javascript +var minimatch = require("minimatch") + +minimatch("bar.foo", "*.foo") // true! +minimatch("bar.foo", "*.bar") // false! +``` + +## Features + +Supports these glob features: + +* Brace Expansion +* Extended glob matching +* "Globstar" `**` matching + +See: + +* `man sh` +* `man bash` +* `man 3 fnmatch` +* `man 5 gitignore` + +### Comparisons to other fnmatch/glob implementations + +While strict compliance with the existing standards is a worthwhile +goal, some discrepancies exist between minimatch and other +implementations, and are intentional. + +If the pattern starts with a `!` character, then it is negated. Set the +`nonegate` flag to suppress this behavior, and treat leading `!` +characters normally. This is perhaps relevant if you wish to start the +pattern with a negative extglob pattern like `!(a|B)`. Multiple `!` +characters at the start of a pattern will negate the pattern multiple +times. + +If a pattern starts with `#`, then it is treated as a comment, and +will not match anything. Use `\#` to match a literal `#` at the +start of a line, or set the `nocomment` flag to suppress this behavior. + +The double-star character `**` is supported by default, unless the +`noglobstar` flag is set. This is supported in the manner of bsdglob +and bash 4.1, where `**` only has special significance if it is the only +thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but +`a/**b` will not. **Note that this is different from the way that `**` is +handled by ruby's `Dir` class.** + +If an escaped pattern has no matches, and the `nonull` flag is set, +then minimatch.match returns the pattern as-provided, rather than +interpreting the character escapes. For example, +`minimatch.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than +`"*a?"`. This is akin to setting the `nullglob` option in bash, except +that it does not resolve escaped pattern characters. + +If brace expansion is not disabled, then it is performed before any +other interpretation of the glob pattern. Thus, a pattern like +`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded +**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are +checked for validity. Since those two are valid, matching proceeds. + + +## Minimatch Class + +Create a minimatch object by instanting the `minimatch.Minimatch` class. + +```javascript +var Minimatch = require("minimatch").Minimatch +var mm = new Minimatch(pattern, options) +``` + +### Properties + +* `pattern` The original pattern the minimatch object represents. +* `options` The options supplied to the constructor. +* `set` A 2-dimensional array of regexp or string expressions. + Each row in the + array corresponds to a brace-expanded pattern. Each item in the row + corresponds to a single path-part. For example, the pattern + `{a,b/c}/d` would expand to a set of patterns like: + + [ [ a, d ] + , [ b, c, d ] ] + + If a portion of the pattern doesn't have any "magic" in it + (that is, it's something like `"foo"` rather than `fo*o?`), then it + will be left as a string rather than converted to a regular + expression. + +* `regexp` Created by the `makeRe` method. A single regular expression + expressing the entire pattern. This is useful in cases where you wish + to use the pattern somewhat like `fnmatch(3)` with `FNM_PATH` enabled. +* `negate` True if the pattern is negated. +* `comment` True if the pattern is a comment. +* `empty` True if the pattern is `""`. + +### Methods + +* `makeRe` Generate the `regexp` member if necessary, and return it. + Will return `false` if the pattern is invalid. +* `match(fname)` Return true if the filename matches the pattern, or + false otherwise. +* `matchOne(fileArray, patternArray, partial)` Take a `/`-split + filename, and match it against a single row in the `regExpSet`. This + method is mainly for internal use, but is exposed so that it can be + used by a glob-walker that needs to avoid excessive filesystem calls. + +All other methods are internal, and will be called as necessary. + +## Functions + +The top-level exported function has a `cache` property, which is an LRU +cache set to store 100 items. So, calling these methods repeatedly +with the same pattern and options will use the same Minimatch object, +saving the cost of parsing it multiple times. + +### minimatch(path, pattern, options) + +Main export. Tests a path against the pattern using the options. + +```javascript +var isJS = minimatch(file, "*.js", { matchBase: true }) +``` + +### minimatch.filter(pattern, options) + +Returns a function that tests its +supplied argument, suitable for use with `Array.filter`. Example: + +```javascript +var javascripts = fileList.filter(minimatch.filter("*.js", {matchBase: true})) +``` + +### minimatch.match(list, pattern, options) + +Match against the list of +files, in the style of fnmatch or glob. If nothing is matched, and +options.nonull is set, then return a list containing the pattern itself. + +```javascript +var javascripts = minimatch.match(fileList, "*.js", {matchBase: true})) +``` + +### minimatch.makeRe(pattern, options) + +Make a regular expression object from the pattern. + +## Options + +All options are `false` by default. + +### debug + +Dump a ton of stuff to stderr. + +### nobrace + +Do not expand `{a,b}` and `{1..3}` brace sets. + +### noglobstar + +Disable `**` matching against multiple folder names. + +### dot + +Allow patterns to match filenames starting with a period, even if +the pattern does not explicitly have a period in that spot. + +Note that by default, `a/**/b` will **not** match `a/.d/b`, unless `dot` +is set. + +### noext + +Disable "extglob" style patterns like `+(a|b)`. + +### nocase + +Perform a case-insensitive match. + +### nonull + +When a match is not found by `minimatch.match`, return a list containing +the pattern itself. When set, an empty list is returned if there are +no matches. + +### matchBase + +If set, then patterns without slashes will be matched +against the basename of the path if it contains slashes. For example, +`a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`. + +### nocomment + +Suppress the behavior of treating `#` at the start of a pattern as a +comment. + +### nonegate + +Suppress the behavior of treating a leading `!` character as negation. + +### flipNegate + +Returns from negate expressions the same as if they were not negated. +(Ie, true on a hit, false on a miss.) diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/minimatch.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/minimatch.js new file mode 100644 index 0000000..405746b --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/minimatch.js @@ -0,0 +1,1079 @@ +;(function (require, exports, module, platform) { + +if (module) module.exports = minimatch +else exports.minimatch = minimatch + +if (!require) { + require = function (id) { + switch (id) { + case "sigmund": return function sigmund (obj) { + return JSON.stringify(obj) + } + case "path": return { basename: function (f) { + f = f.split(/[\/\\]/) + var e = f.pop() + if (!e) e = f.pop() + return e + }} + case "lru-cache": return function LRUCache () { + // not quite an LRU, but still space-limited. + var cache = {} + var cnt = 0 + this.set = function (k, v) { + cnt ++ + if (cnt >= 100) cache = {} + cache[k] = v + } + this.get = function (k) { return cache[k] } + } + } + } +} + +minimatch.Minimatch = Minimatch + +var LRU = require("lru-cache") + , cache = minimatch.cache = new LRU({max: 100}) + , GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} + , sigmund = require("sigmund") + +var path = require("path") + // any single thing other than / + // don't need to escape / when using new RegExp() + , qmark = "[^/]" + + // * => any number of characters + , star = qmark + "*?" + + // ** when dots are allowed. Anything goes, except .. and . + // not (^ or / followed by one or two dots followed by $ or /), + // followed by anything, any number of times. + , twoStarDot = "(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?" + + // not a ^ or / followed by a dot, + // followed by anything, any number of times. + , twoStarNoDot = "(?:(?!(?:\\\/|^)\\.).)*?" + + // characters that need to be escaped in RegExp. + , reSpecials = charSet("().*{}+?[]^$\\!") + +// "abc" -> { a:true, b:true, c:true } +function charSet (s) { + return s.split("").reduce(function (set, c) { + set[c] = true + return set + }, {}) +} + +// normalizes slashes. +var slashSplit = /\/+/ + +minimatch.monkeyPatch = monkeyPatch +function monkeyPatch () { + var desc = Object.getOwnPropertyDescriptor(String.prototype, "match") + var orig = desc.value + desc.value = function (p) { + if (p instanceof Minimatch) return p.match(this) + return orig.call(this, p) + } + Object.defineProperty(String.prototype, desc) +} + +minimatch.filter = filter +function filter (pattern, options) { + options = options || {} + return function (p, i, list) { + return minimatch(p, pattern, options) + } +} + +function ext (a, b) { + a = a || {} + b = b || {} + var t = {} + Object.keys(b).forEach(function (k) { + t[k] = b[k] + }) + Object.keys(a).forEach(function (k) { + t[k] = a[k] + }) + return t +} + +minimatch.defaults = function (def) { + if (!def || !Object.keys(def).length) return minimatch + + var orig = minimatch + + var m = function minimatch (p, pattern, options) { + return orig.minimatch(p, pattern, ext(def, options)) + } + + m.Minimatch = function Minimatch (pattern, options) { + return new orig.Minimatch(pattern, ext(def, options)) + } + + return m +} + +Minimatch.defaults = function (def) { + if (!def || !Object.keys(def).length) return Minimatch + return minimatch.defaults(def).Minimatch +} + + +function minimatch (p, pattern, options) { + if (typeof pattern !== "string") { + throw new TypeError("glob pattern string required") + } + + if (!options) options = {} + + // shortcut: comments match nothing. + if (!options.nocomment && pattern.charAt(0) === "#") { + return false + } + + // "" only matches "" + if (pattern.trim() === "") return p === "" + + return new Minimatch(pattern, options).match(p) +} + +function Minimatch (pattern, options) { + if (!(this instanceof Minimatch)) { + return new Minimatch(pattern, options, cache) + } + + if (typeof pattern !== "string") { + throw new TypeError("glob pattern string required") + } + + if (!options) options = {} + pattern = pattern.trim() + + // windows: need to use /, not \ + // On other platforms, \ is a valid (albeit bad) filename char. + if (platform === "win32") { + pattern = pattern.split("\\").join("/") + } + + // lru storage. + // these things aren't particularly big, but walking down the string + // and turning it into a regexp can get pretty costly. + var cacheKey = pattern + "\n" + sigmund(options) + var cached = minimatch.cache.get(cacheKey) + if (cached) return cached + minimatch.cache.set(cacheKey, this) + + this.options = options + this.set = [] + this.pattern = pattern + this.regexp = null + this.negate = false + this.comment = false + this.empty = false + + // make the set of regexps etc. + this.make() +} + +Minimatch.prototype.make = make +function make () { + // don't do it more than once. + if (this._made) return + + var pattern = this.pattern + var options = this.options + + // empty patterns and comments match nothing. + if (!options.nocomment && pattern.charAt(0) === "#") { + this.comment = true + return + } + if (!pattern) { + this.empty = true + return + } + + // step 1: figure out negation, etc. + this.parseNegate() + + // step 2: expand braces + var set = this.globSet = this.braceExpand() + + if (options.debug) console.error(this.pattern, set) + + // step 3: now we have a set, so turn each one into a series of path-portion + // matching patterns. + // These will be regexps, except in the case of "**", which is + // set to the GLOBSTAR object for globstar behavior, + // and will not contain any / characters + set = this.globParts = set.map(function (s) { + return s.split(slashSplit) + }) + + if (options.debug) console.error(this.pattern, set) + + // glob --> regexps + set = set.map(function (s, si, set) { + return s.map(this.parse, this) + }, this) + + if (options.debug) console.error(this.pattern, set) + + // filter out everything that didn't compile properly. + set = set.filter(function (s) { + return -1 === s.indexOf(false) + }) + + if (options.debug) console.error(this.pattern, set) + + this.set = set +} + +Minimatch.prototype.parseNegate = parseNegate +function parseNegate () { + var pattern = this.pattern + , negate = false + , options = this.options + , negateOffset = 0 + + if (options.nonegate) return + + for ( var i = 0, l = pattern.length + ; i < l && pattern.charAt(i) === "!" + ; i ++) { + negate = !negate + negateOffset ++ + } + + if (negateOffset) this.pattern = pattern.substr(negateOffset) + this.negate = negate +} + +// Brace expansion: +// a{b,c}d -> abd acd +// a{b,}c -> abc ac +// a{0..3}d -> a0d a1d a2d a3d +// a{b,c{d,e}f}g -> abg acdfg acefg +// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg +// +// Invalid sets are not expanded. +// a{2..}b -> a{2..}b +// a{b}c -> a{b}c +minimatch.braceExpand = function (pattern, options) { + return new Minimatch(pattern, options).braceExpand() +} + +Minimatch.prototype.braceExpand = braceExpand +function braceExpand (pattern, options) { + options = options || this.options + pattern = typeof pattern === "undefined" + ? this.pattern : pattern + + if (typeof pattern === "undefined") { + throw new Error("undefined pattern") + } + + if (options.nobrace || + !pattern.match(/\{.*\}/)) { + // shortcut. no need to expand. + return [pattern] + } + + var escaping = false + + // examples and comments refer to this crazy pattern: + // a{b,c{d,e},{f,g}h}x{y,z} + // expected: + // abxy + // abxz + // acdxy + // acdxz + // acexy + // acexz + // afhxy + // afhxz + // aghxy + // aghxz + + // everything before the first \{ is just a prefix. + // So, we pluck that off, and work with the rest, + // and then prepend it to everything we find. + if (pattern.charAt(0) !== "{") { + // console.error(pattern) + var prefix = null + for (var i = 0, l = pattern.length; i < l; i ++) { + var c = pattern.charAt(i) + // console.error(i, c) + if (c === "\\") { + escaping = !escaping + } else if (c === "{" && !escaping) { + prefix = pattern.substr(0, i) + break + } + } + + // actually no sets, all { were escaped. + if (prefix === null) { + // console.error("no sets") + return [pattern] + } + + var tail = braceExpand(pattern.substr(i), options) + return tail.map(function (t) { + return prefix + t + }) + } + + // now we have something like: + // {b,c{d,e},{f,g}h}x{y,z} + // walk through the set, expanding each part, until + // the set ends. then, we'll expand the suffix. + // If the set only has a single member, then'll put the {} back + + // first, handle numeric sets, since they're easier + var numset = pattern.match(/^\{(-?[0-9]+)\.\.(-?[0-9]+)\}/) + if (numset) { + // console.error("numset", numset[1], numset[2]) + var suf = braceExpand(pattern.substr(numset[0].length), options) + , start = +numset[1] + , end = +numset[2] + , inc = start > end ? -1 : 1 + , set = [] + for (var i = start; i != (end + inc); i += inc) { + // append all the suffixes + for (var ii = 0, ll = suf.length; ii < ll; ii ++) { + set.push(i + suf[ii]) + } + } + return set + } + + // ok, walk through the set + // We hope, somewhat optimistically, that there + // will be a } at the end. + // If the closing brace isn't found, then the pattern is + // interpreted as braceExpand("\\" + pattern) so that + // the leading \{ will be interpreted literally. + var i = 1 // skip the \{ + , depth = 1 + , set = [] + , member = "" + , sawEnd = false + , escaping = false + + function addMember () { + set.push(member) + member = "" + } + + // console.error("Entering for") + FOR: for (i = 1, l = pattern.length; i < l; i ++) { + var c = pattern.charAt(i) + // console.error("", i, c) + + if (escaping) { + escaping = false + member += "\\" + c + } else { + switch (c) { + case "\\": + escaping = true + continue + + case "{": + depth ++ + member += "{" + continue + + case "}": + depth -- + // if this closes the actual set, then we're done + if (depth === 0) { + addMember() + // pluck off the close-brace + i ++ + break FOR + } else { + member += c + continue + } + + case ",": + if (depth === 1) { + addMember() + } else { + member += c + } + continue + + default: + member += c + continue + } // switch + } // else + } // for + + // now we've either finished the set, and the suffix is + // pattern.substr(i), or we have *not* closed the set, + // and need to escape the leading brace + if (depth !== 0) { + // console.error("didn't close", pattern) + return braceExpand("\\" + pattern, options) + } + + // x{y,z} -> ["xy", "xz"] + // console.error("set", set) + // console.error("suffix", pattern.substr(i)) + var suf = braceExpand(pattern.substr(i), options) + // ["b", "c{d,e}","{f,g}h"] -> + // [["b"], ["cd", "ce"], ["fh", "gh"]] + var addBraces = set.length === 1 + // console.error("set pre-expanded", set) + set = set.map(function (p) { + return braceExpand(p, options) + }) + // console.error("set expanded", set) + + + // [["b"], ["cd", "ce"], ["fh", "gh"]] -> + // ["b", "cd", "ce", "fh", "gh"] + set = set.reduce(function (l, r) { + return l.concat(r) + }) + + if (addBraces) { + set = set.map(function (s) { + return "{" + s + "}" + }) + } + + // now attach the suffixes. + var ret = [] + for (var i = 0, l = set.length; i < l; i ++) { + for (var ii = 0, ll = suf.length; ii < ll; ii ++) { + ret.push(set[i] + suf[ii]) + } + } + return ret +} + +// parse a component of the expanded set. +// At this point, no pattern may contain "/" in it +// so we're going to return a 2d array, where each entry is the full +// pattern, split on '/', and then turned into a regular expression. +// A regexp is made at the end which joins each array with an +// escaped /, and another full one which joins each regexp with |. +// +// Following the lead of Bash 4.1, note that "**" only has special meaning +// when it is the *only* thing in a path portion. Otherwise, any series +// of * is equivalent to a single *. Globstar behavior is enabled by +// default, and can be disabled by setting options.noglobstar. +Minimatch.prototype.parse = parse +var SUBPARSE = {} +function parse (pattern, isSub) { + var options = this.options + + // shortcuts + if (!options.noglobstar && pattern === "**") return GLOBSTAR + if (pattern === "") return "" + + var re = "" + , hasMagic = !!options.nocase + , escaping = false + // ? => one single character + , patternListStack = [] + , plType + , stateChar + , inClass = false + , reClassStart = -1 + , classStart = -1 + // . and .. never match anything that doesn't start with ., + // even when options.dot is set. + , patternStart = pattern.charAt(0) === "." ? "" // anything + // not (start or / followed by . or .. followed by / or end) + : options.dot ? "(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))" + : "(?!\\.)" + + function clearStateChar () { + if (stateChar) { + // we had some state-tracking character + // that wasn't consumed by this pass. + switch (stateChar) { + case "*": + re += star + hasMagic = true + break + case "?": + re += qmark + hasMagic = true + break + default: + re += "\\"+stateChar + break + } + stateChar = false + } + } + + for ( var i = 0, len = pattern.length, c + ; (i < len) && (c = pattern.charAt(i)) + ; i ++ ) { + + if (options.debug) { + console.error("%s\t%s %s %j", pattern, i, re, c) + } + + // skip over any that are escaped. + if (escaping && reSpecials[c]) { + re += "\\" + c + escaping = false + continue + } + + SWITCH: switch (c) { + case "/": + // completely not allowed, even escaped. + // Should already be path-split by now. + return false + + case "\\": + clearStateChar() + escaping = true + continue + + // the various stateChar values + // for the "extglob" stuff. + case "?": + case "*": + case "+": + case "@": + case "!": + if (options.debug) { + console.error("%s\t%s %s %j <-- stateChar", pattern, i, re, c) + } + + // all of those are literals inside a class, except that + // the glob [!a] means [^a] in regexp + if (inClass) { + if (c === "!" && i === classStart + 1) c = "^" + re += c + continue + } + + // if we already have a stateChar, then it means + // that there was something like ** or +? in there. + // Handle the stateChar, then proceed with this one. + clearStateChar() + stateChar = c + // if extglob is disabled, then +(asdf|foo) isn't a thing. + // just clear the statechar *now*, rather than even diving into + // the patternList stuff. + if (options.noext) clearStateChar() + continue + + case "(": + if (inClass) { + re += "(" + continue + } + + if (!stateChar) { + re += "\\(" + continue + } + + plType = stateChar + patternListStack.push({ type: plType + , start: i - 1 + , reStart: re.length }) + // negation is (?:(?!js)[^/]*) + re += stateChar === "!" ? "(?:(?!" : "(?:" + stateChar = false + continue + + case ")": + if (inClass || !patternListStack.length) { + re += "\\)" + continue + } + + hasMagic = true + re += ")" + plType = patternListStack.pop().type + // negation is (?:(?!js)[^/]*) + // The others are (?:) + switch (plType) { + case "!": + re += "[^/]*?)" + break + case "?": + case "+": + case "*": re += plType + case "@": break // the default anyway + } + continue + + case "|": + if (inClass || !patternListStack.length || escaping) { + re += "\\|" + escaping = false + continue + } + + re += "|" + continue + + // these are mostly the same in regexp and glob + case "[": + // swallow any state-tracking char before the [ + clearStateChar() + + if (inClass) { + re += "\\" + c + continue + } + + inClass = true + classStart = i + reClassStart = re.length + re += c + continue + + case "]": + // a right bracket shall lose its special + // meaning and represent itself in + // a bracket expression if it occurs + // first in the list. -- POSIX.2 2.8.3.2 + if (i === classStart + 1 || !inClass) { + re += "\\" + c + escaping = false + continue + } + + // finish up the class. + hasMagic = true + inClass = false + re += c + continue + + default: + // swallow any state char that wasn't consumed + clearStateChar() + + if (escaping) { + // no need + escaping = false + } else if (reSpecials[c] + && !(c === "^" && inClass)) { + re += "\\" + } + + re += c + + } // switch + } // for + + + // handle the case where we left a class open. + // "[abc" is valid, equivalent to "\[abc" + if (inClass) { + // split where the last [ was, and escape it + // this is a huge pita. We now have to re-walk + // the contents of the would-be class to re-translate + // any characters that were passed through as-is + var cs = pattern.substr(classStart + 1) + , sp = this.parse(cs, SUBPARSE) + re = re.substr(0, reClassStart) + "\\[" + sp[0] + hasMagic = hasMagic || sp[1] + } + + // handle the case where we had a +( thing at the *end* + // of the pattern. + // each pattern list stack adds 3 chars, and we need to go through + // and escape any | chars that were passed through as-is for the regexp. + // Go through and escape them, taking care not to double-escape any + // | chars that were already escaped. + var pl + while (pl = patternListStack.pop()) { + var tail = re.slice(pl.reStart + 3) + // maybe some even number of \, then maybe 1 \, followed by a | + tail = tail.replace(/((?:\\{2})*)(\\?)\|/g, function (_, $1, $2) { + if (!$2) { + // the | isn't already escaped, so escape it. + $2 = "\\" + } + + // need to escape all those slashes *again*, without escaping the + // one that we need for escaping the | character. As it works out, + // escaping an even number of slashes can be done by simply repeating + // it exactly after itself. That's why this trick works. + // + // I am sorry that you have to see this. + return $1 + $1 + $2 + "|" + }) + + // console.error("tail=%j\n %s", tail, tail) + var t = pl.type === "*" ? star + : pl.type === "?" ? qmark + : "\\" + pl.type + + hasMagic = true + re = re.slice(0, pl.reStart) + + t + "\\(" + + tail + } + + // handle trailing things that only matter at the very end. + clearStateChar() + if (escaping) { + // trailing \\ + re += "\\\\" + } + + // only need to apply the nodot start if the re starts with + // something that could conceivably capture a dot + var addPatternStart = false + switch (re.charAt(0)) { + case ".": + case "[": + case "(": addPatternStart = true + } + + // if the re is not "" at this point, then we need to make sure + // it doesn't match against an empty path part. + // Otherwise a/* will match a/, which it should not. + if (re !== "" && hasMagic) re = "(?=.)" + re + + if (addPatternStart) re = patternStart + re + + // parsing just a piece of a larger pattern. + if (isSub === SUBPARSE) { + return [ re, hasMagic ] + } + + // skip the regexp for non-magical patterns + // unescape anything in it, though, so that it'll be + // an exact match against a file etc. + if (!hasMagic) { + return globUnescape(pattern) + } + + var flags = options.nocase ? "i" : "" + , regExp = new RegExp("^" + re + "$", flags) + + regExp._glob = pattern + regExp._src = re + + return regExp +} + +minimatch.makeRe = function (pattern, options) { + return new Minimatch(pattern, options || {}).makeRe() +} + +Minimatch.prototype.makeRe = makeRe +function makeRe () { + if (this.regexp || this.regexp === false) return this.regexp + + // at this point, this.set is a 2d array of partial + // pattern strings, or "**". + // + // It's better to use .match(). This function shouldn't + // be used, really, but it's pretty convenient sometimes, + // when you just want to work with a regex. + var set = this.set + + if (!set.length) return this.regexp = false + var options = this.options + + var twoStar = options.noglobstar ? star + : options.dot ? twoStarDot + : twoStarNoDot + , flags = options.nocase ? "i" : "" + + var re = set.map(function (pattern) { + return pattern.map(function (p) { + return (p === GLOBSTAR) ? twoStar + : (typeof p === "string") ? regExpEscape(p) + : p._src + }).join("\\\/") + }).join("|") + + // must match entire pattern + // ending in a * or ** will make it less strict. + re = "^(?:" + re + ")$" + + // can match anything, as long as it's not this. + if (this.negate) re = "^(?!" + re + ").*$" + + try { + return this.regexp = new RegExp(re, flags) + } catch (ex) { + return this.regexp = false + } +} + +minimatch.match = function (list, pattern, options) { + var mm = new Minimatch(pattern, options) + list = list.filter(function (f) { + return mm.match(f) + }) + if (options.nonull && !list.length) { + list.push(pattern) + } + return list +} + +Minimatch.prototype.match = match +function match (f, partial) { + // console.error("match", f, this.pattern) + // short-circuit in the case of busted things. + // comments, etc. + if (this.comment) return false + if (this.empty) return f === "" + + if (f === "/" && partial) return true + + var options = this.options + + // windows: need to use /, not \ + // On other platforms, \ is a valid (albeit bad) filename char. + if (platform === "win32") { + f = f.split("\\").join("/") + } + + // treat the test path as a set of pathparts. + f = f.split(slashSplit) + if (options.debug) { + console.error(this.pattern, "split", f) + } + + // just ONE of the pattern sets in this.set needs to match + // in order for it to be valid. If negating, then just one + // match means that we have failed. + // Either way, return on the first hit. + + var set = this.set + // console.error(this.pattern, "set", set) + + for (var i = 0, l = set.length; i < l; i ++) { + var pattern = set[i] + var hit = this.matchOne(f, pattern, partial) + if (hit) { + if (options.flipNegate) return true + return !this.negate + } + } + + // didn't get any hits. this is success if it's a negative + // pattern, failure otherwise. + if (options.flipNegate) return false + return this.negate +} + +// set partial to true to test if, for example, +// "/a/b" matches the start of "/*/b/*/d" +// Partial means, if you run out of file before you run +// out of pattern, then that's fine, as long as all +// the parts match. +Minimatch.prototype.matchOne = function (file, pattern, partial) { + var options = this.options + + if (options.debug) { + console.error("matchOne", + { "this": this + , file: file + , pattern: pattern }) + } + + if (options.matchBase && pattern.length === 1) { + file = path.basename(file.join("/")).split("/") + } + + if (options.debug) { + console.error("matchOne", file.length, pattern.length) + } + + for ( var fi = 0 + , pi = 0 + , fl = file.length + , pl = pattern.length + ; (fi < fl) && (pi < pl) + ; fi ++, pi ++ ) { + + if (options.debug) { + console.error("matchOne loop") + } + var p = pattern[pi] + , f = file[fi] + + if (options.debug) { + console.error(pattern, p, f) + } + + // should be impossible. + // some invalid regexp stuff in the set. + if (p === false) return false + + if (p === GLOBSTAR) { + if (options.debug) + console.error('GLOBSTAR', [pattern, p, f]) + + // "**" + // a/**/b/**/c would match the following: + // a/b/x/y/z/c + // a/x/y/z/b/c + // a/b/x/b/x/c + // a/b/c + // To do this, take the rest of the pattern after + // the **, and see if it would match the file remainder. + // If so, return success. + // If not, the ** "swallows" a segment, and try again. + // This is recursively awful. + // + // a/**/b/**/c matching a/b/x/y/z/c + // - a matches a + // - doublestar + // - matchOne(b/x/y/z/c, b/**/c) + // - b matches b + // - doublestar + // - matchOne(x/y/z/c, c) -> no + // - matchOne(y/z/c, c) -> no + // - matchOne(z/c, c) -> no + // - matchOne(c, c) yes, hit + var fr = fi + , pr = pi + 1 + if (pr === pl) { + if (options.debug) + console.error('** at the end') + // a ** at the end will just swallow the rest. + // We have found a match. + // however, it will not swallow /.x, unless + // options.dot is set. + // . and .. are *never* matched by **, for explosively + // exponential reasons. + for ( ; fi < fl; fi ++) { + if (file[fi] === "." || file[fi] === ".." || + (!options.dot && file[fi].charAt(0) === ".")) return false + } + return true + } + + // ok, let's see if we can swallow whatever we can. + WHILE: while (fr < fl) { + var swallowee = file[fr] + + if (options.debug) { + console.error('\nglobstar while', + file, fr, pattern, pr, swallowee) + } + + // XXX remove this slice. Just pass the start index. + if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { + if (options.debug) + console.error('globstar found match!', fr, fl, swallowee) + // found a match. + return true + } else { + // can't swallow "." or ".." ever. + // can only swallow ".foo" when explicitly asked. + if (swallowee === "." || swallowee === ".." || + (!options.dot && swallowee.charAt(0) === ".")) { + if (options.debug) + console.error("dot detected!", file, fr, pattern, pr) + break WHILE + } + + // ** swallows a segment, and continue. + if (options.debug) + console.error('globstar swallow a segment, and continue') + fr ++ + } + } + // no match was found. + // However, in partial mode, we can't say this is necessarily over. + // If there's more *pattern* left, then + if (partial) { + // ran out of file + // console.error("\n>>> no match, partial?", file, fr, pattern, pr) + if (fr === fl) return true + } + return false + } + + // something other than ** + // non-magic patterns just have to match exactly + // patterns with magic have been turned into regexps. + var hit + if (typeof p === "string") { + if (options.nocase) { + hit = f.toLowerCase() === p.toLowerCase() + } else { + hit = f === p + } + if (options.debug) { + console.error("string match", p, f, hit) + } + } else { + hit = f.match(p) + if (options.debug) { + console.error("pattern match", p, f, hit) + } + } + + if (!hit) return false + } + + // Note: ending in / means that we'll get a final "" + // at the end of the pattern. This can only match a + // corresponding "" at the end of the file. + // If the file ends in /, then it can only match a + // a pattern that ends in /, unless the pattern just + // doesn't have any more for it. But, a/b/ should *not* + // match "a/b/*", even though "" matches against the + // [^/]*? pattern, except in partial mode, where it might + // simply not be reached yet. + // However, a/b/ should still satisfy a/* + + // now either we fell off the end of the pattern, or we're done. + if (fi === fl && pi === pl) { + // ran out of pattern and filename at the same time. + // an exact hit! + return true + } else if (fi === fl) { + // ran out of file, but still had pattern left. + // this is ok if we're doing the match as part of + // a glob fs traversal. + return partial + } else if (pi === pl) { + // ran out of pattern, still have file left. + // this is only acceptable if we're on the very last + // empty segment of a file with a trailing slash. + // a/* should match a/b/ + var emptyFileEnd = (fi === fl - 1) && (file[fi] === "") + return emptyFileEnd + } + + // should be unreachable. + throw new Error("wtf?") +} + + +// replace stuff like \* with * +function globUnescape (s) { + return s.replace(/\\(.)/g, "$1") +} + + +function regExpEscape (s) { + return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") +} + +})( typeof require === "function" ? require : null, + this, + typeof module === "object" ? module : null, + typeof process === "object" ? process.platform : "win32" + ) diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/.npmignore b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/.npmignore new file mode 100644 index 0000000..07e6e47 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/.npmignore @@ -0,0 +1 @@ +/node_modules diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/AUTHORS b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/AUTHORS new file mode 100644 index 0000000..016d7fb --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/AUTHORS @@ -0,0 +1,8 @@ +# Authors, sorted by whether or not they are me +Isaac Z. Schlueter +Carlos Brito Lage +Marko Mikulicic +Trent Mick +Kevin O'Hara +Marco Rogers +Jesse Dailey diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/LICENSE b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/LICENSE new file mode 100644 index 0000000..05a4010 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/LICENSE @@ -0,0 +1,23 @@ +Copyright 2009, 2010, 2011 Isaac Z. Schlueter. +All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/README.md b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/README.md new file mode 100644 index 0000000..03ee0f9 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/README.md @@ -0,0 +1,97 @@ +# lru cache + +A cache object that deletes the least-recently-used items. + +## Usage: + +```javascript +var LRU = require("lru-cache") + , options = { max: 500 + , length: function (n) { return n * 2 } + , dispose: function (key, n) { n.close() } + , maxAge: 1000 * 60 * 60 } + , cache = LRU(options) + , otherCache = LRU(50) // sets just the max size + +cache.set("key", "value") +cache.get("key") // "value" + +cache.reset() // empty the cache +``` + +If you put more stuff in it, then items will fall out. + +If you try to put an oversized thing in it, then it'll fall out right +away. + +## Options + +* `max` The maximum size of the cache, checked by applying the length + function to all values in the cache. Not setting this is kind of + silly, since that's the whole purpose of this lib, but it defaults + to `Infinity`. +* `maxAge` Maximum age in ms. Items are not pro-actively pruned out + as they age, but if you try to get an item that is too old, it'll + drop it and return undefined instead of giving it to you. +* `length` Function that is used to calculate the length of stored + items. If you're storing strings or buffers, then you probably want + to do something like `function(n){return n.length}`. The default is + `function(n){return 1}`, which is fine if you want to store `n` + like-sized things. +* `dispose` Function that is called on items when they are dropped + from the cache. This can be handy if you want to close file + descriptors or do other cleanup tasks when items are no longer + accessible. Called with `key, value`. It's called *before* + actually removing the item from the internal cache, so if you want + to immediately put it back in, you'll have to do that in a + `nextTick` or `setTimeout` callback or it won't do anything. +* `stale` By default, if you set a `maxAge`, it'll only actually pull + stale items out of the cache when you `get(key)`. (That is, it's + not pre-emptively doing a `setTimeout` or anything.) If you set + `stale:true`, it'll return the stale value before deleting it. If + you don't set this, then it'll return `undefined` when you try to + get a stale entry, as if it had already been deleted. + +## API + +* `set(key, value)` +* `get(key) => value` + + Both of these will update the "recently used"-ness of the key. + They do what you think. + +* `peek(key)` + + Returns the key value (or `undefined` if not found) without + updating the "recently used"-ness of the key. + + (If you find yourself using this a lot, you *might* be using the + wrong sort of data structure, but there are some use cases where + it's handy.) + +* `del(key)` + + Deletes a key out of the cache. + +* `reset()` + + Clear the cache entirely, throwing away all values. + +* `has(key)` + + Check if a key is in the cache, without updating the recent-ness + or deleting it for being stale. + +* `forEach(function(value,key,cache), [thisp])` + + Just like `Array.prototype.forEach`. Iterates over all the keys + in the cache, in order of recent-ness. (Ie, more recently used + items are iterated over first.) + +* `keys()` + + Return an array of the keys in the cache. + +* `values()` + + Return an array of the values in the cache. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/bench.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/bench.js new file mode 100644 index 0000000..9111540 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/bench.js @@ -0,0 +1,25 @@ +var LRU = require('lru-cache'); + +var max = +process.argv[2] || 10240; +var more = 102400; + +var cache = LRU({ + max: max, maxAge: 86400e3 +}); + +// fill cache +for (var i = 0; i < max; ++i) { + cache.set(i, {}); +} + +var start = process.hrtime(); + +// adding more items +for ( ; i < max+more; ++i) { + cache.set(i, {}); +} + +var end = process.hrtime(start); +var msecs = end[0] * 1E3 + end[1] / 1E6; + +console.log('adding %d items took %d ms', more, msecs.toPrecision(5)); diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js new file mode 100644 index 0000000..49c1dc6 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js @@ -0,0 +1,263 @@ +;(function () { // closure for web browsers + +if (typeof module === 'object' && module.exports) { + module.exports = LRUCache +} else { + // just set the global for non-node platforms. + this.LRUCache = LRUCache +} + +function hOP (obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key) +} + +function naiveLength () { return 1 } + +function LRUCache (options) { + if (!(this instanceof LRUCache)) { + return new LRUCache(options) + } + + var max + if (typeof options === 'number') { + max = options + options = { max: max } + } + + if (!options) options = {} + + max = options.max + + var lengthCalculator = options.length || naiveLength + + if (typeof lengthCalculator !== "function") { + lengthCalculator = naiveLength + } + + if (!max || !(typeof max === "number") || max <= 0 ) { + // a little bit silly. maybe this should throw? + max = Infinity + } + + var allowStale = options.stale || false + + var maxAge = options.maxAge || null + + var dispose = options.dispose + + var cache = Object.create(null) // hash of items by key + , lruList = Object.create(null) // list of items in order of use recency + , mru = 0 // most recently used + , lru = 0 // least recently used + , length = 0 // number of items in the list + , itemCount = 0 + + + // resize the cache when the max changes. + Object.defineProperty(this, "max", + { set : function (mL) { + if (!mL || !(typeof mL === "number") || mL <= 0 ) mL = Infinity + max = mL + // if it gets above double max, trim right away. + // otherwise, do it whenever it's convenient. + if (length > max) trim() + } + , get : function () { return max } + , enumerable : true + }) + + // resize the cache when the lengthCalculator changes. + Object.defineProperty(this, "lengthCalculator", + { set : function (lC) { + if (typeof lC !== "function") { + lengthCalculator = naiveLength + length = itemCount + for (var key in cache) { + cache[key].length = 1 + } + } else { + lengthCalculator = lC + length = 0 + for (var key in cache) { + cache[key].length = lengthCalculator(cache[key].value) + length += cache[key].length + } + } + + if (length > max) trim() + } + , get : function () { return lengthCalculator } + , enumerable : true + }) + + Object.defineProperty(this, "length", + { get : function () { return length } + , enumerable : true + }) + + + Object.defineProperty(this, "itemCount", + { get : function () { return itemCount } + , enumerable : true + }) + + this.forEach = function (fn, thisp) { + thisp = thisp || this + var i = 0; + for (var k = mru - 1; k >= 0 && i < itemCount; k--) if (lruList[k]) { + i++ + var hit = lruList[k] + if (maxAge && (Date.now() - hit.now > maxAge)) { + del(hit) + if (!allowStale) hit = undefined + } + if (hit) { + fn.call(thisp, hit.value, hit.key, this) + } + } + } + + this.keys = function () { + var keys = new Array(itemCount) + var i = 0 + for (var k = mru - 1; k >= 0 && i < itemCount; k--) if (lruList[k]) { + var hit = lruList[k] + keys[i++] = hit.key + } + return keys + } + + this.values = function () { + var values = new Array(itemCount) + var i = 0 + for (var k = mru - 1; k >= 0 && i < itemCount; k--) if (lruList[k]) { + var hit = lruList[k] + values[i++] = hit.value + } + return values + } + + this.reset = function () { + if (dispose) { + for (var k in cache) { + dispose(k, cache[k].value) + } + } + cache = {} + lruList = {} + lru = 0 + mru = 0 + length = 0 + itemCount = 0 + } + + // Provided for debugging/dev purposes only. No promises whatsoever that + // this API stays stable. + this.dump = function () { + return cache + } + + this.dumpLru = function () { + return lruList + } + + this.set = function (key, value) { + if (hOP(cache, key)) { + // dispose of the old one before overwriting + if (dispose) dispose(key, cache[key].value) + if (maxAge) cache[key].now = Date.now() + cache[key].value = value + this.get(key) + return true + } + + var len = lengthCalculator(value) + var age = maxAge ? Date.now() : 0 + var hit = new Entry(key, value, mru++, len, age) + + // oversized objects fall out of cache automatically. + if (hit.length > max) { + if (dispose) dispose(key, value) + return false + } + + length += hit.length + lruList[hit.lu] = cache[key] = hit + itemCount ++ + + if (length > max) trim() + return true + } + + this.has = function (key) { + if (!hOP(cache, key)) return false + var hit = cache[key] + if (maxAge && (Date.now() - hit.now > maxAge)) { + return false + } + return true + } + + this.get = function (key) { + return get(key, true) + } + + this.peek = function (key) { + return get(key, false) + } + + function get (key, doUse) { + var hit = cache[key] + if (hit) { + if (maxAge && (Date.now() - hit.now > maxAge)) { + del(hit) + if (!allowStale) hit = undefined + } else { + if (doUse) use(hit) + } + if (hit) hit = hit.value + } + return hit + } + + function use (hit) { + shiftLU(hit) + hit.lu = mru ++ + lruList[hit.lu] = hit + } + + this.del = function (key) { + del(cache[key]) + } + + function trim () { + while (lru < mru && length > max) + del(lruList[lru]) + } + + function shiftLU(hit) { + delete lruList[ hit.lu ] + while (lru < mru && !lruList[lru]) lru ++ + } + + function del(hit) { + if (hit) { + if (dispose) dispose(hit.key, hit.value) + length -= hit.length + itemCount -- + delete cache[ hit.key ] + shiftLU(hit) + } + } +} + +// classy, since V8 prefers predictable objects. +function Entry (key, value, mru, len, age) { + this.key = key + this.value = value + this.lu = mru + this.length = len + this.now = age +} + +})() diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/package.json new file mode 100644 index 0000000..bc688d2 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/package.json @@ -0,0 +1,66 @@ +{ + "name": "lru-cache", + "description": "A cache object that deletes the least-recently-used items.", + "version": "2.3.1", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + "scripts": { + "test": "tap test --gc" + }, + "main": "lib/lru-cache.js", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/node-lru-cache.git" + }, + "devDependencies": { + "tap": "", + "weak": "" + }, + "license": { + "type": "MIT", + "url": "http://github.com/isaacs/node-lru-cache/raw/master/LICENSE" + }, + "contributors": [ + { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + { + "name": "Carlos Brito Lage", + "email": "carlos@carloslage.net" + }, + { + "name": "Marko Mikulicic", + "email": "marko.mikulicic@isti.cnr.it" + }, + { + "name": "Trent Mick", + "email": "trentm@gmail.com" + }, + { + "name": "Kevin O'Hara", + "email": "kevinohara80@gmail.com" + }, + { + "name": "Marco Rogers", + "email": "marco.rogers@gmail.com" + }, + { + "name": "Jesse Dailey", + "email": "jesse.dailey@gmail.com" + } + ], + "readme": "# lru cache\n\nA cache object that deletes the least-recently-used items.\n\n## Usage:\n\n```javascript\nvar LRU = require(\"lru-cache\")\n , options = { max: 500\n , length: function (n) { return n * 2 }\n , dispose: function (key, n) { n.close() }\n , maxAge: 1000 * 60 * 60 }\n , cache = LRU(options)\n , otherCache = LRU(50) // sets just the max size\n\ncache.set(\"key\", \"value\")\ncache.get(\"key\") // \"value\"\n\ncache.reset() // empty the cache\n```\n\nIf you put more stuff in it, then items will fall out.\n\nIf you try to put an oversized thing in it, then it'll fall out right\naway.\n\n## Options\n\n* `max` The maximum size of the cache, checked by applying the length\n function to all values in the cache. Not setting this is kind of\n silly, since that's the whole purpose of this lib, but it defaults\n to `Infinity`.\n* `maxAge` Maximum age in ms. Items are not pro-actively pruned out\n as they age, but if you try to get an item that is too old, it'll\n drop it and return undefined instead of giving it to you.\n* `length` Function that is used to calculate the length of stored\n items. If you're storing strings or buffers, then you probably want\n to do something like `function(n){return n.length}`. The default is\n `function(n){return 1}`, which is fine if you want to store `n`\n like-sized things.\n* `dispose` Function that is called on items when they are dropped\n from the cache. This can be handy if you want to close file\n descriptors or do other cleanup tasks when items are no longer\n accessible. Called with `key, value`. It's called *before*\n actually removing the item from the internal cache, so if you want\n to immediately put it back in, you'll have to do that in a\n `nextTick` or `setTimeout` callback or it won't do anything.\n* `stale` By default, if you set a `maxAge`, it'll only actually pull\n stale items out of the cache when you `get(key)`. (That is, it's\n not pre-emptively doing a `setTimeout` or anything.) If you set\n `stale:true`, it'll return the stale value before deleting it. If\n you don't set this, then it'll return `undefined` when you try to\n get a stale entry, as if it had already been deleted.\n\n## API\n\n* `set(key, value)`\n* `get(key) => value`\n\n Both of these will update the \"recently used\"-ness of the key.\n They do what you think.\n\n* `peek(key)`\n\n Returns the key value (or `undefined` if not found) without\n updating the \"recently used\"-ness of the key.\n\n (If you find yourself using this a lot, you *might* be using the\n wrong sort of data structure, but there are some use cases where\n it's handy.)\n\n* `del(key)`\n\n Deletes a key out of the cache.\n\n* `reset()`\n\n Clear the cache entirely, throwing away all values.\n\n* `has(key)`\n\n Check if a key is in the cache, without updating the recent-ness\n or deleting it for being stale.\n\n* `forEach(function(value,key,cache), [thisp])`\n\n Just like `Array.prototype.forEach`. Iterates over all the keys\n in the cache, in order of recent-ness. (Ie, more recently used\n items are iterated over first.)\n\n* `keys()`\n\n Return an array of the keys in the cache.\n\n* `values()`\n\n Return an array of the values in the cache.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/node-lru-cache/issues" + }, + "_id": "lru-cache@2.3.1", + "dist": { + "shasum": "dc1baa0c583de3769cefe2af865b43b41b151b44" + }, + "_from": "lru-cache@2", + "_resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.3.1.tgz" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/test/basic.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/test/basic.js new file mode 100644 index 0000000..70f3f8b --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/test/basic.js @@ -0,0 +1,329 @@ +var test = require("tap").test + , LRU = require("../") + +test("basic", function (t) { + var cache = new LRU({max: 10}) + cache.set("key", "value") + t.equal(cache.get("key"), "value") + t.equal(cache.get("nada"), undefined) + t.equal(cache.length, 1) + t.equal(cache.max, 10) + t.end() +}) + +test("least recently set", function (t) { + var cache = new LRU(2) + cache.set("a", "A") + cache.set("b", "B") + cache.set("c", "C") + t.equal(cache.get("c"), "C") + t.equal(cache.get("b"), "B") + t.equal(cache.get("a"), undefined) + t.end() +}) + +test("lru recently gotten", function (t) { + var cache = new LRU(2) + cache.set("a", "A") + cache.set("b", "B") + cache.get("a") + cache.set("c", "C") + t.equal(cache.get("c"), "C") + t.equal(cache.get("b"), undefined) + t.equal(cache.get("a"), "A") + t.end() +}) + +test("del", function (t) { + var cache = new LRU(2) + cache.set("a", "A") + cache.del("a") + t.equal(cache.get("a"), undefined) + t.end() +}) + +test("max", function (t) { + var cache = new LRU(3) + + // test changing the max, verify that the LRU items get dropped. + cache.max = 100 + for (var i = 0; i < 100; i ++) cache.set(i, i) + t.equal(cache.length, 100) + for (var i = 0; i < 100; i ++) { + t.equal(cache.get(i), i) + } + cache.max = 3 + t.equal(cache.length, 3) + for (var i = 0; i < 97; i ++) { + t.equal(cache.get(i), undefined) + } + for (var i = 98; i < 100; i ++) { + t.equal(cache.get(i), i) + } + + // now remove the max restriction, and try again. + cache.max = "hello" + for (var i = 0; i < 100; i ++) cache.set(i, i) + t.equal(cache.length, 100) + for (var i = 0; i < 100; i ++) { + t.equal(cache.get(i), i) + } + // should trigger an immediate resize + cache.max = 3 + t.equal(cache.length, 3) + for (var i = 0; i < 97; i ++) { + t.equal(cache.get(i), undefined) + } + for (var i = 98; i < 100; i ++) { + t.equal(cache.get(i), i) + } + t.end() +}) + +test("reset", function (t) { + var cache = new LRU(10) + cache.set("a", "A") + cache.set("b", "B") + cache.reset() + t.equal(cache.length, 0) + t.equal(cache.max, 10) + t.equal(cache.get("a"), undefined) + t.equal(cache.get("b"), undefined) + t.end() +}) + + +// Note: `.dump()` is a debugging tool only. No guarantees are made +// about the format/layout of the response. +test("dump", function (t) { + var cache = new LRU(10) + var d = cache.dump(); + t.equal(Object.keys(d).length, 0, "nothing in dump for empty cache") + cache.set("a", "A") + var d = cache.dump() // { a: { key: "a", value: "A", lu: 0 } } + t.ok(d.a) + t.equal(d.a.key, "a") + t.equal(d.a.value, "A") + t.equal(d.a.lu, 0) + + cache.set("b", "B") + cache.get("b") + d = cache.dump() + t.ok(d.b) + t.equal(d.b.key, "b") + t.equal(d.b.value, "B") + t.equal(d.b.lu, 2) + + t.end() +}) + + +test("basic with weighed length", function (t) { + var cache = new LRU({ + max: 100, + length: function (item) { return item.size } + }) + cache.set("key", {val: "value", size: 50}) + t.equal(cache.get("key").val, "value") + t.equal(cache.get("nada"), undefined) + t.equal(cache.lengthCalculator(cache.get("key")), 50) + t.equal(cache.length, 50) + t.equal(cache.max, 100) + t.end() +}) + + +test("weighed length item too large", function (t) { + var cache = new LRU({ + max: 10, + length: function (item) { return item.size } + }) + t.equal(cache.max, 10) + + // should fall out immediately + cache.set("key", {val: "value", size: 50}) + + t.equal(cache.length, 0) + t.equal(cache.get("key"), undefined) + t.end() +}) + +test("least recently set with weighed length", function (t) { + var cache = new LRU({ + max:8, + length: function (item) { return item.length } + }) + cache.set("a", "A") + cache.set("b", "BB") + cache.set("c", "CCC") + cache.set("d", "DDDD") + t.equal(cache.get("d"), "DDDD") + t.equal(cache.get("c"), "CCC") + t.equal(cache.get("b"), undefined) + t.equal(cache.get("a"), undefined) + t.end() +}) + +test("lru recently gotten with weighed length", function (t) { + var cache = new LRU({ + max: 8, + length: function (item) { return item.length } + }) + cache.set("a", "A") + cache.set("b", "BB") + cache.set("c", "CCC") + cache.get("a") + cache.get("b") + cache.set("d", "DDDD") + t.equal(cache.get("c"), undefined) + t.equal(cache.get("d"), "DDDD") + t.equal(cache.get("b"), "BB") + t.equal(cache.get("a"), "A") + t.end() +}) + +test("set returns proper booleans", function(t) { + var cache = new LRU({ + max: 5, + length: function (item) { return item.length } + }) + + t.equal(cache.set("a", "A"), true) + + // should return false for max exceeded + t.equal(cache.set("b", "donuts"), false) + + t.equal(cache.set("b", "B"), true) + t.equal(cache.set("c", "CCCC"), true) + t.end() +}) + +test("drop the old items", function(t) { + var cache = new LRU({ + max: 5, + maxAge: 50 + }) + + cache.set("a", "A") + + setTimeout(function () { + cache.set("b", "b") + t.equal(cache.get("a"), "A") + }, 25) + + setTimeout(function () { + cache.set("c", "C") + // timed out + t.notOk(cache.get("a")) + }, 60) + + setTimeout(function () { + t.notOk(cache.get("b")) + t.equal(cache.get("c"), "C") + }, 90) + + setTimeout(function () { + t.notOk(cache.get("c")) + t.end() + }, 155) +}) + +test("disposal function", function(t) { + var disposed = false + var cache = new LRU({ + max: 1, + dispose: function (k, n) { + disposed = n + } + }) + + cache.set(1, 1) + cache.set(2, 2) + t.equal(disposed, 1) + cache.set(3, 3) + t.equal(disposed, 2) + cache.reset() + t.equal(disposed, 3) + t.end() +}) + +test("disposal function on too big of item", function(t) { + var disposed = false + var cache = new LRU({ + max: 1, + length: function (k) { + return k.length + }, + dispose: function (k, n) { + disposed = n + } + }) + var obj = [ 1, 2 ] + + t.equal(disposed, false) + cache.set("obj", obj) + t.equal(disposed, obj) + t.end() +}) + +test("has()", function(t) { + var cache = new LRU({ + max: 1, + maxAge: 10 + }) + + cache.set('foo', 'bar') + t.equal(cache.has('foo'), true) + cache.set('blu', 'baz') + t.equal(cache.has('foo'), false) + t.equal(cache.has('blu'), true) + setTimeout(function() { + t.equal(cache.has('blu'), false) + t.end() + }, 15) +}) + +test("stale", function(t) { + var cache = new LRU({ + maxAge: 10, + stale: true + }) + + cache.set('foo', 'bar') + t.equal(cache.get('foo'), 'bar') + t.equal(cache.has('foo'), true) + setTimeout(function() { + t.equal(cache.has('foo'), false) + t.equal(cache.get('foo'), 'bar') + t.equal(cache.get('foo'), undefined) + t.end() + }, 15) +}) + +test("lru update via set", function(t) { + var cache = LRU({ max: 2 }); + + cache.set('foo', 1); + cache.set('bar', 2); + cache.del('bar'); + cache.set('baz', 3); + cache.set('qux', 4); + + t.equal(cache.get('foo'), undefined) + t.equal(cache.get('bar'), undefined) + t.equal(cache.get('baz'), 3) + t.equal(cache.get('qux'), 4) + t.end() +}) + +test("least recently set w/ peek", function (t) { + var cache = new LRU(2) + cache.set("a", "A") + cache.set("b", "B") + t.equal(cache.peek("a"), "A") + cache.set("c", "C") + t.equal(cache.get("c"), "C") + t.equal(cache.get("b"), "B") + t.equal(cache.get("a"), undefined) + t.end() +}) diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/test/foreach.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/test/foreach.js new file mode 100644 index 0000000..eefb80d --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/test/foreach.js @@ -0,0 +1,52 @@ +var test = require('tap').test +var LRU = require('../') + +test('forEach', function (t) { + var l = new LRU(5) + for (var i = 0; i < 10; i ++) { + l.set(i.toString(), i.toString(2)) + } + + var i = 9 + l.forEach(function (val, key, cache) { + t.equal(cache, l) + t.equal(key, i.toString()) + t.equal(val, i.toString(2)) + i -= 1 + }) + + // get in order of most recently used + l.get(6) + l.get(8) + + var order = [ 8, 6, 9, 7, 5 ] + var i = 0 + + l.forEach(function (val, key, cache) { + var j = order[i ++] + t.equal(cache, l) + t.equal(key, j.toString()) + t.equal(val, j.toString(2)) + }) + + t.end() +}) + +test('keys() and values()', function (t) { + var l = new LRU(5) + for (var i = 0; i < 10; i ++) { + l.set(i.toString(), i.toString(2)) + } + + t.similar(l.keys(), ['9', '8', '7', '6', '5']) + t.similar(l.values(), ['1001', '1000', '111', '110', '101']) + + // get in order of most recently used + l.get(6) + l.get(8) + + t.similar(l.keys(), ['8', '6', '9', '7', '5']) + t.similar(l.values(), ['1000', '110', '1001', '111', '101']) + + t.end() +}) diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/test/memory-leak.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/test/memory-leak.js new file mode 100644 index 0000000..7af45b0 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/lru-cache/test/memory-leak.js @@ -0,0 +1,50 @@ +#!/usr/bin/env node --expose_gc + +var weak = require('weak'); +var test = require('tap').test +var LRU = require('../') +var l = new LRU({ max: 10 }) +var refs = 0 +function X() { + refs ++ + weak(this, deref) +} + +function deref() { + refs -- +} + +test('no leaks', function (t) { + // fill up the cache + for (var i = 0; i < 100; i++) { + l.set(i, new X); + // throw some gets in there, too. + if (i % 2 === 0) + l.get(i / 2) + } + + gc() + + var start = process.memoryUsage() + + // capture the memory + var startRefs = refs + + // do it again, but more + for (var i = 0; i < 10000; i++) { + l.set(i, new X); + // throw some gets in there, too. + if (i % 2 === 0) + l.get(i / 2) + } + + gc() + + var end = process.memoryUsage() + t.equal(refs, startRefs, 'no leaky refs') + + console.error('start: %j\n' + + 'end: %j', start, end); + t.pass(); + t.end(); +}) diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/LICENSE b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/LICENSE new file mode 100644 index 0000000..0c44ae7 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) Isaac Z. Schlueter ("Author") +All rights reserved. + +The BSD License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/README.md b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/README.md new file mode 100644 index 0000000..7e36512 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/README.md @@ -0,0 +1,53 @@ +# sigmund + +Quick and dirty signatures for Objects. + +This is like a much faster `deepEquals` comparison, which returns a +string key suitable for caches and the like. + +## Usage + +```javascript +function doSomething (someObj) { + var key = sigmund(someObj, maxDepth) // max depth defaults to 10 + var cached = cache.get(key) + if (cached) return cached) + + var result = expensiveCalculation(someObj) + cache.set(key, result) + return result +} +``` + +The resulting key will be as unique and reproducible as calling +`JSON.stringify` or `util.inspect` on the object, but is much faster. +In order to achieve this speed, some differences are glossed over. +For example, the object `{0:'foo'}` will be treated identically to the +array `['foo']`. + +Also, just as there is no way to summon the soul from the scribblings +of a cocain-addled psychoanalyst, there is no way to revive the object +from the signature string that sigmund gives you. In fact, it's +barely even readable. + +As with `sys.inspect` and `JSON.stringify`, larger objects will +produce larger signature strings. + +Because sigmund is a bit less strict than the more thorough +alternatives, the strings will be shorter, and also there is a +slightly higher chance for collisions. For example, these objects +have the same signature: + + var obj1 = {a:'b',c:/def/,g:['h','i',{j:'',k:'l'}]} + var obj2 = {a:'b',c:'/def/',g:['h','i','{jkl']} + +Like a good Freudian, sigmund is most effective when you already have +some understanding of what you're looking for. It can help you help +yourself, but you must be willing to do some work as well. + +Cycles are handled, and cyclical objects are silently omitted (though +the key is included in the signature output.) + +The second argument is the maximum depth, which defaults to 10, +because that is the maximum object traversal depth covered by most +insurance carriers. diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/bench.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/bench.js new file mode 100644 index 0000000..5acfd6d --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/bench.js @@ -0,0 +1,283 @@ +// different ways to id objects +// use a req/res pair, since it's crazy deep and cyclical + +// sparseFE10 and sigmund are usually pretty close, which is to be expected, +// since they are essentially the same algorithm, except that sigmund handles +// regular expression objects properly. + + +var http = require('http') +var util = require('util') +var sigmund = require('./sigmund.js') +var sreq, sres, creq, cres, test + +http.createServer(function (q, s) { + sreq = q + sres = s + sres.end('ok') + this.close(function () { setTimeout(function () { + start() + }, 200) }) +}).listen(1337, function () { + creq = http.get({ port: 1337 }) + creq.on('response', function (s) { cres = s }) +}) + +function start () { + test = [sreq, sres, creq, cres] + // test = sreq + // sreq.sres = sres + // sreq.creq = creq + // sreq.cres = cres + + for (var i in exports.compare) { + console.log(i) + var hash = exports.compare[i]() + console.log(hash) + console.log(hash.length) + console.log('') + } + + require('bench').runMain() +} + +function customWs (obj, md, d) { + d = d || 0 + var to = typeof obj + if (to === 'undefined' || to === 'function' || to === null) return '' + if (d > md || !obj || to !== 'object') return ('' + obj).replace(/[\n ]+/g, '') + + if (Array.isArray(obj)) { + return obj.map(function (i, _, __) { + return customWs(i, md, d + 1) + }).reduce(function (a, b) { return a + b }, '') + } + + var keys = Object.keys(obj) + return keys.map(function (k, _, __) { + return k + ':' + customWs(obj[k], md, d + 1) + }).reduce(function (a, b) { return a + b }, '') +} + +function custom (obj, md, d) { + d = d || 0 + var to = typeof obj + if (to === 'undefined' || to === 'function' || to === null) return '' + if (d > md || !obj || to !== 'object') return '' + obj + + if (Array.isArray(obj)) { + return obj.map(function (i, _, __) { + return custom(i, md, d + 1) + }).reduce(function (a, b) { return a + b }, '') + } + + var keys = Object.keys(obj) + return keys.map(function (k, _, __) { + return k + ':' + custom(obj[k], md, d + 1) + }).reduce(function (a, b) { return a + b }, '') +} + +function sparseFE2 (obj, maxDepth) { + var seen = [] + var soFar = '' + function ch (v, depth) { + if (depth > maxDepth) return + if (typeof v === 'function' || typeof v === 'undefined') return + if (typeof v !== 'object' || !v) { + soFar += v + return + } + if (seen.indexOf(v) !== -1 || depth === maxDepth) return + seen.push(v) + soFar += '{' + Object.keys(v).forEach(function (k, _, __) { + // pseudo-private values. skip those. + if (k.charAt(0) === '_') return + var to = typeof v[k] + if (to === 'function' || to === 'undefined') return + soFar += k + ':' + ch(v[k], depth + 1) + }) + soFar += '}' + } + ch(obj, 0) + return soFar +} + +function sparseFE (obj, maxDepth) { + var seen = [] + var soFar = '' + function ch (v, depth) { + if (depth > maxDepth) return + if (typeof v === 'function' || typeof v === 'undefined') return + if (typeof v !== 'object' || !v) { + soFar += v + return + } + if (seen.indexOf(v) !== -1 || depth === maxDepth) return + seen.push(v) + soFar += '{' + Object.keys(v).forEach(function (k, _, __) { + // pseudo-private values. skip those. + if (k.charAt(0) === '_') return + var to = typeof v[k] + if (to === 'function' || to === 'undefined') return + soFar += k + ch(v[k], depth + 1) + }) + } + ch(obj, 0) + return soFar +} + +function sparse (obj, maxDepth) { + var seen = [] + var soFar = '' + function ch (v, depth) { + if (depth > maxDepth) return + if (typeof v === 'function' || typeof v === 'undefined') return + if (typeof v !== 'object' || !v) { + soFar += v + return + } + if (seen.indexOf(v) !== -1 || depth === maxDepth) return + seen.push(v) + soFar += '{' + for (var k in v) { + // pseudo-private values. skip those. + if (k.charAt(0) === '_') continue + var to = typeof v[k] + if (to === 'function' || to === 'undefined') continue + soFar += k + ch(v[k], depth + 1) + } + } + ch(obj, 0) + return soFar +} + +function noCommas (obj, maxDepth) { + var seen = [] + var soFar = '' + function ch (v, depth) { + if (depth > maxDepth) return + if (typeof v === 'function' || typeof v === 'undefined') return + if (typeof v !== 'object' || !v) { + soFar += v + return + } + if (seen.indexOf(v) !== -1 || depth === maxDepth) return + seen.push(v) + soFar += '{' + for (var k in v) { + // pseudo-private values. skip those. + if (k.charAt(0) === '_') continue + var to = typeof v[k] + if (to === 'function' || to === 'undefined') continue + soFar += k + ':' + ch(v[k], depth + 1) + } + soFar += '}' + } + ch(obj, 0) + return soFar +} + + +function flatten (obj, maxDepth) { + var seen = [] + var soFar = '' + function ch (v, depth) { + if (depth > maxDepth) return + if (typeof v === 'function' || typeof v === 'undefined') return + if (typeof v !== 'object' || !v) { + soFar += v + return + } + if (seen.indexOf(v) !== -1 || depth === maxDepth) return + seen.push(v) + soFar += '{' + for (var k in v) { + // pseudo-private values. skip those. + if (k.charAt(0) === '_') continue + var to = typeof v[k] + if (to === 'function' || to === 'undefined') continue + soFar += k + ':' + ch(v[k], depth + 1) + soFar += ',' + } + soFar += '}' + } + ch(obj, 0) + return soFar +} + +exports.compare = +{ + // 'custom 2': function () { + // return custom(test, 2, 0) + // }, + // 'customWs 2': function () { + // return customWs(test, 2, 0) + // }, + 'JSON.stringify (guarded)': function () { + var seen = [] + return JSON.stringify(test, function (k, v) { + if (typeof v !== 'object' || !v) return v + if (seen.indexOf(v) !== -1) return undefined + seen.push(v) + return v + }) + }, + + 'flatten 10': function () { + return flatten(test, 10) + }, + + // 'flattenFE 10': function () { + // return flattenFE(test, 10) + // }, + + 'noCommas 10': function () { + return noCommas(test, 10) + }, + + 'sparse 10': function () { + return sparse(test, 10) + }, + + 'sparseFE 10': function () { + return sparseFE(test, 10) + }, + + 'sparseFE2 10': function () { + return sparseFE2(test, 10) + }, + + sigmund: function() { + return sigmund(test, 10) + }, + + + // 'util.inspect 1': function () { + // return util.inspect(test, false, 1, false) + // }, + // 'util.inspect undefined': function () { + // util.inspect(test) + // }, + // 'util.inspect 2': function () { + // util.inspect(test, false, 2, false) + // }, + // 'util.inspect 3': function () { + // util.inspect(test, false, 3, false) + // }, + // 'util.inspect 4': function () { + // util.inspect(test, false, 4, false) + // }, + // 'util.inspect Infinity': function () { + // util.inspect(test, false, Infinity, false) + // } +} + +/** results +**/ diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/package.json new file mode 100644 index 0000000..f43e206 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/package.json @@ -0,0 +1,45 @@ +{ + "name": "sigmund", + "version": "1.0.0", + "description": "Quick and dirty signatures for Objects.", + "main": "sigmund.js", + "directories": { + "test": "test" + }, + "dependencies": {}, + "devDependencies": { + "tap": "~0.3.0" + }, + "scripts": { + "test": "tap test/*.js", + "bench": "node bench.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/isaacs/sigmund" + }, + "keywords": [ + "object", + "signature", + "key", + "data", + "psychoanalysis" + ], + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me/" + }, + "license": "BSD", + "readme": "# sigmund\n\nQuick and dirty signatures for Objects.\n\nThis is like a much faster `deepEquals` comparison, which returns a\nstring key suitable for caches and the like.\n\n## Usage\n\n```javascript\nfunction doSomething (someObj) {\n var key = sigmund(someObj, maxDepth) // max depth defaults to 10\n var cached = cache.get(key)\n if (cached) return cached)\n\n var result = expensiveCalculation(someObj)\n cache.set(key, result)\n return result\n}\n```\n\nThe resulting key will be as unique and reproducible as calling\n`JSON.stringify` or `util.inspect` on the object, but is much faster.\nIn order to achieve this speed, some differences are glossed over.\nFor example, the object `{0:'foo'}` will be treated identically to the\narray `['foo']`.\n\nAlso, just as there is no way to summon the soul from the scribblings\nof a cocain-addled psychoanalyst, there is no way to revive the object\nfrom the signature string that sigmund gives you. In fact, it's\nbarely even readable.\n\nAs with `sys.inspect` and `JSON.stringify`, larger objects will\nproduce larger signature strings.\n\nBecause sigmund is a bit less strict than the more thorough\nalternatives, the strings will be shorter, and also there is a\nslightly higher chance for collisions. For example, these objects\nhave the same signature:\n\n var obj1 = {a:'b',c:/def/,g:['h','i',{j:'',k:'l'}]}\n var obj2 = {a:'b',c:'/def/',g:['h','i','{jkl']}\n\nLike a good Freudian, sigmund is most effective when you already have\nsome understanding of what you're looking for. It can help you help\nyourself, but you must be willing to do some work as well.\n\nCycles are handled, and cyclical objects are silently omitted (though\nthe key is included in the signature output.)\n\nThe second argument is the maximum depth, which defaults to 10,\nbecause that is the maximum object traversal depth covered by most\ninsurance carriers.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/sigmund/issues" + }, + "_id": "sigmund@1.0.0", + "dist": { + "shasum": "8b342a413c9a7c2c3b82a0f2ea4c56343bc4cb13" + }, + "_from": "sigmund@~1.0.0", + "_resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.0.tgz" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/sigmund.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/sigmund.js new file mode 100644 index 0000000..82c7ab8 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/sigmund.js @@ -0,0 +1,39 @@ +module.exports = sigmund +function sigmund (subject, maxSessions) { + maxSessions = maxSessions || 10; + var notes = []; + var analysis = ''; + var RE = RegExp; + + function psychoAnalyze (subject, session) { + if (session > maxSessions) return; + + if (typeof subject === 'function' || + typeof subject === 'undefined') { + return; + } + + if (typeof subject !== 'object' || !subject || + (subject instanceof RE)) { + analysis += subject; + return; + } + + if (notes.indexOf(subject) !== -1 || session === maxSessions) return; + + notes.push(subject); + analysis += '{'; + Object.keys(subject).forEach(function (issue, _, __) { + // pseudo-private values. skip those. + if (issue.charAt(0) === '_') return; + var to = typeof subject[issue]; + if (to === 'function' || to === 'undefined') return; + analysis += issue; + psychoAnalyze(subject[issue], session + 1); + }); + } + psychoAnalyze(subject, 0); + return analysis; +} + +// vim: set softtabstop=4 shiftwidth=4: diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/test/basic.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/test/basic.js new file mode 100644 index 0000000..50c53a1 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/node_modules/sigmund/test/basic.js @@ -0,0 +1,24 @@ +var test = require('tap').test +var sigmund = require('../sigmund.js') + + +// occasionally there are duplicates +// that's an acceptable edge-case. JSON.stringify and util.inspect +// have some collision potential as well, though less, and collision +// detection is expensive. +var hash = '{abc/def/g{0h1i2{jkl' +var obj1 = {a:'b',c:/def/,g:['h','i',{j:'',k:'l'}]} +var obj2 = {a:'b',c:'/def/',g:['h','i','{jkl']} + +var obj3 = JSON.parse(JSON.stringify(obj1)) +obj3.c = /def/ +obj3.g[2].cycle = obj3 +var cycleHash = '{abc/def/g{0h1i2{jklcycle' + +test('basic', function (t) { + t.equal(sigmund(obj1), hash) + t.equal(sigmund(obj2), hash) + t.equal(sigmund(obj3), cycleHash) + t.end() +}) + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/package.json new file mode 100644 index 0000000..e14f73c --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/package.json @@ -0,0 +1,43 @@ +{ + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me" + }, + "name": "minimatch", + "description": "a glob matcher in javascript", + "version": "0.2.12", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/minimatch.git" + }, + "main": "minimatch.js", + "scripts": { + "test": "tap test" + }, + "engines": { + "node": "*" + }, + "dependencies": { + "lru-cache": "2", + "sigmund": "~1.0.0" + }, + "devDependencies": { + "tap": "" + }, + "license": { + "type": "MIT", + "url": "http://github.com/isaacs/minimatch/raw/master/LICENSE" + }, + "readme": "# minimatch\n\nA minimal matching utility.\n\n[![Build Status](https://secure.travis-ci.org/isaacs/minimatch.png)](http://travis-ci.org/isaacs/minimatch)\n\n\nThis is the matching library used internally by npm.\n\nEventually, it will replace the C binding in node-glob.\n\nIt works by converting glob expressions into JavaScript `RegExp`\nobjects.\n\n## Usage\n\n```javascript\nvar minimatch = require(\"minimatch\")\n\nminimatch(\"bar.foo\", \"*.foo\") // true!\nminimatch(\"bar.foo\", \"*.bar\") // false!\n```\n\n## Features\n\nSupports these glob features:\n\n* Brace Expansion\n* Extended glob matching\n* \"Globstar\" `**` matching\n\nSee:\n\n* `man sh`\n* `man bash`\n* `man 3 fnmatch`\n* `man 5 gitignore`\n\n### Comparisons to other fnmatch/glob implementations\n\nWhile strict compliance with the existing standards is a worthwhile\ngoal, some discrepancies exist between minimatch and other\nimplementations, and are intentional.\n\nIf the pattern starts with a `!` character, then it is negated. Set the\n`nonegate` flag to suppress this behavior, and treat leading `!`\ncharacters normally. This is perhaps relevant if you wish to start the\npattern with a negative extglob pattern like `!(a|B)`. Multiple `!`\ncharacters at the start of a pattern will negate the pattern multiple\ntimes.\n\nIf a pattern starts with `#`, then it is treated as a comment, and\nwill not match anything. Use `\\#` to match a literal `#` at the\nstart of a line, or set the `nocomment` flag to suppress this behavior.\n\nThe double-star character `**` is supported by default, unless the\n`noglobstar` flag is set. This is supported in the manner of bsdglob\nand bash 4.1, where `**` only has special significance if it is the only\nthing in a path part. That is, `a/**/b` will match `a/x/y/b`, but\n`a/**b` will not. **Note that this is different from the way that `**` is\nhandled by ruby's `Dir` class.**\n\nIf an escaped pattern has no matches, and the `nonull` flag is set,\nthen minimatch.match returns the pattern as-provided, rather than\ninterpreting the character escapes. For example,\n`minimatch.match([], \"\\\\*a\\\\?\")` will return `\"\\\\*a\\\\?\"` rather than\n`\"*a?\"`. This is akin to setting the `nullglob` option in bash, except\nthat it does not resolve escaped pattern characters.\n\nIf brace expansion is not disabled, then it is performed before any\nother interpretation of the glob pattern. Thus, a pattern like\n`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded\n**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are\nchecked for validity. Since those two are valid, matching proceeds.\n\n\n## Minimatch Class\n\nCreate a minimatch object by instanting the `minimatch.Minimatch` class.\n\n```javascript\nvar Minimatch = require(\"minimatch\").Minimatch\nvar mm = new Minimatch(pattern, options)\n```\n\n### Properties\n\n* `pattern` The original pattern the minimatch object represents.\n* `options` The options supplied to the constructor.\n* `set` A 2-dimensional array of regexp or string expressions.\n Each row in the\n array corresponds to a brace-expanded pattern. Each item in the row\n corresponds to a single path-part. For example, the pattern\n `{a,b/c}/d` would expand to a set of patterns like:\n\n [ [ a, d ]\n , [ b, c, d ] ]\n\n If a portion of the pattern doesn't have any \"magic\" in it\n (that is, it's something like `\"foo\"` rather than `fo*o?`), then it\n will be left as a string rather than converted to a regular\n expression.\n\n* `regexp` Created by the `makeRe` method. A single regular expression\n expressing the entire pattern. This is useful in cases where you wish\n to use the pattern somewhat like `fnmatch(3)` with `FNM_PATH` enabled.\n* `negate` True if the pattern is negated.\n* `comment` True if the pattern is a comment.\n* `empty` True if the pattern is `\"\"`.\n\n### Methods\n\n* `makeRe` Generate the `regexp` member if necessary, and return it.\n Will return `false` if the pattern is invalid.\n* `match(fname)` Return true if the filename matches the pattern, or\n false otherwise.\n* `matchOne(fileArray, patternArray, partial)` Take a `/`-split\n filename, and match it against a single row in the `regExpSet`. This\n method is mainly for internal use, but is exposed so that it can be\n used by a glob-walker that needs to avoid excessive filesystem calls.\n\nAll other methods are internal, and will be called as necessary.\n\n## Functions\n\nThe top-level exported function has a `cache` property, which is an LRU\ncache set to store 100 items. So, calling these methods repeatedly\nwith the same pattern and options will use the same Minimatch object,\nsaving the cost of parsing it multiple times.\n\n### minimatch(path, pattern, options)\n\nMain export. Tests a path against the pattern using the options.\n\n```javascript\nvar isJS = minimatch(file, \"*.js\", { matchBase: true })\n```\n\n### minimatch.filter(pattern, options)\n\nReturns a function that tests its\nsupplied argument, suitable for use with `Array.filter`. Example:\n\n```javascript\nvar javascripts = fileList.filter(minimatch.filter(\"*.js\", {matchBase: true}))\n```\n\n### minimatch.match(list, pattern, options)\n\nMatch against the list of\nfiles, in the style of fnmatch or glob. If nothing is matched, and\noptions.nonull is set, then return a list containing the pattern itself.\n\n```javascript\nvar javascripts = minimatch.match(fileList, \"*.js\", {matchBase: true}))\n```\n\n### minimatch.makeRe(pattern, options)\n\nMake a regular expression object from the pattern.\n\n## Options\n\nAll options are `false` by default.\n\n### debug\n\nDump a ton of stuff to stderr.\n\n### nobrace\n\nDo not expand `{a,b}` and `{1..3}` brace sets.\n\n### noglobstar\n\nDisable `**` matching against multiple folder names.\n\n### dot\n\nAllow patterns to match filenames starting with a period, even if\nthe pattern does not explicitly have a period in that spot.\n\nNote that by default, `a/**/b` will **not** match `a/.d/b`, unless `dot`\nis set.\n\n### noext\n\nDisable \"extglob\" style patterns like `+(a|b)`.\n\n### nocase\n\nPerform a case-insensitive match.\n\n### nonull\n\nWhen a match is not found by `minimatch.match`, return a list containing\nthe pattern itself. When set, an empty list is returned if there are\nno matches.\n\n### matchBase\n\nIf set, then patterns without slashes will be matched\nagainst the basename of the path if it contains slashes. For example,\n`a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`.\n\n### nocomment\n\nSuppress the behavior of treating `#` at the start of a pattern as a\ncomment.\n\n### nonegate\n\nSuppress the behavior of treating a leading `!` character as negation.\n\n### flipNegate\n\nReturns from negate expressions the same as if they were not negated.\n(Ie, true on a hit, false on a miss.)\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/minimatch/issues" + }, + "_id": "minimatch@0.2.12", + "dist": { + "shasum": "308fb5bc9d1aabe4a0477f812ec820ee5fa8e25d" + }, + "_from": "minimatch@>=0.2.4", + "_resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.12.tgz" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/test/basic.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/test/basic.js new file mode 100644 index 0000000..ae7ac73 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/test/basic.js @@ -0,0 +1,399 @@ +// http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test +// +// TODO: Some of these tests do very bad things with backslashes, and will +// most likely fail badly on windows. They should probably be skipped. + +var tap = require("tap") + , globalBefore = Object.keys(global) + , mm = require("../") + , files = [ "a", "b", "c", "d", "abc" + , "abd", "abe", "bb", "bcd" + , "ca", "cb", "dd", "de" + , "bdir/", "bdir/cfile"] + , next = files.concat([ "a-b", "aXb" + , ".x", ".y" ]) + + +var patterns = + [ "http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test" + , ["a*", ["a", "abc", "abd", "abe"]] + , ["X*", ["X*"], {nonull: true}] + + // allow null glob expansion + , ["X*", []] + + // isaacs: Slightly different than bash/sh/ksh + // \\* is not un-escaped to literal "*" in a failed match, + // but it does make it get treated as a literal star + , ["\\*", ["\\*"], {nonull: true}] + , ["\\**", ["\\**"], {nonull: true}] + , ["\\*\\*", ["\\*\\*"], {nonull: true}] + + , ["b*/", ["bdir/"]] + , ["c*", ["c", "ca", "cb"]] + , ["**", files] + + , ["\\.\\./*/", ["\\.\\./*/"], {nonull: true}] + , ["s/\\..*//", ["s/\\..*//"], {nonull: true}] + + , "legendary larry crashes bashes" + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/" + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/"], {nonull: true}] + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/" + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/"], {nonull: true}] + + , "character classes" + , ["[a-c]b*", ["abc", "abd", "abe", "bb", "cb"]] + , ["[a-y]*[^c]", ["abd", "abe", "bb", "bcd", + "bdir/", "ca", "cb", "dd", "de"]] + , ["a*[^c]", ["abd", "abe"]] + , function () { files.push("a-b", "aXb") } + , ["a[X-]b", ["a-b", "aXb"]] + , function () { files.push(".x", ".y") } + , ["[^a-c]*", ["d", "dd", "de"]] + , function () { files.push("a*b/", "a*b/ooo") } + , ["a\\*b/*", ["a*b/ooo"]] + , ["a\\*?/*", ["a*b/ooo"]] + , ["*\\\\!*", [], {null: true}, ["echo !7"]] + , ["*\\!*", ["echo !7"], null, ["echo !7"]] + , ["*.\\*", ["r.*"], null, ["r.*"]] + , ["a[b]c", ["abc"]] + , ["a[\\b]c", ["abc"]] + , ["a?c", ["abc"]] + , ["a\\*c", [], {null: true}, ["abc"]] + , ["", [""], { null: true }, [""]] + + , "http://www.opensource.apple.com/source/bash/bash-23/" + + "bash/tests/glob-test" + , function () { files.push("man/", "man/man1/", "man/man1/bash.1") } + , ["*/man*/bash.*", ["man/man1/bash.1"]] + , ["man/man1/bash.1", ["man/man1/bash.1"]] + , ["a***c", ["abc"], null, ["abc"]] + , ["a*****?c", ["abc"], null, ["abc"]] + , ["?*****??", ["abc"], null, ["abc"]] + , ["*****??", ["abc"], null, ["abc"]] + , ["?*****?c", ["abc"], null, ["abc"]] + , ["?***?****c", ["abc"], null, ["abc"]] + , ["?***?****?", ["abc"], null, ["abc"]] + , ["?***?****", ["abc"], null, ["abc"]] + , ["*******c", ["abc"], null, ["abc"]] + , ["*******?", ["abc"], null, ["abc"]] + , ["a*cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??k***", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??***k", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??***k**", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a****c**?**??*****", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["[-abc]", ["-"], null, ["-"]] + , ["[abc-]", ["-"], null, ["-"]] + , ["\\", ["\\"], null, ["\\"]] + , ["[\\\\]", ["\\"], null, ["\\"]] + , ["[[]", ["["], null, ["["]] + , ["[", ["["], null, ["["]] + , ["[*", ["[abc"], null, ["[abc"]] + , "a right bracket shall lose its special meaning and\n" + + "represent itself in a bracket expression if it occurs\n" + + "first in the list. -- POSIX.2 2.8.3.2" + , ["[]]", ["]"], null, ["]"]] + , ["[]-]", ["]"], null, ["]"]] + , ["[a-\z]", ["p"], null, ["p"]] + , ["??**********?****?", [], { null: true }, ["abc"]] + , ["??**********?****c", [], { null: true }, ["abc"]] + , ["?************c****?****", [], { null: true }, ["abc"]] + , ["*c*?**", [], { null: true }, ["abc"]] + , ["a*****c*?**", [], { null: true }, ["abc"]] + , ["a********???*******", [], { null: true }, ["abc"]] + , ["[]", [], { null: true }, ["a"]] + , ["[abc", [], { null: true }, ["["]] + + , "nocase tests" + , ["XYZ", ["xYz"], { nocase: true, null: true } + , ["xYz", "ABC", "IjK"]] + , ["ab*", ["ABC"], { nocase: true, null: true } + , ["xYz", "ABC", "IjK"]] + , ["[ia]?[ck]", ["ABC", "IjK"], { nocase: true, null: true } + , ["xYz", "ABC", "IjK"]] + + // [ pattern, [matches], MM opts, files, TAP opts] + , "onestar/twostar" + , ["{/*,*}", [], {null: true}, ["/asdf/asdf/asdf"]] + , ["{/?,*}", ["/a", "bb"], {null: true} + , ["/a", "/b/b", "/a/b/c", "bb"]] + + , "dots should not match unless requested" + , ["**", ["a/b"], {}, ["a/b", "a/.d", ".a/.d"]] + + // .. and . can only match patterns starting with ., + // even when options.dot is set. + , function () { + files = ["a/./b", "a/../b", "a/c/b", "a/.d/b"] + } + , ["a/*/b", ["a/c/b", "a/.d/b"], {dot: true}] + , ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: true}] + , ["a/*/b", ["a/c/b"], {dot:false}] + , ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: false}] + + + // this also tests that changing the options needs + // to change the cache key, even if the pattern is + // the same! + , ["**", ["a/b","a/.d",".a/.d"], { dot: true } + , [ ".a/.d", "a/.d", "a/b"]] + + , "paren sets cannot contain slashes" + , ["*(a/b)", ["*(a/b)"], {nonull: true}, ["a/b"]] + + // brace sets trump all else. + // + // invalid glob pattern. fails on bash4 and bsdglob. + // however, in this implementation, it's easier just + // to do the intuitive thing, and let brace-expansion + // actually come before parsing any extglob patterns, + // like the documentation seems to say. + // + // XXX: if anyone complains about this, either fix it + // or tell them to grow up and stop complaining. + // + // bash/bsdglob says this: + // , ["*(a|{b),c)}", ["*(a|{b),c)}"], {}, ["a", "ab", "ac", "ad"]] + // but we do this instead: + , ["*(a|{b),c)}", ["a", "ab", "ac"], {}, ["a", "ab", "ac", "ad"]] + + // test partial parsing in the presence of comment/negation chars + , ["[!a*", ["[!ab"], {}, ["[!ab", "[ab"]] + , ["[#a*", ["[#ab"], {}, ["[#ab", "[ab"]] + + // like: {a,b|c\\,d\\\|e} except it's unclosed, so it has to be escaped. + , ["+(a|*\\|c\\\\|d\\\\\\|e\\\\\\\\|f\\\\\\\\\\|g" + , ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g"] + , {} + , ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g", "a", "b\\c"]] + + + // crazy nested {,,} and *(||) tests. + , function () { + files = [ "a", "b", "c", "d" + , "ab", "ac", "ad" + , "bc", "cb" + , "bc,d", "c,db", "c,d" + , "d)", "(b|c", "*(b|c" + , "b|c", "b|cc", "cb|c" + , "x(a|b|c)", "x(a|c)" + , "(a|b|c)", "(a|c)"] + } + , ["*(a|{b,c})", ["a", "b", "c", "ab", "ac"]] + , ["{a,*(b|c,d)}", ["a","(b|c", "*(b|c", "d)"]] + // a + // *(b|c) + // *(b|d) + , ["{a,*(b|{c,d})}", ["a","b", "bc", "cb", "c", "d"]] + , ["*(a|{b|c,c})", ["a", "b", "c", "ab", "ac", "bc", "cb"]] + + + // test various flag settings. + , [ "*(a|{b|c,c})", ["x(a|b|c)", "x(a|c)", "(a|b|c)", "(a|c)"] + , { noext: true } ] + , ["a?b", ["x/y/acb", "acb/"], {matchBase: true} + , ["x/y/acb", "acb/", "acb/d/e", "x/y/acb/d"] ] + , ["#*", ["#a", "#b"], {nocomment: true}, ["#a", "#b", "c#d"]] + + + // begin channelling Boole and deMorgan... + , "negation tests" + , function () { + files = ["d", "e", "!ab", "!abc", "a!b", "\\!a"] + } + + // anything that is NOT a* matches. + , ["!a*", ["\\!a", "d", "e", "!ab", "!abc"]] + + // anything that IS !a* matches. + , ["!a*", ["!ab", "!abc"], {nonegate: true}] + + // anything that IS a* matches + , ["!!a*", ["a!b"]] + + // anything that is NOT !a* matches + , ["!\\!a*", ["a!b", "d", "e", "\\!a"]] + + // negation nestled within a pattern + , function () { + files = [ "foo.js" + , "foo.bar" + // can't match this one without negative lookbehind. + , "foo.js.js" + , "blar.js" + , "foo." + , "boo.js.boo" ] + } + , ["*.!(js)", ["foo.bar", "foo.", "boo.js.boo"] ] + + // https://github.com/isaacs/minimatch/issues/5 + , function () { + files = [ 'a/b/.x/c' + , 'a/b/.x/c/d' + , 'a/b/.x/c/d/e' + , 'a/b/.x' + , 'a/b/.x/' + , 'a/.x/b' + , '.x' + , '.x/' + , '.x/a' + , '.x/a/b' + , 'a/.x/b/.x/c' + , '.x/.x' ] + } + , ["**/.x/**", [ '.x/' + , '.x/a' + , '.x/a/b' + , 'a/.x/b' + , 'a/b/.x/' + , 'a/b/.x/c' + , 'a/b/.x/c/d' + , 'a/b/.x/c/d/e' ] ] + + ] + +var regexps = + [ '/^(?:(?=.)a[^/]*?)$/', + '/^(?:(?=.)X[^/]*?)$/', + '/^(?:(?=.)X[^/]*?)$/', + '/^(?:\\*)$/', + '/^(?:(?=.)\\*[^/]*?)$/', + '/^(?:\\*\\*)$/', + '/^(?:(?=.)b[^/]*?\\/)$/', + '/^(?:(?=.)c[^/]*?)$/', + '/^(?:(?:(?!(?:\\/|^)\\.).)*?)$/', + '/^(?:\\.\\.\\/(?!\\.)(?=.)[^/]*?\\/)$/', + '/^(?:s\\/(?=.)\\.\\.[^/]*?\\/)$/', + '/^(?:\\/\\^root:\\/\\{s\\/(?=.)\\^[^:][^/]*?:[^:][^/]*?:\\([^:]\\)[^/]*?\\.[^/]*?\\$\\/1\\/)$/', + '/^(?:\\/\\^root:\\/\\{s\\/(?=.)\\^[^:][^/]*?:[^:][^/]*?:\\([^:]\\)[^/]*?\\.[^/]*?\\$\\/\u0001\\/)$/', + '/^(?:(?!\\.)(?=.)[a-c]b[^/]*?)$/', + '/^(?:(?!\\.)(?=.)[a-y][^/]*?[^c])$/', + '/^(?:(?=.)a[^/]*?[^c])$/', + '/^(?:(?=.)a[X-]b)$/', + '/^(?:(?!\\.)(?=.)[^a-c][^/]*?)$/', + '/^(?:a\\*b\\/(?!\\.)(?=.)[^/]*?)$/', + '/^(?:(?=.)a\\*[^/]\\/(?!\\.)(?=.)[^/]*?)$/', + '/^(?:(?!\\.)(?=.)[^/]*?\\\\\\![^/]*?)$/', + '/^(?:(?!\\.)(?=.)[^/]*?\\![^/]*?)$/', + '/^(?:(?!\\.)(?=.)[^/]*?\\.\\*)$/', + '/^(?:(?=.)a[b]c)$/', + '/^(?:(?=.)a[b]c)$/', + '/^(?:(?=.)a[^/]c)$/', + '/^(?:a\\*c)$/', + 'false', + '/^(?:(?!\\.)(?=.)[^/]*?\\/(?=.)man[^/]*?\\/(?=.)bash\\.[^/]*?)$/', + '/^(?:man\\/man1\\/bash\\.1)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/]*?c)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]c)$/', + '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/])$/', + '/^(?:(?!\\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/])$/', + '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]c)$/', + '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?c)$/', + '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/])$/', + '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?)$/', + '/^(?:(?!\\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c)$/', + '/^(?:(?!\\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/])$/', + '/^(?:(?=.)a[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k[^/]*?[^/]*?[^/]*?)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?k)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?k[^/]*?[^/]*?)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?)$/', + '/^(?:(?!\\.)(?=.)[-abc])$/', + '/^(?:(?!\\.)(?=.)[abc-])$/', + '/^(?:\\\\)$/', + '/^(?:(?!\\.)(?=.)[\\\\])$/', + '/^(?:(?!\\.)(?=.)[\\[])$/', + '/^(?:\\[)$/', + '/^(?:(?=.)\\[(?!\\.)(?=.)[^/]*?)$/', + '/^(?:(?!\\.)(?=.)[\\]])$/', + '/^(?:(?!\\.)(?=.)[\\]-])$/', + '/^(?:(?!\\.)(?=.)[a-z])$/', + '/^(?:(?!\\.)(?=.)[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/])$/', + '/^(?:(?!\\.)(?=.)[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?c)$/', + '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?)$/', + '/^(?:(?!\\.)(?=.)[^/]*?c[^/]*?[^/][^/]*?[^/]*?)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/][^/]*?[^/]*?)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?)$/', + '/^(?:\\[\\])$/', + '/^(?:\\[abc)$/', + '/^(?:(?=.)XYZ)$/i', + '/^(?:(?=.)ab[^/]*?)$/i', + '/^(?:(?!\\.)(?=.)[ia][^/][ck])$/i', + '/^(?:\\/(?!\\.)(?=.)[^/]*?|(?!\\.)(?=.)[^/]*?)$/', + '/^(?:\\/(?!\\.)(?=.)[^/]|(?!\\.)(?=.)[^/]*?)$/', + '/^(?:(?:(?!(?:\\/|^)\\.).)*?)$/', + '/^(?:a\\/(?!(?:^|\\/)\\.{1,2}(?:$|\\/))(?=.)[^/]*?\\/b)$/', + '/^(?:a\\/(?=.)\\.[^/]*?\\/b)$/', + '/^(?:a\\/(?!\\.)(?=.)[^/]*?\\/b)$/', + '/^(?:a\\/(?=.)\\.[^/]*?\\/b)$/', + '/^(?:(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?)$/', + '/^(?:(?!\\.)(?=.)[^/]*?\\(a\\/b\\))$/', + '/^(?:(?!\\.)(?=.)(?:a|b)*|(?!\\.)(?=.)(?:a|c)*)$/', + '/^(?:(?=.)\\[(?=.)\\!a[^/]*?)$/', + '/^(?:(?=.)\\[(?=.)#a[^/]*?)$/', + '/^(?:(?=.)\\+\\(a\\|[^/]*?\\|c\\\\\\\\\\|d\\\\\\\\\\|e\\\\\\\\\\\\\\\\\\|f\\\\\\\\\\\\\\\\\\|g)$/', + '/^(?:(?!\\.)(?=.)(?:a|b)*|(?!\\.)(?=.)(?:a|c)*)$/', + '/^(?:a|(?!\\.)(?=.)[^/]*?\\(b\\|c|d\\))$/', + '/^(?:a|(?!\\.)(?=.)(?:b|c)*|(?!\\.)(?=.)(?:b|d)*)$/', + '/^(?:(?!\\.)(?=.)(?:a|b|c)*|(?!\\.)(?=.)(?:a|c)*)$/', + '/^(?:(?!\\.)(?=.)[^/]*?\\(a\\|b\\|c\\)|(?!\\.)(?=.)[^/]*?\\(a\\|c\\))$/', + '/^(?:(?=.)a[^/]b)$/', + '/^(?:(?=.)#[^/]*?)$/', + '/^(?!^(?:(?=.)a[^/]*?)$).*$/', + '/^(?:(?=.)\\!a[^/]*?)$/', + '/^(?:(?=.)a[^/]*?)$/', + '/^(?!^(?:(?=.)\\!a[^/]*?)$).*$/', + '/^(?:(?!\\.)(?=.)[^/]*?\\.(?:(?!js)[^/]*?))$/', + '/^(?:(?:(?!(?:\\/|^)\\.).)*?\\/\\.x\\/(?:(?!(?:\\/|^)\\.).)*?)$/' ] +var re = 0; + +tap.test("basic tests", function (t) { + var start = Date.now() + + // [ pattern, [matches], MM opts, files, TAP opts] + patterns.forEach(function (c) { + if (typeof c === "function") return c() + if (typeof c === "string") return t.comment(c) + + var pattern = c[0] + , expect = c[1].sort(alpha) + , options = c[2] || {} + , f = c[3] || files + , tapOpts = c[4] || {} + + // options.debug = true + var m = new mm.Minimatch(pattern, options) + var r = m.makeRe() + var expectRe = regexps[re++] + tapOpts.re = String(r) || JSON.stringify(r) + tapOpts.files = JSON.stringify(f) + tapOpts.pattern = pattern + tapOpts.set = m.set + tapOpts.negated = m.negate + + var actual = mm.match(f, pattern, options) + actual.sort(alpha) + + t.equivalent( actual, expect + , JSON.stringify(pattern) + " " + JSON.stringify(expect) + , tapOpts ) + + t.equal(tapOpts.re, expectRe, tapOpts) + }) + + t.comment("time=" + (Date.now() - start) + "ms") + t.end() +}) + +tap.test("global leak test", function (t) { + var globalAfter = Object.keys(global) + t.equivalent(globalAfter, globalBefore, "no new globals, please") + t.end() +}) + +function alpha (a, b) { + return a > b ? 1 : -1 +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/test/brace-expand.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/test/brace-expand.js new file mode 100644 index 0000000..7ee278a --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/test/brace-expand.js @@ -0,0 +1,33 @@ +var tap = require("tap") + , minimatch = require("../") + +tap.test("brace expansion", function (t) { + // [ pattern, [expanded] ] + ; [ [ "a{b,c{d,e},{f,g}h}x{y,z}" + , [ "abxy" + , "abxz" + , "acdxy" + , "acdxz" + , "acexy" + , "acexz" + , "afhxy" + , "afhxz" + , "aghxy" + , "aghxz" ] ] + , [ "a{1..5}b" + , [ "a1b" + , "a2b" + , "a3b" + , "a4b" + , "a5b" ] ] + , [ "a{b}c", ["a{b}c"] ] + ].forEach(function (tc) { + var p = tc[0] + , expect = tc[1] + t.equivalent(minimatch.braceExpand(p), expect, p) + }) + console.error("ending") + t.end() +}) + + diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/test/caching.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/test/caching.js new file mode 100644 index 0000000..0fec4b0 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/test/caching.js @@ -0,0 +1,14 @@ +var Minimatch = require("../minimatch.js").Minimatch +var tap = require("tap") +tap.test("cache test", function (t) { + var mm1 = new Minimatch("a?b") + var mm2 = new Minimatch("a?b") + t.equal(mm1, mm2, "should get the same object") + // the lru should drop it after 100 entries + for (var i = 0; i < 100; i ++) { + new Minimatch("a"+i) + } + mm2 = new Minimatch("a?b") + t.notEqual(mm1, mm2, "cache should have dropped") + t.end() +}) diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/test/defaults.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/test/defaults.js new file mode 100644 index 0000000..25f1f60 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/node_modules/minimatch/test/defaults.js @@ -0,0 +1,274 @@ +// http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test +// +// TODO: Some of these tests do very bad things with backslashes, and will +// most likely fail badly on windows. They should probably be skipped. + +var tap = require("tap") + , globalBefore = Object.keys(global) + , mm = require("../") + , files = [ "a", "b", "c", "d", "abc" + , "abd", "abe", "bb", "bcd" + , "ca", "cb", "dd", "de" + , "bdir/", "bdir/cfile"] + , next = files.concat([ "a-b", "aXb" + , ".x", ".y" ]) + +tap.test("basic tests", function (t) { + var start = Date.now() + + // [ pattern, [matches], MM opts, files, TAP opts] + ; [ "http://www.bashcookbook.com/bashinfo" + + "/source/bash-1.14.7/tests/glob-test" + , ["a*", ["a", "abc", "abd", "abe"]] + , ["X*", ["X*"], {nonull: true}] + + // allow null glob expansion + , ["X*", []] + + // isaacs: Slightly different than bash/sh/ksh + // \\* is not un-escaped to literal "*" in a failed match, + // but it does make it get treated as a literal star + , ["\\*", ["\\*"], {nonull: true}] + , ["\\**", ["\\**"], {nonull: true}] + , ["\\*\\*", ["\\*\\*"], {nonull: true}] + + , ["b*/", ["bdir/"]] + , ["c*", ["c", "ca", "cb"]] + , ["**", files] + + , ["\\.\\./*/", ["\\.\\./*/"], {nonull: true}] + , ["s/\\..*//", ["s/\\..*//"], {nonull: true}] + + , "legendary larry crashes bashes" + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/" + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/"], {nonull: true}] + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/" + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/"], {nonull: true}] + + , "character classes" + , ["[a-c]b*", ["abc", "abd", "abe", "bb", "cb"]] + , ["[a-y]*[^c]", ["abd", "abe", "bb", "bcd", + "bdir/", "ca", "cb", "dd", "de"]] + , ["a*[^c]", ["abd", "abe"]] + , function () { files.push("a-b", "aXb") } + , ["a[X-]b", ["a-b", "aXb"]] + , function () { files.push(".x", ".y") } + , ["[^a-c]*", ["d", "dd", "de"]] + , function () { files.push("a*b/", "a*b/ooo") } + , ["a\\*b/*", ["a*b/ooo"]] + , ["a\\*?/*", ["a*b/ooo"]] + , ["*\\\\!*", [], {null: true}, ["echo !7"]] + , ["*\\!*", ["echo !7"], null, ["echo !7"]] + , ["*.\\*", ["r.*"], null, ["r.*"]] + , ["a[b]c", ["abc"]] + , ["a[\\b]c", ["abc"]] + , ["a?c", ["abc"]] + , ["a\\*c", [], {null: true}, ["abc"]] + , ["", [""], { null: true }, [""]] + + , "http://www.opensource.apple.com/source/bash/bash-23/" + + "bash/tests/glob-test" + , function () { files.push("man/", "man/man1/", "man/man1/bash.1") } + , ["*/man*/bash.*", ["man/man1/bash.1"]] + , ["man/man1/bash.1", ["man/man1/bash.1"]] + , ["a***c", ["abc"], null, ["abc"]] + , ["a*****?c", ["abc"], null, ["abc"]] + , ["?*****??", ["abc"], null, ["abc"]] + , ["*****??", ["abc"], null, ["abc"]] + , ["?*****?c", ["abc"], null, ["abc"]] + , ["?***?****c", ["abc"], null, ["abc"]] + , ["?***?****?", ["abc"], null, ["abc"]] + , ["?***?****", ["abc"], null, ["abc"]] + , ["*******c", ["abc"], null, ["abc"]] + , ["*******?", ["abc"], null, ["abc"]] + , ["a*cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??k***", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??***k", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??***k**", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a****c**?**??*****", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["[-abc]", ["-"], null, ["-"]] + , ["[abc-]", ["-"], null, ["-"]] + , ["\\", ["\\"], null, ["\\"]] + , ["[\\\\]", ["\\"], null, ["\\"]] + , ["[[]", ["["], null, ["["]] + , ["[", ["["], null, ["["]] + , ["[*", ["[abc"], null, ["[abc"]] + , "a right bracket shall lose its special meaning and\n" + + "represent itself in a bracket expression if it occurs\n" + + "first in the list. -- POSIX.2 2.8.3.2" + , ["[]]", ["]"], null, ["]"]] + , ["[]-]", ["]"], null, ["]"]] + , ["[a-\z]", ["p"], null, ["p"]] + , ["??**********?****?", [], { null: true }, ["abc"]] + , ["??**********?****c", [], { null: true }, ["abc"]] + , ["?************c****?****", [], { null: true }, ["abc"]] + , ["*c*?**", [], { null: true }, ["abc"]] + , ["a*****c*?**", [], { null: true }, ["abc"]] + , ["a********???*******", [], { null: true }, ["abc"]] + , ["[]", [], { null: true }, ["a"]] + , ["[abc", [], { null: true }, ["["]] + + , "nocase tests" + , ["XYZ", ["xYz"], { nocase: true, null: true } + , ["xYz", "ABC", "IjK"]] + , ["ab*", ["ABC"], { nocase: true, null: true } + , ["xYz", "ABC", "IjK"]] + , ["[ia]?[ck]", ["ABC", "IjK"], { nocase: true, null: true } + , ["xYz", "ABC", "IjK"]] + + // [ pattern, [matches], MM opts, files, TAP opts] + , "onestar/twostar" + , ["{/*,*}", [], {null: true}, ["/asdf/asdf/asdf"]] + , ["{/?,*}", ["/a", "bb"], {null: true} + , ["/a", "/b/b", "/a/b/c", "bb"]] + + , "dots should not match unless requested" + , ["**", ["a/b"], {}, ["a/b", "a/.d", ".a/.d"]] + + // .. and . can only match patterns starting with ., + // even when options.dot is set. + , function () { + files = ["a/./b", "a/../b", "a/c/b", "a/.d/b"] + } + , ["a/*/b", ["a/c/b", "a/.d/b"], {dot: true}] + , ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: true}] + , ["a/*/b", ["a/c/b"], {dot:false}] + , ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: false}] + + + // this also tests that changing the options needs + // to change the cache key, even if the pattern is + // the same! + , ["**", ["a/b","a/.d",".a/.d"], { dot: true } + , [ ".a/.d", "a/.d", "a/b"]] + + , "paren sets cannot contain slashes" + , ["*(a/b)", ["*(a/b)"], {nonull: true}, ["a/b"]] + + // brace sets trump all else. + // + // invalid glob pattern. fails on bash4 and bsdglob. + // however, in this implementation, it's easier just + // to do the intuitive thing, and let brace-expansion + // actually come before parsing any extglob patterns, + // like the documentation seems to say. + // + // XXX: if anyone complains about this, either fix it + // or tell them to grow up and stop complaining. + // + // bash/bsdglob says this: + // , ["*(a|{b),c)}", ["*(a|{b),c)}"], {}, ["a", "ab", "ac", "ad"]] + // but we do this instead: + , ["*(a|{b),c)}", ["a", "ab", "ac"], {}, ["a", "ab", "ac", "ad"]] + + // test partial parsing in the presence of comment/negation chars + , ["[!a*", ["[!ab"], {}, ["[!ab", "[ab"]] + , ["[#a*", ["[#ab"], {}, ["[#ab", "[ab"]] + + // like: {a,b|c\\,d\\\|e} except it's unclosed, so it has to be escaped. + , ["+(a|*\\|c\\\\|d\\\\\\|e\\\\\\\\|f\\\\\\\\\\|g" + , ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g"] + , {} + , ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g", "a", "b\\c"]] + + + // crazy nested {,,} and *(||) tests. + , function () { + files = [ "a", "b", "c", "d" + , "ab", "ac", "ad" + , "bc", "cb" + , "bc,d", "c,db", "c,d" + , "d)", "(b|c", "*(b|c" + , "b|c", "b|cc", "cb|c" + , "x(a|b|c)", "x(a|c)" + , "(a|b|c)", "(a|c)"] + } + , ["*(a|{b,c})", ["a", "b", "c", "ab", "ac"]] + , ["{a,*(b|c,d)}", ["a","(b|c", "*(b|c", "d)"]] + // a + // *(b|c) + // *(b|d) + , ["{a,*(b|{c,d})}", ["a","b", "bc", "cb", "c", "d"]] + , ["*(a|{b|c,c})", ["a", "b", "c", "ab", "ac", "bc", "cb"]] + + + // test various flag settings. + , [ "*(a|{b|c,c})", ["x(a|b|c)", "x(a|c)", "(a|b|c)", "(a|c)"] + , { noext: true } ] + , ["a?b", ["x/y/acb", "acb/"], {matchBase: true} + , ["x/y/acb", "acb/", "acb/d/e", "x/y/acb/d"] ] + , ["#*", ["#a", "#b"], {nocomment: true}, ["#a", "#b", "c#d"]] + + + // begin channelling Boole and deMorgan... + , "negation tests" + , function () { + files = ["d", "e", "!ab", "!abc", "a!b", "\\!a"] + } + + // anything that is NOT a* matches. + , ["!a*", ["\\!a", "d", "e", "!ab", "!abc"]] + + // anything that IS !a* matches. + , ["!a*", ["!ab", "!abc"], {nonegate: true}] + + // anything that IS a* matches + , ["!!a*", ["a!b"]] + + // anything that is NOT !a* matches + , ["!\\!a*", ["a!b", "d", "e", "\\!a"]] + + // negation nestled within a pattern + , function () { + files = [ "foo.js" + , "foo.bar" + // can't match this one without negative lookbehind. + , "foo.js.js" + , "blar.js" + , "foo." + , "boo.js.boo" ] + } + , ["*.!(js)", ["foo.bar", "foo.", "boo.js.boo"] ] + + ].forEach(function (c) { + if (typeof c === "function") return c() + if (typeof c === "string") return t.comment(c) + + var pattern = c[0] + , expect = c[1].sort(alpha) + , options = c[2] || {} + , f = c[3] || files + , tapOpts = c[4] || {} + + // options.debug = true + var Class = mm.defaults(options).Minimatch + var m = new Class(pattern, {}) + var r = m.makeRe() + tapOpts.re = String(r) || JSON.stringify(r) + tapOpts.files = JSON.stringify(f) + tapOpts.pattern = pattern + tapOpts.set = m.set + tapOpts.negated = m.negate + + var actual = mm.match(f, pattern, options) + actual.sort(alpha) + + t.equivalent( actual, expect + , JSON.stringify(pattern) + " " + JSON.stringify(expect) + , tapOpts ) + }) + + t.comment("time=" + (Date.now() - start) + "ms") + t.end() +}) + +tap.test("global leak test", function (t) { + var globalAfter = Object.keys(global) + t.equivalent(globalAfter, globalBefore, "no new globals, please") + t.end() +}) + +function alpha (a, b) { + return a > b ? 1 : -1 +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/package.json b/node_modules/jade/node_modules/monocle/node_modules/readdirp/package.json new file mode 100644 index 0000000..6774e47 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/package.json @@ -0,0 +1,53 @@ +{ + "author": { + "name": "Thorsten Lorenz", + "email": "thlorenz@gmx.de", + "url": "thlorenz.com" + }, + "name": "readdirp", + "description": "Recursive version of fs.readdir with streaming api.", + "version": "0.2.5", + "homepage": "https://github.com/thlorenz/readdirp", + "repository": { + "type": "git", + "url": "git://github.com/thlorenz/readdirp.git" + }, + "engines": { + "node": ">=0.4" + }, + "keywords": [ + "recursive", + "fs", + "stream", + "streams", + "readdir", + "filesystem", + "find", + "filter" + ], + "main": "readdirp.js", + "scripts": { + "test": "tap test/*.js" + }, + "dependencies": { + "minimatch": ">=0.2.4" + }, + "devDependencies": { + "tap": "~0.3.1", + "through": "~1.1.0", + "minimatch": "~0.2.7" + }, + "optionalDependencies": {}, + "license": "MIT", + "readme": "# readdirp [![Build Status](https://secure.travis-ci.org/thlorenz/readdirp.png)](http://travis-ci.org/thlorenz/readdirp)\n\nRecursive version of [fs.readdir](http://nodejs.org/docs/latest/api/fs.html#fs_fs_readdir_path_callback). Exposes a **stream api**.\n\n```javascript\nvar readdirp = require('readdirp'); \n , path = require('path')\n , es = require('event-stream');\n\n// print out all JavaScript files along with their size\n\nvar stream = readdirp({ root: path.join(__dirname), fileFilter: '*.js' });\nstream\n .on('warn', function (err) { \n console.error('non-fatal error', err); \n // optionally call stream.destroy() here in order to abort and cause 'close' to be emitted\n })\n .on('error', function (err) { console.error('fatal error', err); })\n .pipe(es.mapSync(function (entry) { \n return { path: entry.path, size: entry.stat.size };\n }))\n .pipe(es.stringify())\n .pipe(process.stdout);\n```\n\nMeant to be one of the recursive versions of [fs](http://nodejs.org/docs/latest/api/fs.html) functions, e.g., like [mkdirp](https://github.com/substack/node-mkdirp).\n\n**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)*\n\n- [Installation](#installation)\n- [API](#api)\n\t- [entry stream](#entry-stream)\n\t- [options](#options)\n\t- [entry info](#entry-info)\n\t- [Filters](#filters)\n\t- [Callback API](#callback-api)\n\t\t- [allProcessed ](#allprocessed)\n\t\t- [fileProcessed](#fileprocessed)\n- [More Examples](#more-examples)\n\t- [stream api](#stream-api)\n\t- [stream api pipe](#stream-api-pipe)\n\t- [grep](#grep)\n\t- [using callback api](#using-callback-api)\n\t- [tests](#tests)\n\n\n# Installation\n\n npm install readdirp\n\n# API\n\n***var entryStream = readdirp (options)***\n\nReads given root recursively and returns a `stream` of [entry info](#entry-info)s.\n\n## entry stream\n\nBehaves as follows:\n \n- `emit('data')` passes an [entry info](#entry-info) whenever one is found\n- `emit('warn')` passes a non-fatal `Error` that prevents a file/directory from being processed (i.e., if it is\n inaccessible to the user)\n- `emit('error')` passes a fatal `Error` which also ends the stream (i.e., when illegal options where passed)\n- `emit('end')` called when all entries were found and no more will be emitted (i.e., we are done)\n- `emit('close')` called when the stream is destroyed via `stream.destroy()` (which could be useful if you want to\n manually abort even on a non fatal error) - at that point the stream is no longer `readable` and no more entries,\n warning or errors are emitted\n- the stream is `paused` initially in order to allow `pipe` and `on` handlers be connected before data or errors are\n emitted\n- the stream is `resumed` automatically during the next event loop \n- to learn more about streams, consult the [stream-handbook](https://github.com/substack/stream-handbook)\n\n## options\n \n- **root**: path in which to start reading and recursing into subdirectories\n\n- **fileFilter**: filter to include/exclude files found (see [Filters](#filters) for more)\n\n- **directoryFilter**: filter to include/exclude directories found and to recurse into (see [Filters](#filters) for more)\n\n- **depth**: depth at which to stop recursing even if more subdirectories are found\n\n## entry info\n\nHas the following properties:\n\n- **parentDir** : directory in which entry was found (relative to given root)\n- **fullParentDir** : full path to parent directory\n- **name** : name of the file/directory\n- **path** : path to the file/directory (relative to given root)\n- **fullPath** : full path to the file/directory found\n- **stat** : built in [stat object](http://nodejs.org/docs/v0.4.9/api/fs.html#fs.Stats)\n- **Example**: (assuming root was `/User/dev/readdirp`)\n \n parentDir : 'test/bed/root_dir1',\n fullParentDir : '/User/dev/readdirp/test/bed/root_dir1',\n name : 'root_dir1_subdir1',\n path : 'test/bed/root_dir1/root_dir1_subdir1',\n fullPath : '/User/dev/readdirp/test/bed/root_dir1/root_dir1_subdir1',\n stat : [ ... ]\n \n## Filters\n \nThere are three different ways to specify filters for files and directories respectively. \n\n- **function**: a function that takes an entry info as a parameter and returns true to include or false to exclude the entry\n\n- **glob string**: a string (e.g., `*.js`) which is matched using [minimatch](https://github.com/isaacs/minimatch), so go there for more\n information. \n\n Globstars (`**`) are not supported since specifiying a recursive pattern for an already recursive function doesn't make sense.\n\n Negated globs (as explained in the minimatch documentation) are allowed, e.g., `!*.txt` matches everything but text files.\n\n- **array of glob strings**: either need to be all inclusive or all exclusive (negated) patterns otherwise an error is thrown.\n \n `[ '*.json', '*.js' ]` includes all JavaScript and Json files.\n \n \n `[ '!.git', '!node_modules' ]` includes all directories except the '.git' and 'node_modules'.\n\nDirectories that do not pass a filter will not be recursed into.\n\n## Callback API\n\nAlthough the stream api is recommended, readdirp also exposes a callback based api.\n\n***readdirp (options, callback1 [, callback2])***\n\nIf callback2 is given, callback1 functions as the **fileProcessed** callback, and callback2 as the **allProcessed** callback.\n\nIf only callback1 is given, it functions as the **allProcessed** callback.\n\n### allProcessed \n\n- function with err and res parameters, e.g., `function (err, res) { ... }`\n- **err**: array of errors that occurred during the operation, **res may still be present, even if errors occurred**\n- **res**: collection of file/directory [entry infos](#entry-info)\n\n### fileProcessed\n\n- function with [entry info](#entry-info) parameter e.g., `function (entryInfo) { ... }`\n\n\n# More Examples\n\n`on('error', ..)`, `on('warn', ..)` and `on('end', ..)` handling omitted for brevity\n\n```javascript\nvar readdirp = require('readdirp');\n\n// Glob file filter\nreaddirp({ root: './test/bed', fileFilter: '*.js' })\n .on('data', function (entry) {\n // do something with each JavaScript file entry\n });\n\n// Combined glob file filters\nreaddirp({ root: './test/bed', fileFilter: [ '*.js', '*.json' ] })\n .on('data', function (entry) {\n // do something with each JavaScript and Json file entry \n });\n\n// Combined negated directory filters\nreaddirp({ root: './test/bed', directoryFilter: [ '!.git', '!*modules' ] })\n .on('data', function (entry) {\n // do something with each file entry found outside '.git' or any modules directory \n });\n\n// Function directory filter\nreaddirp({ root: './test/bed', directoryFilter: function (di) { return di.name.length === 9; } })\n .on('data', function (entry) {\n // do something with each file entry found inside directories whose name has length 9\n });\n\n// Limiting depth\nreaddirp({ root: './test/bed', depth: 1 })\n .on('data', function (entry) {\n // do something with each file entry found up to 1 subdirectory deep\n });\n\n// callback api\nreaddirp(\n { root: '.' }\n , function(fileInfo) { \n // do something with file entry here\n } \n , function (err, res) {\n // all done, move on or do final step for all file entries here\n }\n);\n```\n\nTry more examples by following [instructions](https://github.com/thlorenz/readdirp/blob/master/examples/Readme.md)\non how to get going.\n\n## stream api\n\n[stream-api.js](https://github.com/thlorenz/readdirp/blob/master/examples/stream-api.js)\n\nDemonstrates error and data handling by listening to events emitted from the readdirp stream.\n\n## stream api pipe\n\n[stream-api-pipe.js](https://github.com/thlorenz/readdirp/blob/master/examples/stream-api-pipe.js)\n\nDemonstrates error handling by listening to events emitted from the readdirp stream and how to pipe the data stream into\nanother destination stream.\n\n## grep\n\n[grep.js](https://github.com/thlorenz/readdirp/blob/master/examples/grep.js)\n\nVery naive implementation of grep, for demonstration purposes only.\n\n## using callback api\n\n[callback-api.js](https://github.com/thlorenz/readdirp/blob/master/examples/callback-api.js)\n\nShows how to pass callbacks in order to handle errors and/or data.\n\n## tests\n\nThe [readdirp tests](https://github.com/thlorenz/readdirp/blob/master/test/readdirp.js) also will give you a good idea on\nhow things work.\n\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/thlorenz/readdirp/issues" + }, + "_id": "readdirp@0.2.5", + "dist": { + "shasum": "cbc9c2bc1211e03528512b1070df05de529f1e7d" + }, + "_from": "readdirp@~0.2.3", + "_resolved": "https://registry.npmjs.org/readdirp/-/readdirp-0.2.5.tgz" +} diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/readdirp.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/readdirp.js new file mode 100644 index 0000000..6111e11 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/readdirp.js @@ -0,0 +1,276 @@ +'use strict'; + +var fs = require('fs') + , path = require('path') + , minimatch = require('minimatch') + , toString = Object.prototype.toString + ; + +// Standard helpers +function isFunction (obj) { + return toString.call(obj) == '[object Function]'; +} + +function isString (obj) { + return toString.call(obj) == '[object String]'; +} + +function isRegExp (obj) { + return toString.call(obj) == '[object RegExp]'; +} + +function isUndefined (obj) { + return obj === void 0; +} + +/** + * Main function which ends up calling readdirRec and reads all files and directories in given root recursively. + * @param { Object } opts Options to specify root (start directory), filters and recursion depth + * @param { function } callback1 When callback2 is given calls back for each processed file - function (fileInfo) { ... }, + * when callback2 is not given, it behaves like explained in callback2 + * @param { function } callback2 Calls back once all files have been processed with an array of errors and file infos + * function (err, fileInfos) { ... } + */ +function readdir(opts, callback1, callback2) { + var stream + , handleError + , handleFatalError + , pending = 0 + , errors = [] + , readdirResult = { + directories: [] + , files: [] + } + , fileProcessed + , allProcessed + , realRoot + , aborted = false + ; + + // If no callbacks were given we will use a streaming interface + if (isUndefined(callback1)) { + var api = require('./stream-api')(); + stream = api.stream; + callback1 = api.processEntry; + callback2 = api.done; + handleError = api.handleError; + handleFatalError = api.handleFatalError; + + stream.on('close', function () { aborted = true; }); + } else { + handleError = function (err) { errors.push(err); }; + handleFatalError = function (err) { + handleError(err); + allProcessed(errors, null); + }; + } + + if (isUndefined(opts)){ + handleFatalError(new Error ( + 'Need to pass at least one argument: opts! \n' + + 'https://github.com/thlorenz/readdirp#options' + ) + ); + return stream; + } + + opts.root = opts.root || '.'; + opts.fileFilter = opts.fileFilter || function() { return true; }; + opts.directoryFilter = opts.directoryFilter || function() { return true; }; + opts.depth = typeof opts.depth === 'undefined' ? 999999999 : opts.depth; + + if (isUndefined(callback2)) { + fileProcessed = function() { }; + allProcessed = callback1; + } else { + fileProcessed = callback1; + allProcessed = callback2; + } + + function normalizeFilter (filter) { + + if (isUndefined(filter)) return undefined; + + function isNegated (filters) { + + function negated(f) { + return f.indexOf('!') === 0; + } + + var some = filters.some(negated); + if (!some) { + return false; + } else { + if (filters.every(negated)) { + return true; + } else { + // if we detect illegal filters, bail out immediately + throw new Error( + 'Cannot mix negated with non negated glob filters: ' + filters + '\n' + + 'https://github.com/thlorenz/readdirp#filters' + ); + } + } + } + + // Turn all filters into a function + if (isFunction(filter)) { + + return filter; + + } else if (isString(filter)) { + + return function (entryInfo) { + return minimatch(entryInfo.name, filter.trim()); + }; + + } else if (filter && Array.isArray(filter)) { + + if (filter) filter = filter.map(function (f) { + return f.trim(); + }); + + return isNegated(filter) ? + // use AND to concat multiple negated filters + function (entryInfo) { + return filter.every(function (f) { + return minimatch(entryInfo.name, f); + }); + } + : + // use OR to concat multiple inclusive filters + function (entryInfo) { + return filter.some(function (f) { + return minimatch(entryInfo.name, f); + }); + }; + } + } + + function processDir(currentDir, entries, callProcessed) { + if (aborted) return; + var total = entries.length + , processed = 0 + , entryInfos = [] + ; + + fs.realpath(currentDir, function(err, realCurrentDir) { + if (aborted) return; + if (err) { + handleError(err); + callProcessed(entryInfos); + return; + } + + var relDir = path.relative(realRoot, realCurrentDir); + + if (entries.length === 0) { + callProcessed([]); + } else { + entries.forEach(function (entry) { + + var fullPath = path.join(realCurrentDir, entry), + relPath = path.join(relDir, entry); + + fs.stat(fullPath, function (err, stat) { + if (err) { + handleError(err); + } else { + entryInfos.push({ + name : entry + , path : relPath // relative to root + , fullPath : fullPath + + , parentDir : relDir // relative to root + , fullParentDir : realCurrentDir + + , stat : stat + }); + } + processed++; + if (processed === total) callProcessed(entryInfos); + }); + }); + } + }); + } + + function readdirRec(currentDir, depth, callCurrentDirProcessed) { + if (aborted) return; + + fs.readdir(currentDir, function (err, entries) { + if (err) { + handleError(err); + callCurrentDirProcessed(); + return; + } + + processDir(currentDir, entries, function(entryInfos) { + + var subdirs = entryInfos + .filter(function (ei) { return ei.stat.isDirectory() && opts.directoryFilter(ei); }); + + subdirs.forEach(function (di) { + readdirResult.directories.push(di); + }); + + entryInfos + .filter(function(ei) { return ei.stat.isFile() && opts.fileFilter(ei); }) + .forEach(function (fi) { + fileProcessed(fi); + readdirResult.files.push(fi); + }); + + var pendingSubdirs = subdirs.length; + + // Be done if no more subfolders exist or we reached the maximum desired depth + if(pendingSubdirs === 0 || depth === opts.depth) { + callCurrentDirProcessed(); + } else { + // recurse into subdirs, keeping track of which ones are done + // and call back once all are processed + subdirs.forEach(function (subdir) { + readdirRec(subdir.fullPath, depth + 1, function () { + pendingSubdirs = pendingSubdirs - 1; + if(pendingSubdirs === 0) { + callCurrentDirProcessed(); + } + }); + }); + } + }); + }); + } + + // Validate and normalize filters + try { + opts.fileFilter = normalizeFilter(opts.fileFilter); + opts.directoryFilter = normalizeFilter(opts.directoryFilter); + } catch (err) { + // if we detect illegal filters, bail out immediately + handleFatalError(err); + return stream; + } + + // If filters were valid get on with the show + fs.realpath(opts.root, function(err, res) { + if (err) { + handleFatalError(err); + return stream; + } + + realRoot = res; + readdirRec(opts.root, 0, function () { + // All errors are collected into the errors array + if (errors.length > 0) { + allProcessed(errors, readdirResult); + } else { + allProcessed(null, readdirResult); + } + }); + }); + + return stream; +} + +module.exports = readdir; diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/stream-api.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/stream-api.js new file mode 100644 index 0000000..1cfc616 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/stream-api.js @@ -0,0 +1,86 @@ +var Stream = require('stream'); + +function createStreamAPI () { + var stream + , processEntry + , done + , handleError + , handleFatalError + , paused = true + , controlled = false + , buffer = [] + , closed = false + ; + + stream = new Stream(); + stream.writable = false; + stream.readable = true; + + stream.pause = function () { + controlled = true; + paused = true; + }; + + stream.resume = function () { + controlled = true; + paused = false; + + // emit all buffered entries, errors and ends + while (!paused && buffer.length) { + var msg = buffer.shift(); + this.emit(msg.type, msg.data); + } + }; + + stream.destroy = function () { + closed = true; + stream.readable = false; + stream.emit('close'); + }; + + // called for each entry + processEntry = function (entry) { + if (closed) return; + return paused ? buffer.push({ type: 'data', data: entry }) : stream.emit('data', entry); + }; + + // called with all found entries when directory walk finished + done = function (err, entries) { + if (closed) return; + + // since we already emitted each entry and all non fatal errors + // all we need to do here is to signal that we are done + stream.emit('end'); + }; + + handleError = function (err) { + if (closed) return; + return paused ? buffer.push({ type: 'warn', data: err }) : stream.emit('warn', err); + }; + + handleFatalError = function (err) { + if (closed) return; + return paused ? buffer.push({ type: 'error', data: err }) : stream.emit('error', err); + }; + + // Allow stream to be returned and handlers to be attached and/or stream to be piped before emitting messages + // Otherwise we may loose data/errors that are emitted immediately + process.nextTick(function () { + if (closed) return; + + // In case was controlled (paused/resumed) manually, we don't interfer + // see https://github.com/thlorenz/readdirp/commit/ab7ff8561d73fca82c2ce7eb4ce9f7f5caf48b55#commitcomment-1964530 + if (controlled) return; + stream.resume(); + }); + + return { + stream : stream + , processEntry : processEntry + , done : done + , handleError : handleError + , handleFatalError : handleFatalError + }; +} + +module.exports = createStreamAPI; diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_dir1/root_dir1_file1.ext1 b/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_dir1/root_dir1_file1.ext1 new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_dir1/root_dir1_file2.ext2 b/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_dir1/root_dir1_file2.ext2 new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_dir1/root_dir1_file3.ext3 b/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_dir1/root_dir1_file3.ext3 new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_dir1/root_dir1_subdir1/root1_dir1_subdir1_file1.ext1 b/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_dir1/root_dir1_subdir1/root1_dir1_subdir1_file1.ext1 new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_dir2/root_dir2_file1.ext1 b/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_dir2/root_dir2_file1.ext1 new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_dir2/root_dir2_file2.ext2 b/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_dir2/root_dir2_file2.ext2 new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_file1.ext1 b/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_file1.ext1 new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_file2.ext2 b/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_file2.ext2 new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_file3.ext3 b/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/bed/root_file3.ext3 new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/readdirp-stream.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/readdirp-stream.js new file mode 100644 index 0000000..261c5f6 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/readdirp-stream.js @@ -0,0 +1,215 @@ +/*jshint asi:true */ + +var test = require('tap').test + , path = require('path') + , fs = require('fs') + , util = require('util') + , Stream = require('stream') + , through = require('through') + , streamapi = require('../stream-api') + , readdirp = require('..') + , root = path.join(__dirname, 'bed') + , totalDirs = 6 + , totalFiles = 12 + , ext1Files = 4 + , ext2Files = 3 + , ext3Files = 2 + ; + +// see test/readdirp.js for test bed layout + +function opts (extend) { + var o = { root: root }; + + if (extend) { + for (var prop in extend) { + o[prop] = extend[prop]; + } + } + return o; +} + +function capture () { + var result = { entries: [], errors: [], ended: false } + , dst = new Stream(); + + dst.writable = true; + dst.readable = true; + + dst.write = function (entry) { + result.entries.push(entry); + } + + dst.end = function () { + result.ended = true; + dst.emit('data', result); + dst.emit('end'); + } + + return dst; +} + +test('\nintegrated', function (t) { + t.test('\n# reading root without filter', function (t) { + t.plan(2); + readdirp(opts()) + .on('error', function (err) { + t.fail('should not throw error', err); + }) + .pipe(capture()) + .pipe(through( + function (result) { + t.equals(result.entries.length, totalFiles, 'emits all files'); + t.ok(result.ended, 'ends stream'); + t.end(); + } + )); + }) + + t.test('\n# normal: ["*.ext1", "*.ext3"]', function (t) { + t.plan(2); + + readdirp(opts( { fileFilter: [ '*.ext1', '*.ext3' ] } )) + .on('error', function (err) { + t.fail('should not throw error', err); + }) + .pipe(capture()) + .pipe(through( + function (result) { + t.equals(result.entries.length, ext1Files + ext3Files, 'all ext1 and ext3 files'); + t.ok(result.ended, 'ends stream'); + t.end(); + } + )) + }) + + t.test('\n# negated: ["!*.ext1", "!*.ext3"]', function (t) { + t.plan(2); + + readdirp(opts( { fileFilter: [ '!*.ext1', '!*.ext3' ] } )) + .on('error', function (err) { + t.fail('should not throw error', err); + }) + .pipe(capture()) + .pipe(through( + function (result) { + t.equals(result.entries.length, totalFiles - ext1Files - ext3Files, 'all but ext1 and ext3 files'); + t.ok(result.ended, 'ends stream'); + t.end(); + } + )) + }) + + t.test('\n# no options given', function (t) { + t.plan(1); + readdirp() + .on('error', function (err) { + t.similar(err.toString() , /Need to pass at least one argument/ , 'emits meaningful error'); + t.end(); + }) + }) + + t.test('\n# mixed: ["*.ext1", "!*.ext3"]', function (t) { + t.plan(1); + + readdirp(opts( { fileFilter: [ '*.ext1', '!*.ext3' ] } )) + .on('error', function (err) { + t.similar(err.toString() , /Cannot mix negated with non negated glob filters/ , 'emits meaningful error'); + t.end(); + }) + }) +}) + + +test('\napi separately', function (t) { + + t.test('\n# handleError', function (t) { + t.plan(1); + + var api = streamapi() + , warning = new Error('some file caused problems'); + + api.stream + .on('warn', function (err) { + t.equals(err, warning, 'warns with the handled error'); + }) + api.handleError(warning); + }) + + t.test('\n# when stream is paused and then resumed', function (t) { + t.plan(6); + var api = streamapi() + , resumed = false + , fatalError = new Error('fatal!') + , nonfatalError = new Error('nonfatal!') + , processedData = 'some data' + ; + + api.stream + .on('warn', function (err) { + t.equals(err, nonfatalError, 'emits the buffered warning'); + t.ok(resumed, 'emits warning only after it was resumed'); + }) + .on('error', function (err) { + t.equals(err, fatalError, 'emits the buffered fatal error'); + t.ok(resumed, 'emits errors only after it was resumed'); + }) + .on('data', function (data) { + t.equals(data, processedData, 'emits the buffered data'); + t.ok(resumed, 'emits data only after it was resumed'); + }) + .pause() + + api.processEntry(processedData); + api.handleError(nonfatalError); + api.handleFatalError(fatalError); + + process.nextTick(function () { + resumed = true; + api.stream.resume(); + }) + }) + + t.test('\n# when a stream is destroyed, it emits "closed", but no longer emits "data", "warn" and "error"', function (t) { + t.plan(6) + var api = streamapi() + , destroyed = false + , fatalError = new Error('fatal!') + , nonfatalError = new Error('nonfatal!') + , processedData = 'some data' + + var stream = api.stream + .on('warn', function (err) { + t.notOk(destroyed, 'emits warning until destroyed'); + }) + .on('error', function (err) { + t.notOk(destroyed, 'emits errors until destroyed'); + }) + .on('data', function (data) { + t.notOk(destroyed, 'emits data until destroyed'); + }) + .on('close', function () { + t.ok(destroyed, 'emits close when stream is destroyed'); + }) + + + api.processEntry(processedData); + api.handleError(nonfatalError); + api.handleFatalError(fatalError); + + process.nextTick(function () { + destroyed = true + stream.destroy() + + t.notOk(stream.readable, 'stream is no longer readable after it is destroyed') + + api.processEntry(processedData); + api.handleError(nonfatalError); + api.handleFatalError(fatalError); + + process.nextTick(function () { + t.pass('emits no more data, warn or error events after it was destroyed') + }) + }) + }) +}) diff --git a/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/readdirp.js b/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/readdirp.js new file mode 100644 index 0000000..f3edb52 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/node_modules/readdirp/test/readdirp.js @@ -0,0 +1,252 @@ +/*jshint asi:true */ + +var test = require('tap').test + , path = require('path') + , fs = require('fs') + , util = require('util') + , readdirp = require('../readdirp.js') + , root = path.join(__dirname, '../test/bed') + , totalDirs = 6 + , totalFiles = 12 + , ext1Files = 4 + , ext2Files = 3 + , ext3Files = 2 + , rootDir2Files = 2 + , nameHasLength9Dirs = 2 + , depth1Files = 8 + , depth0Files = 3 + ; + +/* +Structure of test bed: + . + ├── root_dir1 + │   ├── root_dir1_file1.ext1 + │   ├── root_dir1_file2.ext2 + │   ├── root_dir1_file3.ext3 + │   ├── root_dir1_subdir1 + │   │   └── root1_dir1_subdir1_file1.ext1 + │   └── root_dir1_subdir2 + │   └── .gitignore + ├── root_dir2 + │   ├── root_dir2_file1.ext1 + │   ├── root_dir2_file2.ext2 + │   ├── root_dir2_subdir1 + │   │   └── .gitignore + │   └── root_dir2_subdir2 + │   └── .gitignore + ├── root_file1.ext1 + ├── root_file2.ext2 + └── root_file3.ext3 + + 6 directories, 13 files +*/ + +// console.log('\033[2J'); // clear console + +function opts (extend) { + var o = { root: root }; + + if (extend) { + for (var prop in extend) { + o[prop] = extend[prop]; + } + } + return o; +} + +test('\nreading root without filter', function (t) { + t.plan(2); + readdirp(opts(), function (err, res) { + t.equals(res.directories.length, totalDirs, 'all directories'); + t.equals(res.files.length, totalFiles, 'all files'); + t.end(); + }) +}) + +test('\nreading root using glob filter', function (t) { + // normal + t.test('\n# "*.ext1"', function (t) { + t.plan(1); + readdirp(opts( { fileFilter: '*.ext1' } ), function (err, res) { + t.equals(res.files.length, ext1Files, 'all ext1 files'); + t.end(); + }) + }) + t.test('\n# ["*.ext1", "*.ext3"]', function (t) { + t.plan(1); + readdirp(opts( { fileFilter: [ '*.ext1', '*.ext3' ] } ), function (err, res) { + t.equals(res.files.length, ext1Files + ext3Files, 'all ext1 and ext3 files'); + t.end(); + }) + }) + t.test('\n# "root_dir1"', function (t) { + t.plan(1); + readdirp(opts( { directoryFilter: 'root_dir1' }), function (err, res) { + t.equals(res.directories.length, 1, 'one directory'); + t.end(); + }) + }) + t.test('\n# ["root_dir1", "*dir1_subdir1"]', function (t) { + t.plan(1); + readdirp(opts( { directoryFilter: [ 'root_dir1', '*dir1_subdir1' ]}), function (err, res) { + t.equals(res.directories.length, 2, 'two directories'); + t.end(); + }) + }) + + t.test('\n# negated: "!*.ext1"', function (t) { + t.plan(1); + readdirp(opts( { fileFilter: '!*.ext1' } ), function (err, res) { + t.equals(res.files.length, totalFiles - ext1Files, 'all but ext1 files'); + t.end(); + }) + }) + t.test('\n# negated: ["!*.ext1", "!*.ext3"]', function (t) { + t.plan(1); + readdirp(opts( { fileFilter: [ '!*.ext1', '!*.ext3' ] } ), function (err, res) { + t.equals(res.files.length, totalFiles - ext1Files - ext3Files, 'all but ext1 and ext3 files'); + t.end(); + }) + }) + + t.test('\n# mixed: ["*.ext1", "!*.ext3"]', function (t) { + t.plan(1); + readdirp(opts( { fileFilter: [ '*.ext1', '!*.ext3' ] } ), function (err, res) { + t.similar(err[0].toString(), /Cannot mix negated with non negated glob filters/, 'returns meaningfull error'); + t.end(); + }) + }) + + t.test('\n# leading and trailing spaces: [" *.ext1", "*.ext3 "]', function (t) { + t.plan(1); + readdirp(opts( { fileFilter: [ ' *.ext1', '*.ext3 ' ] } ), function (err, res) { + t.equals(res.files.length, ext1Files + ext3Files, 'all ext1 and ext3 files'); + t.end(); + }) + }) + t.test('\n# leading and trailing spaces: [" !*.ext1", " !*.ext3 "]', function (t) { + t.plan(1); + readdirp(opts( { fileFilter: [ ' !*.ext1', ' !*.ext3' ] } ), function (err, res) { + t.equals(res.files.length, totalFiles - ext1Files - ext3Files, 'all but ext1 and ext3 files'); + t.end(); + }) + }) + + t.test('\n# ** glob pattern', function (t) { + t.plan(1); + readdirp(opts( { fileFilter: '**/*.ext1' } ), function (err, res) { + t.equals(res.files.length, ext1Files, 'ignores ** in **/*.ext1 -> only *.ext1 files'); + t.end(); + }) + }) +}) + +test('\n\nreading root using function filter', function (t) { + t.test('\n# file filter -> "contains root_dir2"', function (t) { + t.plan(1); + readdirp( + opts( { fileFilter: function (fi) { return fi.name.indexOf('root_dir2') >= 0; } }) + , function (err, res) { + t.equals(res.files.length, rootDir2Files, 'all rootDir2Files'); + t.end(); + } + ) + }) + + t.test('\n# directory filter -> "name has length 9"', function (t) { + t.plan(1); + readdirp( + opts( { directoryFilter: function (di) { return di.name.length === 9; } }) + , function (err, res) { + t.equals(res.directories.length, nameHasLength9Dirs, 'all all dirs with name length 9'); + t.end(); + } + ) + }) +}) + +test('\nreading root specifying maximum depth', function (t) { + t.test('\n# depth 1', function (t) { + t.plan(1); + readdirp(opts( { depth: 1 } ), function (err, res) { + t.equals(res.files.length, depth1Files, 'does not return files at depth 2'); + }) + }) +}) + +test('\nreading root with no recursion', function (t) { + t.test('\n# depth 0', function (t) { + t.plan(1); + readdirp(opts( { depth: 0 } ), function (err, res) { + t.equals(res.files.length, depth0Files, 'does not return files at depth 0'); + }) + }) +}) + +test('\nprogress callbacks', function (t) { + t.plan(2); + + var pluckName = function(fi) { return fi.name; } + , processedFiles = []; + + readdirp( + opts() + , function(fi) { + processedFiles.push(fi); + } + , function (err, res) { + t.equals(processedFiles.length, res.files.length, 'calls back for each file processed'); + t.deepEquals(processedFiles.map(pluckName).sort(),res.files.map(pluckName).sort(), 'same file names'); + t.end(); + } + ) +}) + +test('resolving of name, full and relative paths', function (t) { + var expected = { + name : 'root_dir1_file1.ext1' + , parentDirName : 'root_dir1' + , path : 'root_dir1/root_dir1_file1.ext1' + , fullPath : 'test/bed/root_dir1/root_dir1_file1.ext1' + } + , opts = [ + { root: './bed' , prefix: '' } + , { root: './bed/' , prefix: '' } + , { root: 'bed' , prefix: '' } + , { root: 'bed/' , prefix: '' } + , { root: '../test/bed/' , prefix: '' } + , { root: '.' , prefix: 'bed' } + ] + t.plan(opts.length); + + opts.forEach(function (op) { + op.fileFilter = 'root_dir1_file1.ext1'; + + t.test('\n' + util.inspect(op), function (t) { + t.plan(4); + + readdirp (op, function(err, res) { + t.equals(res.files[0].name, expected.name, 'correct name'); + t.equals(res.files[0].path, path.join(op.prefix, expected.path), 'correct path'); + }) + + fs.realpath(op.root, function(err, fullRoot) { + readdirp (op, function(err, res) { + t.equals( + res.files[0].fullParentDir + , path.join(fullRoot, op.prefix, expected.parentDirName) + , 'correct parentDir' + ); + t.equals( + res.files[0].fullPath + , path.join(fullRoot, op.prefix, expected.parentDirName, expected.name) + , 'correct fullPath' + ); + }) + }) + }) + }) +}) + + diff --git a/node_modules/jade/node_modules/monocle/package.json b/node_modules/jade/node_modules/monocle/package.json new file mode 100644 index 0000000..c0793d3 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/package.json @@ -0,0 +1,43 @@ +{ + "name": "monocle", + "version": "1.1.50", + "description": "a tool for watching directories for file changes", + "main": "monocle.js", + "directories": { + "test": "test" + }, + "dependencies": { + "readdirp": "~0.2.3" + }, + "devDependencies": { + "mocha": "1.8.1" + }, + "scripts": { + "test": "mocha test -R spec -t 5000" + }, + "repository": { + "type": "git", + "url": "https://github.com/samccone/monocle.git" + }, + "bugs": { + "url": "https://github.com/samccone/monocle/issues" + }, + "keywords": [ + "watch", + "filesystem", + "folders", + "fs" + ], + "author": { + "name": "Sam Saccone" + }, + "license": "BSD", + "readme": "[![Build Status](https://travis-ci.org/samccone/monocle.png?branch=master)](https://travis-ci.org/samccone/monocle)\n\n# Monocle -- a tool for watching things\n\n[![logo](https://raw.github.com/samccone/monocle/master/logo.png)](https://raw.github.com/samccone/monocle/master/logo.png)\n\nHave you ever wanted to watch a folder and all of its files/nested folders for changes. well now you can!\n\n## Installation\n\n```\nnpm install monocle\n```\n\n## Usage\n\n### Watch a directory:\n\n```js\nvar monocle = require('monocle')()\nmonocle.watchDirectory({\n root: ,\n fileFilter: ,\n directoryFilter: ,\n listener: fn(fs.stat+ object), //triggered on file change / addition\n complete: //file watching all set up\n});\n```\n\nThe listener will recive an object with the following\n\n```js\n name: ,\n path: ,\n fullPath: ,\n parentDir: ,\n fullParentDir: ,\n stat: \n```\n\n[fs.stats](http://nodejs.org/api/fs.html#fs_class_fs_stats)\n\nWhen a new file is added to the directoy it triggers a file change and thus will be passed to your specified listener.\n\nThe two filters are passed through to `readdirp`. More documentation can be found [here](https://github.com/thlorenz/readdirp#filters)\n\n### Watch a list of files:\n\n```js\nMonocle.watchFiles({\n files: [], //path of file(s)\n listener: , //triggered on file / addition\n complete: //file watching all set up\n});\n```\n\n### Just watch path\n\nJust an alias of `watchFiles` and `watchDirectory` so you don't need to tell if that's a file or a directory by yourself. Parameter passed to `path` can be a `string` or a `array` of `string`.\n\n```js\nMonocle.watchPaths({\n path: [], //list of paths, or a string of path\n fileFilter: , // `*.js` for example\n listener: , //triggered on file / addition\n complete: //file watching all set up\n});\n```\n\n## Why not just use fs.watch ?\n\n - file watching is really bad cross platforms in node\n - you need to be smart when using fs.watch as compared to fs.watchFile\n - Monocle takes care of this logic for you!\n - windows systems use fs.watch\n - osx and linux uses fs.watchFile\n\n## License\n\nBSD\n", + "readmeFilename": "README.md", + "_id": "monocle@1.1.50", + "dist": { + "shasum": "e21b059d99726d958371f36240c106b8a067fa7d" + }, + "_from": "monocle@1.1.50", + "_resolved": "https://registry.npmjs.org/monocle/-/monocle-1.1.50.tgz" +} diff --git a/node_modules/jade/node_modules/monocle/test/sample_files/foo.txt b/node_modules/jade/node_modules/monocle/test/sample_files/foo.txt new file mode 100644 index 0000000..6b3d2f0 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/test/sample_files/foo.txt @@ -0,0 +1 @@ +1371772092664 diff --git a/node_modules/jade/node_modules/monocle/test/sample_files/longbow.js b/node_modules/jade/node_modules/monocle/test/sample_files/longbow.js new file mode 100644 index 0000000..474d7be --- /dev/null +++ b/node_modules/jade/node_modules/monocle/test/sample_files/longbow.js @@ -0,0 +1 @@ +1371772069082 diff --git a/node_modules/jade/node_modules/monocle/test/sample_files/nestedDir/servent.txt b/node_modules/jade/node_modules/monocle/test/sample_files/nestedDir/servent.txt new file mode 100644 index 0000000..67ff958 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/test/sample_files/nestedDir/servent.txt @@ -0,0 +1 @@ +1371772092813 diff --git a/node_modules/jade/node_modules/monocle/test/sample_files/zap.bat b/node_modules/jade/node_modules/monocle/test/sample_files/zap.bat new file mode 100644 index 0000000..a358cce --- /dev/null +++ b/node_modules/jade/node_modules/monocle/test/sample_files/zap.bat @@ -0,0 +1,31 @@ +1361223315286 +1361223316535 +1361223345247 +1361223392495 +1361223394521 +1361223401023 +1361223431160 +1361223432160 +1361223437177 +1361223438592 +1361223466645 +1361223467719 +1361223594858 +1361223614308 +1361223643429 +1361223647989 +1361223649211 +1361223650605 +1361223651566 +1361223663051 +1361223664917 +1361223665860 +1361223777758 +1361223779174 +1361223780023 +1361223780769 +1361223783122 +1361223784141 +1361223791305 +1361223795551 +1361223797217 diff --git a/node_modules/jade/node_modules/monocle/test/tester.js b/node_modules/jade/node_modules/monocle/test/tester.js new file mode 100644 index 0000000..8ce94b6 --- /dev/null +++ b/node_modules/jade/node_modules/monocle/test/tester.js @@ -0,0 +1,359 @@ +var fs = require('fs'); +var assert = require('assert'); +var Monocle = require('../monocle'); + +// +// setup +// +var monocle = null; +var sample_dir = __dirname + '/sample_files'; +before(function(){ monocle = Monocle(); }); +after(function() { + fs.unlinkSync(__dirname+"/sample_files/creation.txt"); + fs.unlinkSync(__dirname+"/sample_files/creation2.txt"); + fs.unlinkSync(__dirname+"/sample_files/creation3.txt"); + fs.unlinkSync(__dirname+"/sample_files/creation4.txt"); + fs.unlinkSync(__dirname+"/sample_files/creation5.txt"); + fs.unlinkSync(__dirname+"/sample_files/nestedDir/creation3.txt"); +}); +// +// file change tests +// + +describe("file changes", function() { + + it("should detect a change", function(complete) { + monocle.watchDirectory({ + root: sample_dir, + listener: function(f){ cb_helper('foo.txt', f, complete); }, + complete: function(){ complete_helper("/sample_files/foo.txt"); } + }); + }); + + it("should detect a change in a nested dir file", function(complete) { + monocle.watchDirectory({ + root: sample_dir, + listener: function(f) { cb_helper('servent.txt', f, complete); }, + complete: function() { complete_helper("/sample_files/nestedDir/servent.txt"); } + }); + }); + + it("should detect a change", function(complete) { + monocle.watchDirectory({ + root: sample_dir, + listener: function(f) { cb_helper('longbow.js', f, complete); }, + complete: function() { complete_helper('/sample_files/longbow.js'); } + }); + }); + + it("should detect a change", function(complete) { + monocle.watchPaths({ + path: sample_dir, + listener: function(f) { cb_helper('longbow.js', f, complete); }, + complete: function() { complete_helper('/sample_files/longbow.js'); } + }); + }); + +}); + +// +// file add tests +// + +describe("file added", function() { + it("should detect a file added", function(complete) { + monocle.watchDirectory({ + root: sample_dir, + listener: function(f) { + cb_helper("creation.txt", f, complete) + }, + complete: function() { + complete_helper('/sample_files/creation.txt'); + } + }); + }); + + it("should detect another file added", function(complete) { + monocle.watchDirectory({ + root: sample_dir, + listener: function(f) { + cb_helper("creation2.txt", f, complete); + }, + complete: function() { + complete_helper('/sample_files/creation2.txt'); + } + }); + }); + + it("should detect another file added in a nested folder", function(complete) { + monocle.watchDirectory({ + root: sample_dir, + listener: function(f) { + cb_helper("creation3.txt", f, complete); + }, + complete: function() { + complete_helper('/sample_files/nestedDir/creation3.txt'); + } + }); + }); + + it("should detect another file added", function(complete) { + monocle.watchPaths({ + path: sample_dir, + listener: function(f) { + cb_helper("creation2.txt", f, complete); + }, + complete: function() { + complete_helper('/sample_files/creation2.txt'); + } + }); + }); + + it("should detect another file added but passed as list", function(complete) { + monocle.watchPaths({ + path: [sample_dir], + listener: function(f) { + cb_helper("creation2.txt", f, complete); + }, + complete: function() { + complete_helper('/sample_files/creation2.txt'); + } + }); + }); +}); + + +// +// watch an array of files +// +describe("files watched", function() { + it("should detect a file changed of multiple", function(complete) { + complete_helper('/sample_files/creation.txt'); + complete_helper('/sample_files/creation2.txt'); + complete_helper('/sample_files/creation3.txt'); + + monocle.watchFiles({ + files: [__dirname+"/sample_files/creation.txt", __dirname+"/sample_files/creation2.txt"], + listener: function(f) { + cb_helper("creation2.txt", f, complete) + }, + complete: function() { + complete_helper('/sample_files/creation2.txt'); + } + }); + }); + + it("should detect a file changed (delayed)", function(complete) { + complete_helper('/sample_files/creation3.txt'); + monocle.watchFiles({ + files: [__dirname+"/sample_files/creation3.txt"], + listener: function(f) { + setTimeout(function() { + cb_helper('creation3.txt', f, complete); + }, 400); + }, + complete: function() { + complete_helper('/sample_files/creation3.txt'); + } + }); + }); + + it("should detect a file changed (short delayed)", function(complete) { + complete_helper('/sample_files/creation4.txt'); + monocle.watchFiles({ + files: [__dirname+"/sample_files/creation4.txt"], + listener: function(f) { + setTimeout(function() { + cb_helper('creation4.txt', f, complete); + }, 100); + }, + complete: function() { + complete_helper('/sample_files/creation4.txt'); + } + }); + }); + + it("should detect a file changed", function(complete) { + complete_helper('/sample_files/creation.txt'); + monocle.watchFiles({ + files: [__dirname+"/sample_files/creation.txt"], + listener: function(f) { + cb_helper("creation.txt", f, complete) + }, + complete: function() { + complete_helper('/sample_files/creation.txt'); + } + }); + }); + + it("should not bomb when no callback is passed", function(complete) { + complete_helper('/sample_files/creation5.txt'); + monocle.watchFiles({ + files: [__dirname+"/sample_files/creation5.txt"], + complete: function() { + complete_helper('/sample_files/creation5.txt'); + } + }); + setTimeout(function() { + complete(); + }, 300) + }); +}); + + +// +// watch an array of paths +// +describe("paths watched", function() { + it("should detect a file changed of multiple", function(complete) { + complete_helper('/sample_files/creation.txt'); + complete_helper('/sample_files/creation2.txt'); + complete_helper('/sample_files/creation3.txt'); + + monocle.watchPaths({ + path: [__dirname+"/sample_files/creation.txt", __dirname+"/sample_files/creation2.txt"], + listener: function(f) { + cb_helper("creation2.txt", f, complete) + }, + complete: function() { + complete_helper('/sample_files/creation2.txt'); + } + }); + }); + + it("should detect a file changed (delayed)", function(complete) { + complete_helper('/sample_files/creation3.txt'); + monocle.watchPaths({ + path: [__dirname+"/sample_files/creation3.txt"], + listener: function(f) { + setTimeout(function() { + cb_helper('creation3.txt', f, complete); + }, 400); + }, + complete: function() { + complete_helper('/sample_files/creation3.txt'); + } + }); + }); + + it("should detect a file changed (short delayed)", function(complete) { + complete_helper('/sample_files/creation4.txt'); + monocle.watchPaths({ + path: [__dirname+"/sample_files/creation4.txt"], + listener: function(f) { + setTimeout(function() { + cb_helper('creation4.txt', f, complete); + }, 100); + }, + complete: function() { + complete_helper('/sample_files/creation4.txt'); + } + }); + }); + + it("should detect a file changed", function(complete) { + complete_helper('/sample_files/creation.txt'); + monocle.watchPaths({ + path: [__dirname+"/sample_files/creation.txt"], + listener: function(f) { + cb_helper("creation.txt", f, complete) + }, + complete: function() { + complete_helper('/sample_files/creation.txt'); + } + }); + }); + + it("should not bomb when no callback is passed", function(complete) { + complete_helper('/sample_files/creation5.txt'); + monocle.watchPaths({ + path: [__dirname+"/sample_files/creation5.txt"], + complete: function() { + complete_helper('/sample_files/creation5.txt'); + } + }); + setTimeout(function() { + complete(); + }, 300) + }); +}); + +// +// watchPaths should accept a string or an array +// + +describe("different parameters of watchPaths", function() { + + it("can be a file", function(complete) { + monocle.watchPaths({ + path: sample_dir + "/foo.txt", + listener: function(f) { + cb_helper("foo.txt", f, complete); + }, + complete: function() { + complete_helper('/sample_files/foo.txt'); + } + }); + }); + + it("can be a directory", function(complete) { + monocle.watchPaths({ + path: sample_dir, + listener: function(f) { + cb_helper("foo.txt", f, complete); + }, + complete: function() { + complete_helper('/sample_files/foo.txt'); + } + }); + }); + + it("can be a list of directories", function(complete) { + monocle.watchPaths({ + path: [sample_dir], + listener: function(f) { + cb_helper("foo.txt", f, complete); + }, + complete: function() { + complete_helper('/sample_files/foo.txt'); + } + }); + }); + + it("can be a list of directories and a file", function(complete) { + monocle.watchPaths({ + path: [sample_dir + "/nestedDir", sample_dir + "/foo.txt"], + listener: function(f) { + cb_helper("foo.txt", f, complete); + }, + complete: function() { + complete_helper('/sample_files/foo.txt'); + } + }); + }); + + it("can be a list of files and a directory", function(complete) { + monocle.watchPaths({ + path: [sample_dir + "/foo.txt", sample_dir + "/nestedDir"], + listener: function(f) { + cb_helper("servent.txt", f, complete); + }, + complete: function() { + complete_helper('/sample_files/nestedDir/servent.txt'); + } + }); + }); +}); + + +// +// helpers +// + +function cb_helper(name, file, done){ + if (file.name === name) { monocle.unwatchAll(); done(); } +} + +function complete_helper(path){ + fs.writeFile(__dirname + path, (new Date).getTime() + "\n"); +} diff --git a/node_modules/jade/node_modules/transformers/.npmignore b/node_modules/jade/node_modules/transformers/.npmignore new file mode 100644 index 0000000..2a72174 --- /dev/null +++ b/node_modules/jade/node_modules/transformers/.npmignore @@ -0,0 +1,2 @@ +test/ +.travis.yml \ No newline at end of file diff --git a/node_modules/jade/node_modules/transformers/README.md b/node_modules/jade/node_modules/transformers/README.md new file mode 100644 index 0000000..0caf6d2 --- /dev/null +++ b/node_modules/jade/node_modules/transformers/README.md @@ -0,0 +1,141 @@ +[![Build Status](https://travis-ci.org/ForbesLindesay/transformers.png?branch=master)](https://travis-ci.org/ForbesLindesay/transformers) +# transformers + + String/Data transformations for use in templating libraries, static site generators and web frameworks. This gathers the most useful transformations you can apply to text or data into one library with a consistent API. Transformations can be pretty much anything but most are either compilers or templating engines. + +## Supported transforms + + To use each of these transforms you will also need to install the associated npm module for that transformer. + +### Template engines + + - [atpl](http://documentup.com/soywiz/atpl.js) - Compatible with twig templates + - [coffeecup](http://documentup.com/gradus/coffeecup) - pure coffee-script templates (fork of coffeekup) + - [dot](http://documentup.com/olado/doT) [(website)](https://github.com/Katahdin/dot-packer) - focused on speed + - [dust](http://documentup.com/akdubya/dustjs) [(website)](http://akdubya.github.com/dustjs/) - asyncronous templates + - [eco](http://documentup.com/sstephenson/eco) - Embedded CoffeeScript templates + - [ect](http://documentup.com/baryshev/ect) [(website)](http://ectjs.com/) - Embedded CoffeeScript templates + - [ejs](http://documentup.com/visionmedia/ejs) - Embedded JavaScript templates + - [haml](http://documentup.com/visionmedia/haml.js) [(website)](http://haml-lang.com/) - dry indented markup + - [haml-coffee](http://documentup.com/netzpirat/haml-coffee/) [(website)](http://haml-lang.com/) - haml with embedded CoffeeScript + - [handlebars](http://documentup.com/wycats/handlebars.js/) [(website)](http://handlebarsjs.com/) - extension of mustache templates + - [hogan](http://documentup.com/twitter/hogan.js) [(website)](http://twitter.github.com/hogan.js/) - Mustache templates + - [jade](http://documentup.com/visionmedia/jade) [(website)](http://jade-lang.com/) - robust, elegant, feature rich template engine + - [jazz](http://documentup.com/shinetech/jazz) + - [jqtpl](http://documentup.com/kof/jqtpl) [(website)](http://api.jquery.com/category/plugins/templates/) - extensible logic-less templates + - [JUST](http://documentup.com/baryshev/just) - EJS style template with some special syntax for layouts/partials etc. + - [liquor](http://documentup.com/chjj/liquor) - extended EJS with significant white space + - [mustache](http://documentup.com/janl/mustache.js) - logic less templates + - [QEJS](http://documentup.com/jepso/QEJS) - Promises + EJS for async templating + - [swig](http://documentup.com/paularmstrong/swig) [(website)](http://paularmstrong.github.com/swig/) - Django-like templating engine + - [templayed](http://documentup.com/archan937/templayed.js/) [(website)](http://archan937.github.com/templayed.js/) - Mustache focused on performance + - [toffee](http://documentup.com/malgorithms/toffee) - templating language based on coffeescript + - [underscore](http://documentup.com/documentcloud/underscore) [(website)](http://documentcloud.github.com/underscore/) + - [walrus](http://documentup.com/jeremyruppel/walrus) - A bolder kind of mustache + - [whiskers](http://documentup.com/gsf/whiskers.js/tree/) - logic-less focused on readability + +### Stylesheet Languages + + - [less](http://documentup.com/cloudhead/less.js) [(website)](http://lesscss.org/) - LESS extends CSS with dynamic behavior such as variables, mixins, operations and functions. + - [stylus](http://documentup.com/learnboost/stylus) [(website)](http://learnboost.github.com/stylus/) - revolutionary CSS generator making braces optional + - [sass](http://documentup.com/visionmedia/sass.js) [(website)](http://sass-lang.com/) - Sassy CSS + +### Minifiers + + - [uglify-js](http://documentup.com/mishoo/UglifyJS2) - No need to install anything, just minifies/beautifies JavaScript + - [uglify-css](https://github.com/visionmedia/css) - No need to install anything, just minifies/beautifies CSS + - ugilify-json - No need to install anything, just minifies/beautifies JSON + +### Other + + - cdata - No need to install anything, just wraps input as `` with the standard escape for `]]>` (`]]]]>`). + - cdata-js - as `cdata`, but with surrounding comments suitable for inclusion into a HTML/JavaScript ` + +``` + +## Documentation + +### Collections + +* [each](#each) +* [map](#map) +* [filter](#filter) +* [reject](#reject) +* [reduce](#reduce) +* [detect](#detect) +* [sortBy](#sortBy) +* [some](#some) +* [every](#every) +* [concat](#concat) + +### Control Flow + +* [series](#series) +* [parallel](#parallel) +* [whilst](#whilst) +* [doWhilst](#doWhilst) +* [until](#until) +* [doUntil](#doUntil) +* [forever](#forever) +* [waterfall](#waterfall) +* [compose](#compose) +* [applyEach](#applyEach) +* [queue](#queue) +* [cargo](#cargo) +* [auto](#auto) +* [iterator](#iterator) +* [apply](#apply) +* [nextTick](#nextTick) +* [times](#times) +* [timesSeries](#timesSeries) + +### Utils + +* [memoize](#memoize) +* [unmemoize](#unmemoize) +* [log](#log) +* [dir](#dir) +* [noConflict](#noConflict) + + +## Collections + + + +### each(arr, iterator, callback) + +Applies an iterator function to each item in an array, in parallel. +The iterator is called with an item from the list and a callback for when it +has finished. If the iterator passes an error to this callback, the main +callback for the each function is immediately called with the error. + +Note, that since this function applies the iterator to each item in parallel +there is no guarantee that the iterator functions will complete in order. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback(err) which must be called once it has + completed. If no error has occured, the callback should be run without + arguments or with an explicit null argument. +* callback(err) - A callback which is called after all the iterator functions + have finished, or an error has occurred. + +__Example__ + +```js +// assuming openFiles is an array of file names and saveFile is a function +// to save the modified contents of that file: + +async.each(openFiles, saveFile, function(err){ + // if any of the saves produced an error, err would equal that error +}); +``` + +--------------------------------------- + + + +### eachSeries(arr, iterator, callback) + +The same as each only the iterator is applied to each item in the array in +series. The next iterator is only called once the current one has completed +processing. This means the iterator functions will complete in order. + + +--------------------------------------- + + + +### eachLimit(arr, limit, iterator, callback) + +The same as each only no more than "limit" iterators will be simultaneously +running at any time. + +Note that the items are not processed in batches, so there is no guarantee that + the first "limit" iterator functions will complete before any others are +started. + +__Arguments__ + +* arr - An array to iterate over. +* limit - The maximum number of iterators to run at any time. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback(err) which must be called once it has + completed. If no error has occured, the callback should be run without + arguments or with an explicit null argument. +* callback(err) - A callback which is called after all the iterator functions + have finished, or an error has occurred. + +__Example__ + +```js +// Assume documents is an array of JSON objects and requestApi is a +// function that interacts with a rate-limited REST api. + +async.eachLimit(documents, 20, requestApi, function(err){ + // if any of the saves produced an error, err would equal that error +}); +``` + +--------------------------------------- + + +### map(arr, iterator, callback) + +Produces a new array of values by mapping each value in the given array through +the iterator function. The iterator is called with an item from the array and a +callback for when it has finished processing. The callback takes 2 arguments, +an error and the transformed item from the array. If the iterator passes an +error to this callback, the main callback for the map function is immediately +called with the error. + +Note, that since this function applies the iterator to each item in parallel +there is no guarantee that the iterator functions will complete in order, however +the results array will be in the same order as the original array. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback(err, transformed) which must be called once + it has completed with an error (which can be null) and a transformed item. +* callback(err, results) - A callback which is called after all the iterator + functions have finished, or an error has occurred. Results is an array of the + transformed items from the original array. + +__Example__ + +```js +async.map(['file1','file2','file3'], fs.stat, function(err, results){ + // results is now an array of stats for each file +}); +``` + +--------------------------------------- + + +### mapSeries(arr, iterator, callback) + +The same as map only the iterator is applied to each item in the array in +series. The next iterator is only called once the current one has completed +processing. The results array will be in the same order as the original. + + +--------------------------------------- + + +### mapLimit(arr, limit, iterator, callback) + +The same as map only no more than "limit" iterators will be simultaneously +running at any time. + +Note that the items are not processed in batches, so there is no guarantee that + the first "limit" iterator functions will complete before any others are +started. + +__Arguments__ + +* arr - An array to iterate over. +* limit - The maximum number of iterators to run at any time. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback(err, transformed) which must be called once + it has completed with an error (which can be null) and a transformed item. +* callback(err, results) - A callback which is called after all the iterator + functions have finished, or an error has occurred. Results is an array of the + transformed items from the original array. + +__Example__ + +```js +async.map(['file1','file2','file3'], 1, fs.stat, function(err, results){ + // results is now an array of stats for each file +}); +``` + +--------------------------------------- + + +### filter(arr, iterator, callback) + +__Alias:__ select + +Returns a new array of all the values which pass an async truth test. +_The callback for each iterator call only accepts a single argument of true or +false, it does not accept an error argument first!_ This is in-line with the +way node libraries work with truth tests like fs.exists. This operation is +performed in parallel, but the results array will be in the same order as the +original. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback(truthValue) which must be called with a + boolean argument once it has completed. +* callback(results) - A callback which is called after all the iterator + functions have finished. + +__Example__ + +```js +async.filter(['file1','file2','file3'], fs.exists, function(results){ + // results now equals an array of the existing files +}); +``` + +--------------------------------------- + + +### filterSeries(arr, iterator, callback) + +__alias:__ selectSeries + +The same as filter only the iterator is applied to each item in the array in +series. The next iterator is only called once the current one has completed +processing. The results array will be in the same order as the original. + +--------------------------------------- + + +### reject(arr, iterator, callback) + +The opposite of filter. Removes values that pass an async truth test. + +--------------------------------------- + + +### rejectSeries(arr, iterator, callback) + +The same as reject, only the iterator is applied to each item in the array +in series. + + +--------------------------------------- + + +### reduce(arr, memo, iterator, callback) + +__aliases:__ inject, foldl + +Reduces a list of values into a single value using an async iterator to return +each successive step. Memo is the initial state of the reduction. This +function only operates in series. For performance reasons, it may make sense to +split a call to this function into a parallel map, then use the normal +Array.prototype.reduce on the results. This function is for situations where +each step in the reduction needs to be async, if you can get the data before +reducing it then it's probably a good idea to do so. + +__Arguments__ + +* arr - An array to iterate over. +* memo - The initial state of the reduction. +* iterator(memo, item, callback) - A function applied to each item in the + array to produce the next step in the reduction. The iterator is passed a + callback(err, reduction) which accepts an optional error as its first + argument, and the state of the reduction as the second. If an error is + passed to the callback, the reduction is stopped and the main callback is + immediately called with the error. +* callback(err, result) - A callback which is called after all the iterator + functions have finished. Result is the reduced value. + +__Example__ + +```js +async.reduce([1,2,3], 0, function(memo, item, callback){ + // pointless async: + process.nextTick(function(){ + callback(null, memo + item) + }); +}, function(err, result){ + // result is now equal to the last value of memo, which is 6 +}); +``` + +--------------------------------------- + + +### reduceRight(arr, memo, iterator, callback) + +__Alias:__ foldr + +Same as reduce, only operates on the items in the array in reverse order. + + +--------------------------------------- + + +### detect(arr, iterator, callback) + +Returns the first value in a list that passes an async truth test. The +iterator is applied in parallel, meaning the first iterator to return true will +fire the detect callback with that result. That means the result might not be +the first item in the original array (in terms of order) that passes the test. + +If order within the original array is important then look at detectSeries. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback(truthValue) which must be called with a + boolean argument once it has completed. +* callback(result) - A callback which is called as soon as any iterator returns + true, or after all the iterator functions have finished. Result will be + the first item in the array that passes the truth test (iterator) or the + value undefined if none passed. + +__Example__ + +```js +async.detect(['file1','file2','file3'], fs.exists, function(result){ + // result now equals the first file in the list that exists +}); +``` + +--------------------------------------- + + +### detectSeries(arr, iterator, callback) + +The same as detect, only the iterator is applied to each item in the array +in series. This means the result is always the first in the original array (in +terms of array order) that passes the truth test. + + +--------------------------------------- + + +### sortBy(arr, iterator, callback) + +Sorts a list by the results of running each value through an async iterator. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback(err, sortValue) which must be called once it + has completed with an error (which can be null) and a value to use as the sort + criteria. +* callback(err, results) - A callback which is called after all the iterator + functions have finished, or an error has occurred. Results is the items from + the original array sorted by the values returned by the iterator calls. + +__Example__ + +```js +async.sortBy(['file1','file2','file3'], function(file, callback){ + fs.stat(file, function(err, stats){ + callback(err, stats.mtime); + }); +}, function(err, results){ + // results is now the original array of files sorted by + // modified date +}); +``` + +--------------------------------------- + + +### some(arr, iterator, callback) + +__Alias:__ any + +Returns true if at least one element in the array satisfies an async test. +_The callback for each iterator call only accepts a single argument of true or +false, it does not accept an error argument first!_ This is in-line with the +way node libraries work with truth tests like fs.exists. Once any iterator +call returns true, the main callback is immediately called. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback(truthValue) which must be called with a + boolean argument once it has completed. +* callback(result) - A callback which is called as soon as any iterator returns + true, or after all the iterator functions have finished. Result will be + either true or false depending on the values of the async tests. + +__Example__ + +```js +async.some(['file1','file2','file3'], fs.exists, function(result){ + // if result is true then at least one of the files exists +}); +``` + +--------------------------------------- + + +### every(arr, iterator, callback) + +__Alias:__ all + +Returns true if every element in the array satisfies an async test. +_The callback for each iterator call only accepts a single argument of true or +false, it does not accept an error argument first!_ This is in-line with the +way node libraries work with truth tests like fs.exists. + +__Arguments__ + +* arr - An array to iterate over. +* iterator(item, callback) - A truth test to apply to each item in the array. + The iterator is passed a callback(truthValue) which must be called with a + boolean argument once it has completed. +* callback(result) - A callback which is called after all the iterator + functions have finished. Result will be either true or false depending on + the values of the async tests. + +__Example__ + +```js +async.every(['file1','file2','file3'], fs.exists, function(result){ + // if result is true then every file exists +}); +``` + +--------------------------------------- + + +### concat(arr, iterator, callback) + +Applies an iterator to each item in a list, concatenating the results. Returns the +concatenated list. The iterators are called in parallel, and the results are +concatenated as they return. There is no guarantee that the results array will +be returned in the original order of the arguments passed to the iterator function. + +__Arguments__ + +* arr - An array to iterate over +* iterator(item, callback) - A function to apply to each item in the array. + The iterator is passed a callback(err, results) which must be called once it + has completed with an error (which can be null) and an array of results. +* callback(err, results) - A callback which is called after all the iterator + functions have finished, or an error has occurred. Results is an array containing + the concatenated results of the iterator function. + +__Example__ + +```js +async.concat(['dir1','dir2','dir3'], fs.readdir, function(err, files){ + // files is now a list of filenames that exist in the 3 directories +}); +``` + +--------------------------------------- + + +### concatSeries(arr, iterator, callback) + +Same as async.concat, but executes in series instead of parallel. + + +## Control Flow + + +### series(tasks, [callback]) + +Run an array of functions in series, each one running once the previous +function has completed. If any functions in the series pass an error to its +callback, no more functions are run and the callback for the series is +immediately called with the value of the error. Once the tasks have completed, +the results are passed to the final callback as an array. + +It is also possible to use an object instead of an array. Each property will be +run as a function and the results will be passed to the final callback as an object +instead of an array. This can be a more readable way of handling results from +async.series. + + +__Arguments__ + +* tasks - An array or object containing functions to run, each function is passed + a callback(err, result) it must call on completion with an error (which can + be null) and an optional result value. +* callback(err, results) - An optional callback to run once all the functions + have completed. This function gets a results array (or object) containing all + the result arguments passed to the task callbacks. + +__Example__ + +```js +async.series([ + function(callback){ + // do some stuff ... + callback(null, 'one'); + }, + function(callback){ + // do some more stuff ... + callback(null, 'two'); + } +], +// optional callback +function(err, results){ + // results is now equal to ['one', 'two'] +}); + + +// an example using an object instead of an array +async.series({ + one: function(callback){ + setTimeout(function(){ + callback(null, 1); + }, 200); + }, + two: function(callback){ + setTimeout(function(){ + callback(null, 2); + }, 100); + } +}, +function(err, results) { + // results is now equal to: {one: 1, two: 2} +}); +``` + +--------------------------------------- + + +### parallel(tasks, [callback]) + +Run an array of functions in parallel, without waiting until the previous +function has completed. If any of the functions pass an error to its +callback, the main callback is immediately called with the value of the error. +Once the tasks have completed, the results are passed to the final callback as an +array. + +It is also possible to use an object instead of an array. Each property will be +run as a function and the results will be passed to the final callback as an object +instead of an array. This can be a more readable way of handling results from +async.parallel. + + +__Arguments__ + +* tasks - An array or object containing functions to run, each function is passed + a callback(err, result) it must call on completion with an error (which can + be null) and an optional result value. +* callback(err, results) - An optional callback to run once all the functions + have completed. This function gets a results array (or object) containing all + the result arguments passed to the task callbacks. + +__Example__ + +```js +async.parallel([ + function(callback){ + setTimeout(function(){ + callback(null, 'one'); + }, 200); + }, + function(callback){ + setTimeout(function(){ + callback(null, 'two'); + }, 100); + } +], +// optional callback +function(err, results){ + // the results array will equal ['one','two'] even though + // the second function had a shorter timeout. +}); + + +// an example using an object instead of an array +async.parallel({ + one: function(callback){ + setTimeout(function(){ + callback(null, 1); + }, 200); + }, + two: function(callback){ + setTimeout(function(){ + callback(null, 2); + }, 100); + } +}, +function(err, results) { + // results is now equals to: {one: 1, two: 2} +}); +``` + +--------------------------------------- + + +### parallelLimit(tasks, limit, [callback]) + +The same as parallel only the tasks are executed in parallel with a maximum of "limit" +tasks executing at any time. + +Note that the tasks are not executed in batches, so there is no guarantee that +the first "limit" tasks will complete before any others are started. + +__Arguments__ + +* tasks - An array or object containing functions to run, each function is passed + a callback(err, result) it must call on completion with an error (which can + be null) and an optional result value. +* limit - The maximum number of tasks to run at any time. +* callback(err, results) - An optional callback to run once all the functions + have completed. This function gets a results array (or object) containing all + the result arguments passed to the task callbacks. + +--------------------------------------- + + +### whilst(test, fn, callback) + +Repeatedly call fn, while test returns true. Calls the callback when stopped, +or an error occurs. + +__Arguments__ + +* test() - synchronous truth test to perform before each execution of fn. +* fn(callback) - A function to call each time the test passes. The function is + passed a callback(err) which must be called once it has completed with an + optional error argument. +* callback(err) - A callback which is called after the test fails and repeated + execution of fn has stopped. + +__Example__ + +```js +var count = 0; + +async.whilst( + function () { return count < 5; }, + function (callback) { + count++; + setTimeout(callback, 1000); + }, + function (err) { + // 5 seconds have passed + } +); +``` + +--------------------------------------- + + +### doWhilst(fn, test, callback) + +The post check version of whilst. To reflect the difference in the order of operations `test` and `fn` arguments are switched. `doWhilst` is to `whilst` as `do while` is to `while` in plain JavaScript. + +--------------------------------------- + + +### until(test, fn, callback) + +Repeatedly call fn, until test returns true. Calls the callback when stopped, +or an error occurs. + +The inverse of async.whilst. + +--------------------------------------- + + +### doUntil(fn, test, callback) + +Like doWhilst except the test is inverted. Note the argument ordering differs from `until`. + +--------------------------------------- + + +### forever(fn, callback) + +Calls the asynchronous function 'fn' repeatedly, in series, indefinitely. +If an error is passed to fn's callback then 'callback' is called with the +error, otherwise it will never be called. + +--------------------------------------- + + +### waterfall(tasks, [callback]) + +Runs an array of functions in series, each passing their results to the next in +the array. However, if any of the functions pass an error to the callback, the +next function is not executed and the main callback is immediately called with +the error. + +__Arguments__ + +* tasks - An array of functions to run, each function is passed a + callback(err, result1, result2, ...) it must call on completion. The first + argument is an error (which can be null) and any further arguments will be + passed as arguments in order to the next task. +* callback(err, [results]) - An optional callback to run once all the functions + have completed. This will be passed the results of the last task's callback. + + + +__Example__ + +```js +async.waterfall([ + function(callback){ + callback(null, 'one', 'two'); + }, + function(arg1, arg2, callback){ + callback(null, 'three'); + }, + function(arg1, callback){ + // arg1 now equals 'three' + callback(null, 'done'); + } +], function (err, result) { + // result now equals 'done' +}); +``` + +--------------------------------------- + +### compose(fn1, fn2...) + +Creates a function which is a composition of the passed asynchronous +functions. Each function consumes the return value of the function that +follows. Composing functions f(), g() and h() would produce the result of +f(g(h())), only this version uses callbacks to obtain the return values. + +Each function is executed with the `this` binding of the composed function. + +__Arguments__ + +* functions... - the asynchronous functions to compose + + +__Example__ + +```js +function add1(n, callback) { + setTimeout(function () { + callback(null, n + 1); + }, 10); +} + +function mul3(n, callback) { + setTimeout(function () { + callback(null, n * 3); + }, 10); +} + +var add1mul3 = async.compose(mul3, add1); + +add1mul3(4, function (err, result) { + // result now equals 15 +}); +``` + +--------------------------------------- + +### applyEach(fns, args..., callback) + +Applies the provided arguments to each function in the array, calling the +callback after all functions have completed. If you only provide the first +argument then it will return a function which lets you pass in the +arguments as if it were a single function call. + +__Arguments__ + +* fns - the asynchronous functions to all call with the same arguments +* args... - any number of separate arguments to pass to the function +* callback - the final argument should be the callback, called when all + functions have completed processing + + +__Example__ + +```js +async.applyEach([enableSearch, updateSchema], 'bucket', callback); + +// partial application example: +async.each( + buckets, + async.applyEach([enableSearch, updateSchema]), + callback +); +``` + +--------------------------------------- + + +### applyEachSeries(arr, iterator, callback) + +The same as applyEach only the functions are applied in series. + +--------------------------------------- + + +### queue(worker, concurrency) + +Creates a queue object with the specified concurrency. Tasks added to the +queue will be processed in parallel (up to the concurrency limit). If all +workers are in progress, the task is queued until one is available. Once +a worker has completed a task, the task's callback is called. + +__Arguments__ + +* worker(task, callback) - An asynchronous function for processing a queued + task, which must call its callback(err) argument when finished, with an + optional error as an argument. +* concurrency - An integer for determining how many worker functions should be + run in parallel. + +__Queue objects__ + +The queue object returned by this function has the following properties and +methods: + +* length() - a function returning the number of items waiting to be processed. +* concurrency - an integer for determining how many worker functions should be + run in parallel. This property can be changed after a queue is created to + alter the concurrency on-the-fly. +* push(task, [callback]) - add a new task to the queue, the callback is called + once the worker has finished processing the task. + instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list. +* unshift(task, [callback]) - add a new task to the front of the queue. +* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued +* empty - a callback that is called when the last item from the queue is given to a worker +* drain - a callback that is called when the last item from the queue has returned from the worker + +__Example__ + +```js +// create a queue object with concurrency 2 + +var q = async.queue(function (task, callback) { + console.log('hello ' + task.name); + callback(); +}, 2); + + +// assign a callback +q.drain = function() { + console.log('all items have been processed'); +} + +// add some items to the queue + +q.push({name: 'foo'}, function (err) { + console.log('finished processing foo'); +}); +q.push({name: 'bar'}, function (err) { + console.log('finished processing bar'); +}); + +// add some items to the queue (batch-wise) + +q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function (err) { + console.log('finished processing bar'); +}); + +// add some items to the front of the queue + +q.unshift({name: 'bar'}, function (err) { + console.log('finished processing bar'); +}); +``` + +--------------------------------------- + + +### cargo(worker, [payload]) + +Creates a cargo object with the specified payload. Tasks added to the +cargo will be processed altogether (up to the payload limit). If the +worker is in progress, the task is queued until it is available. Once +the worker has completed some tasks, each callback of those tasks is called. + +__Arguments__ + +* worker(tasks, callback) - An asynchronous function for processing an array of + queued tasks, which must call its callback(err) argument when finished, with + an optional error as an argument. +* payload - An optional integer for determining how many tasks should be + processed per round; if omitted, the default is unlimited. + +__Cargo objects__ + +The cargo object returned by this function has the following properties and +methods: + +* length() - a function returning the number of items waiting to be processed. +* payload - an integer for determining how many tasks should be + process per round. This property can be changed after a cargo is created to + alter the payload on-the-fly. +* push(task, [callback]) - add a new task to the queue, the callback is called + once the worker has finished processing the task. + instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list. +* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued +* empty - a callback that is called when the last item from the queue is given to a worker +* drain - a callback that is called when the last item from the queue has returned from the worker + +__Example__ + +```js +// create a cargo object with payload 2 + +var cargo = async.cargo(function (tasks, callback) { + for(var i=0; i +### auto(tasks, [callback]) + +Determines the best order for running functions based on their requirements. +Each function can optionally depend on other functions being completed first, +and each function is run as soon as its requirements are satisfied. If any of +the functions pass an error to their callback, that function will not complete +(so any other functions depending on it will not run) and the main callback +will be called immediately with the error. Functions also receive an object +containing the results of functions which have completed so far. + +Note, all functions are called with a results object as a second argument, +so it is unsafe to pass functions in the tasks object which cannot handle the +extra argument. For example, this snippet of code: + +```js +async.auto({ + readData: async.apply(fs.readFile, 'data.txt', 'utf-8'); +}, callback); +``` + +will have the effect of calling readFile with the results object as the last +argument, which will fail: + +```js +fs.readFile('data.txt', 'utf-8', cb, {}); +``` + +Instead, wrap the call to readFile in a function which does not forward the +results object: + +```js +async.auto({ + readData: function(cb, results){ + fs.readFile('data.txt', 'utf-8', cb); + } +}, callback); +``` + +__Arguments__ + +* tasks - An object literal containing named functions or an array of + requirements, with the function itself the last item in the array. The key + used for each function or array is used when specifying requirements. The + function receives two arguments: (1) a callback(err, result) which must be + called when finished, passing an error (which can be null) and the result of + the function's execution, and (2) a results object, containing the results of + the previously executed functions. +* callback(err, results) - An optional callback which is called when all the + tasks have been completed. The callback will receive an error as an argument + if any tasks pass an error to their callback. Results will always be passed + but if an error occurred, no other tasks will be performed, and the results + object will only contain partial results. + + +__Example__ + +```js +async.auto({ + get_data: function(callback){ + // async code to get some data + }, + make_folder: function(callback){ + // async code to create a directory to store a file in + // this is run at the same time as getting the data + }, + write_file: ['get_data', 'make_folder', function(callback){ + // once there is some data and the directory exists, + // write the data to a file in the directory + callback(null, filename); + }], + email_link: ['write_file', function(callback, results){ + // once the file is written let's email a link to it... + // results.write_file contains the filename returned by write_file. + }] +}); +``` + +This is a fairly trivial example, but to do this using the basic parallel and +series functions would look like this: + +```js +async.parallel([ + function(callback){ + // async code to get some data + }, + function(callback){ + // async code to create a directory to store a file in + // this is run at the same time as getting the data + } +], +function(err, results){ + async.series([ + function(callback){ + // once there is some data and the directory exists, + // write the data to a file in the directory + }, + function(callback){ + // once the file is written let's email a link to it... + } + ]); +}); +``` + +For a complicated series of async tasks using the auto function makes adding +new tasks much easier and makes the code more readable. + + +--------------------------------------- + + +### iterator(tasks) + +Creates an iterator function which calls the next function in the array, +returning a continuation to call the next one after that. It's also possible to +'peek' the next iterator by doing iterator.next(). + +This function is used internally by the async module but can be useful when +you want to manually control the flow of functions in series. + +__Arguments__ + +* tasks - An array of functions to run. + +__Example__ + +```js +var iterator = async.iterator([ + function(){ sys.p('one'); }, + function(){ sys.p('two'); }, + function(){ sys.p('three'); } +]); + +node> var iterator2 = iterator(); +'one' +node> var iterator3 = iterator2(); +'two' +node> iterator3(); +'three' +node> var nextfn = iterator2.next(); +node> nextfn(); +'three' +``` + +--------------------------------------- + + +### apply(function, arguments..) + +Creates a continuation function with some arguments already applied, a useful +shorthand when combined with other control flow functions. Any arguments +passed to the returned function are added to the arguments originally passed +to apply. + +__Arguments__ + +* function - The function you want to eventually apply all arguments to. +* arguments... - Any number of arguments to automatically apply when the + continuation is called. + +__Example__ + +```js +// using apply + +async.parallel([ + async.apply(fs.writeFile, 'testfile1', 'test1'), + async.apply(fs.writeFile, 'testfile2', 'test2'), +]); + + +// the same process without using apply + +async.parallel([ + function(callback){ + fs.writeFile('testfile1', 'test1', callback); + }, + function(callback){ + fs.writeFile('testfile2', 'test2', callback); + } +]); +``` + +It's possible to pass any number of additional arguments when calling the +continuation: + +```js +node> var fn = async.apply(sys.puts, 'one'); +node> fn('two', 'three'); +one +two +three +``` + +--------------------------------------- + + +### nextTick(callback) + +Calls the callback on a later loop around the event loop. In node.js this just +calls process.nextTick, in the browser it falls back to setImmediate(callback) +if available, otherwise setTimeout(callback, 0), which means other higher priority +events may precede the execution of the callback. + +This is used internally for browser-compatibility purposes. + +__Arguments__ + +* callback - The function to call on a later loop around the event loop. + +__Example__ + +```js +var call_order = []; +async.nextTick(function(){ + call_order.push('two'); + // call_order now equals ['one','two'] +}); +call_order.push('one') +``` + + +### times(n, callback) + +Calls the callback n times and accumulates results in the same manner +you would use with async.map. + +__Arguments__ + +* n - The number of times to run the function. +* callback - The function to call n times. + +__Example__ + +```js +// Pretend this is some complicated async factory +var createUser = function(id, callback) { + callback(null, { + id: 'user' + id + }) +} +// generate 5 users +async.times(5, function(n, next){ + createUser(n, function(err, user) { + next(err, user) + }) +}, function(err, users) { + // we should now have 5 users +}); +``` + + +### timesSeries(n, callback) + +The same as times only the iterator is applied to each item in the array in +series. The next iterator is only called once the current one has completed +processing. The results array will be in the same order as the original. + + +## Utils + + +### memoize(fn, [hasher]) + +Caches the results of an async function. When creating a hash to store function +results against, the callback is omitted from the hash and an optional hash +function can be used. + +The cache of results is exposed as the `memo` property of the function returned +by `memoize`. + +__Arguments__ + +* fn - the function you to proxy and cache results from. +* hasher - an optional function for generating a custom hash for storing + results, it has all the arguments applied to it apart from the callback, and + must be synchronous. + +__Example__ + +```js +var slow_fn = function (name, callback) { + // do something + callback(null, result); +}; +var fn = async.memoize(slow_fn); + +// fn can now be used as if it were slow_fn +fn('some name', function () { + // callback +}); +``` + + +### unmemoize(fn) + +Undoes a memoized function, reverting it to the original, unmemoized +form. Comes handy in tests. + +__Arguments__ + +* fn - the memoized function + + +### log(function, arguments) + +Logs the result of an async function to the console. Only works in node.js or +in browsers that support console.log and console.error (such as FF and Chrome). +If multiple arguments are returned from the async function, console.log is +called on each argument in order. + +__Arguments__ + +* function - The function you want to eventually apply all arguments to. +* arguments... - Any number of arguments to apply to the function. + +__Example__ + +```js +var hello = function(name, callback){ + setTimeout(function(){ + callback(null, 'hello ' + name); + }, 1000); +}; +``` +```js +node> async.log(hello, 'world'); +'hello world' +``` + +--------------------------------------- + + +### dir(function, arguments) + +Logs the result of an async function to the console using console.dir to +display the properties of the resulting object. Only works in node.js or +in browsers that support console.dir and console.error (such as FF and Chrome). +If multiple arguments are returned from the async function, console.dir is +called on each argument in order. + +__Arguments__ + +* function - The function you want to eventually apply all arguments to. +* arguments... - Any number of arguments to apply to the function. + +__Example__ + +```js +var hello = function(name, callback){ + setTimeout(function(){ + callback(null, {hello: name}); + }, 1000); +}; +``` +```js +node> async.dir(hello, 'world'); +{hello: 'world'} +``` + +--------------------------------------- + + +### noConflict() + +Changes the value of async back to its original value, returning a reference to the +async object. diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/async/component.json b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/async/component.json new file mode 100644 index 0000000..bbb0115 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/async/component.json @@ -0,0 +1,11 @@ +{ + "name": "async", + "repo": "caolan/async", + "description": "Higher-order functions and common patterns for asynchronous code", + "version": "0.1.23", + "keywords": [], + "dependencies": {}, + "development": {}, + "main": "lib/async.js", + "scripts": [ "lib/async.js" ] +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/async/lib/async.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/async/lib/async.js new file mode 100755 index 0000000..cb6320d --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/async/lib/async.js @@ -0,0 +1,955 @@ +/*global setImmediate: false, setTimeout: false, console: false */ +(function () { + + var async = {}; + + // global on the server, window in the browser + var root, previous_async; + + root = this; + if (root != null) { + previous_async = root.async; + } + + async.noConflict = function () { + root.async = previous_async; + return async; + }; + + function only_once(fn) { + var called = false; + return function() { + if (called) throw new Error("Callback was already called."); + called = true; + fn.apply(root, arguments); + } + } + + //// cross-browser compatiblity functions //// + + var _each = function (arr, iterator) { + if (arr.forEach) { + return arr.forEach(iterator); + } + for (var i = 0; i < arr.length; i += 1) { + iterator(arr[i], i, arr); + } + }; + + var _map = function (arr, iterator) { + if (arr.map) { + return arr.map(iterator); + } + var results = []; + _each(arr, function (x, i, a) { + results.push(iterator(x, i, a)); + }); + return results; + }; + + var _reduce = function (arr, iterator, memo) { + if (arr.reduce) { + return arr.reduce(iterator, memo); + } + _each(arr, function (x, i, a) { + memo = iterator(memo, x, i, a); + }); + return memo; + }; + + var _keys = function (obj) { + if (Object.keys) { + return Object.keys(obj); + } + var keys = []; + for (var k in obj) { + if (obj.hasOwnProperty(k)) { + keys.push(k); + } + } + return keys; + }; + + //// exported async module functions //// + + //// nextTick implementation with browser-compatible fallback //// + if (typeof process === 'undefined' || !(process.nextTick)) { + if (typeof setImmediate === 'function') { + async.nextTick = function (fn) { + // not a direct alias for IE10 compatibility + setImmediate(fn); + }; + async.setImmediate = async.nextTick; + } + else { + async.nextTick = function (fn) { + setTimeout(fn, 0); + }; + async.setImmediate = async.nextTick; + } + } + else { + async.nextTick = process.nextTick; + if (typeof setImmediate !== 'undefined') { + async.setImmediate = setImmediate; + } + else { + async.setImmediate = async.nextTick; + } + } + + async.each = function (arr, iterator, callback) { + callback = callback || function () {}; + if (!arr.length) { + return callback(); + } + var completed = 0; + _each(arr, function (x) { + iterator(x, only_once(function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + if (completed >= arr.length) { + callback(null); + } + } + })); + }); + }; + async.forEach = async.each; + + async.eachSeries = function (arr, iterator, callback) { + callback = callback || function () {}; + if (!arr.length) { + return callback(); + } + var completed = 0; + var iterate = function () { + iterator(arr[completed], function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + if (completed >= arr.length) { + callback(null); + } + else { + iterate(); + } + } + }); + }; + iterate(); + }; + async.forEachSeries = async.eachSeries; + + async.eachLimit = function (arr, limit, iterator, callback) { + var fn = _eachLimit(limit); + fn.apply(null, [arr, iterator, callback]); + }; + async.forEachLimit = async.eachLimit; + + var _eachLimit = function (limit) { + + return function (arr, iterator, callback) { + callback = callback || function () {}; + if (!arr.length || limit <= 0) { + return callback(); + } + var completed = 0; + var started = 0; + var running = 0; + + (function replenish () { + if (completed >= arr.length) { + return callback(); + } + + while (running < limit && started < arr.length) { + started += 1; + running += 1; + iterator(arr[started - 1], function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + running -= 1; + if (completed >= arr.length) { + callback(); + } + else { + replenish(); + } + } + }); + } + })(); + }; + }; + + + var doParallel = function (fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [async.each].concat(args)); + }; + }; + var doParallelLimit = function(limit, fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [_eachLimit(limit)].concat(args)); + }; + }; + var doSeries = function (fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [async.eachSeries].concat(args)); + }; + }; + + + var _asyncMap = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (err, v) { + results[x.index] = v; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + }; + async.map = doParallel(_asyncMap); + async.mapSeries = doSeries(_asyncMap); + async.mapLimit = function (arr, limit, iterator, callback) { + return _mapLimit(limit)(arr, iterator, callback); + }; + + var _mapLimit = function(limit) { + return doParallelLimit(limit, _asyncMap); + }; + + // reduce only has a series version, as doing reduce in parallel won't + // work in many situations. + async.reduce = function (arr, memo, iterator, callback) { + async.eachSeries(arr, function (x, callback) { + iterator(memo, x, function (err, v) { + memo = v; + callback(err); + }); + }, function (err) { + callback(err, memo); + }); + }; + // inject alias + async.inject = async.reduce; + // foldl alias + async.foldl = async.reduce; + + async.reduceRight = function (arr, memo, iterator, callback) { + var reversed = _map(arr, function (x) { + return x; + }).reverse(); + async.reduce(reversed, memo, iterator, callback); + }; + // foldr alias + async.foldr = async.reduceRight; + + var _filter = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (v) { + if (v) { + results.push(x); + } + callback(); + }); + }, function (err) { + callback(_map(results.sort(function (a, b) { + return a.index - b.index; + }), function (x) { + return x.value; + })); + }); + }; + async.filter = doParallel(_filter); + async.filterSeries = doSeries(_filter); + // select alias + async.select = async.filter; + async.selectSeries = async.filterSeries; + + var _reject = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (v) { + if (!v) { + results.push(x); + } + callback(); + }); + }, function (err) { + callback(_map(results.sort(function (a, b) { + return a.index - b.index; + }), function (x) { + return x.value; + })); + }); + }; + async.reject = doParallel(_reject); + async.rejectSeries = doSeries(_reject); + + var _detect = function (eachfn, arr, iterator, main_callback) { + eachfn(arr, function (x, callback) { + iterator(x, function (result) { + if (result) { + main_callback(x); + main_callback = function () {}; + } + else { + callback(); + } + }); + }, function (err) { + main_callback(); + }); + }; + async.detect = doParallel(_detect); + async.detectSeries = doSeries(_detect); + + async.some = function (arr, iterator, main_callback) { + async.each(arr, function (x, callback) { + iterator(x, function (v) { + if (v) { + main_callback(true); + main_callback = function () {}; + } + callback(); + }); + }, function (err) { + main_callback(false); + }); + }; + // any alias + async.any = async.some; + + async.every = function (arr, iterator, main_callback) { + async.each(arr, function (x, callback) { + iterator(x, function (v) { + if (!v) { + main_callback(false); + main_callback = function () {}; + } + callback(); + }); + }, function (err) { + main_callback(true); + }); + }; + // all alias + async.all = async.every; + + async.sortBy = function (arr, iterator, callback) { + async.map(arr, function (x, callback) { + iterator(x, function (err, criteria) { + if (err) { + callback(err); + } + else { + callback(null, {value: x, criteria: criteria}); + } + }); + }, function (err, results) { + if (err) { + return callback(err); + } + else { + var fn = function (left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }; + callback(null, _map(results.sort(fn), function (x) { + return x.value; + })); + } + }); + }; + + async.auto = function (tasks, callback) { + callback = callback || function () {}; + var keys = _keys(tasks); + if (!keys.length) { + return callback(null); + } + + var results = {}; + + var listeners = []; + var addListener = function (fn) { + listeners.unshift(fn); + }; + var removeListener = function (fn) { + for (var i = 0; i < listeners.length; i += 1) { + if (listeners[i] === fn) { + listeners.splice(i, 1); + return; + } + } + }; + var taskComplete = function () { + _each(listeners.slice(0), function (fn) { + fn(); + }); + }; + + addListener(function () { + if (_keys(results).length === keys.length) { + callback(null, results); + callback = function () {}; + } + }); + + _each(keys, function (k) { + var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k]; + var taskCallback = function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + if (err) { + var safeResults = {}; + _each(_keys(results), function(rkey) { + safeResults[rkey] = results[rkey]; + }); + safeResults[k] = args; + callback(err, safeResults); + // stop subsequent errors hitting callback multiple times + callback = function () {}; + } + else { + results[k] = args; + async.setImmediate(taskComplete); + } + }; + var requires = task.slice(0, Math.abs(task.length - 1)) || []; + var ready = function () { + return _reduce(requires, function (a, x) { + return (a && results.hasOwnProperty(x)); + }, true) && !results.hasOwnProperty(k); + }; + if (ready()) { + task[task.length - 1](taskCallback, results); + } + else { + var listener = function () { + if (ready()) { + removeListener(listener); + task[task.length - 1](taskCallback, results); + } + }; + addListener(listener); + } + }); + }; + + async.waterfall = function (tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor !== Array) { + var err = new Error('First argument to waterfall must be an array of functions'); + return callback(err); + } + if (!tasks.length) { + return callback(); + } + var wrapIterator = function (iterator) { + return function (err) { + if (err) { + callback.apply(null, arguments); + callback = function () {}; + } + else { + var args = Array.prototype.slice.call(arguments, 1); + var next = iterator.next(); + if (next) { + args.push(wrapIterator(next)); + } + else { + args.push(callback); + } + async.setImmediate(function () { + iterator.apply(null, args); + }); + } + }; + }; + wrapIterator(async.iterator(tasks))(); + }; + + var _parallel = function(eachfn, tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor === Array) { + eachfn.map(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args); + }); + } + }, callback); + } + else { + var results = {}; + eachfn.each(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.parallel = function (tasks, callback) { + _parallel({ map: async.map, each: async.each }, tasks, callback); + }; + + async.parallelLimit = function(tasks, limit, callback) { + _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback); + }; + + async.series = function (tasks, callback) { + callback = callback || function () {}; + if (tasks.constructor === Array) { + async.mapSeries(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args); + }); + } + }, callback); + } + else { + var results = {}; + async.eachSeries(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.iterator = function (tasks) { + var makeCallback = function (index) { + var fn = function () { + if (tasks.length) { + tasks[index].apply(null, arguments); + } + return fn.next(); + }; + fn.next = function () { + return (index < tasks.length - 1) ? makeCallback(index + 1): null; + }; + return fn; + }; + return makeCallback(0); + }; + + async.apply = function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + return function () { + return fn.apply( + null, args.concat(Array.prototype.slice.call(arguments)) + ); + }; + }; + + var _concat = function (eachfn, arr, fn, callback) { + var r = []; + eachfn(arr, function (x, cb) { + fn(x, function (err, y) { + r = r.concat(y || []); + cb(err); + }); + }, function (err) { + callback(err, r); + }); + }; + async.concat = doParallel(_concat); + async.concatSeries = doSeries(_concat); + + async.whilst = function (test, iterator, callback) { + if (test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.whilst(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.doWhilst = function (iterator, test, callback) { + iterator(function (err) { + if (err) { + return callback(err); + } + if (test()) { + async.doWhilst(iterator, test, callback); + } + else { + callback(); + } + }); + }; + + async.until = function (test, iterator, callback) { + if (!test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.until(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.doUntil = function (iterator, test, callback) { + iterator(function (err) { + if (err) { + return callback(err); + } + if (!test()) { + async.doUntil(iterator, test, callback); + } + else { + callback(); + } + }); + }; + + async.queue = function (worker, concurrency) { + if (concurrency === undefined) { + concurrency = 1; + } + function _insert(q, data, pos, callback) { + if(data.constructor !== Array) { + data = [data]; + } + _each(data, function(task) { + var item = { + data: task, + callback: typeof callback === 'function' ? callback : null + }; + + if (pos) { + q.tasks.unshift(item); + } else { + q.tasks.push(item); + } + + if (q.saturated && q.tasks.length === concurrency) { + q.saturated(); + } + async.setImmediate(q.process); + }); + } + + var workers = 0; + var q = { + tasks: [], + concurrency: concurrency, + saturated: null, + empty: null, + drain: null, + push: function (data, callback) { + _insert(q, data, false, callback); + }, + unshift: function (data, callback) { + _insert(q, data, true, callback); + }, + process: function () { + if (workers < q.concurrency && q.tasks.length) { + var task = q.tasks.shift(); + if (q.empty && q.tasks.length === 0) { + q.empty(); + } + workers += 1; + var next = function () { + workers -= 1; + if (task.callback) { + task.callback.apply(task, arguments); + } + if (q.drain && q.tasks.length + workers === 0) { + q.drain(); + } + q.process(); + }; + var cb = only_once(next); + worker(task.data, cb); + } + }, + length: function () { + return q.tasks.length; + }, + running: function () { + return workers; + } + }; + return q; + }; + + async.cargo = function (worker, payload) { + var working = false, + tasks = []; + + var cargo = { + tasks: tasks, + payload: payload, + saturated: null, + empty: null, + drain: null, + push: function (data, callback) { + if(data.constructor !== Array) { + data = [data]; + } + _each(data, function(task) { + tasks.push({ + data: task, + callback: typeof callback === 'function' ? callback : null + }); + if (cargo.saturated && tasks.length === payload) { + cargo.saturated(); + } + }); + async.setImmediate(cargo.process); + }, + process: function process() { + if (working) return; + if (tasks.length === 0) { + if(cargo.drain) cargo.drain(); + return; + } + + var ts = typeof payload === 'number' + ? tasks.splice(0, payload) + : tasks.splice(0); + + var ds = _map(ts, function (task) { + return task.data; + }); + + if(cargo.empty) cargo.empty(); + working = true; + worker(ds, function () { + working = false; + + var args = arguments; + _each(ts, function (data) { + if (data.callback) { + data.callback.apply(null, args); + } + }); + + process(); + }); + }, + length: function () { + return tasks.length; + }, + running: function () { + return working; + } + }; + return cargo; + }; + + var _console_fn = function (name) { + return function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + fn.apply(null, args.concat([function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (typeof console !== 'undefined') { + if (err) { + if (console.error) { + console.error(err); + } + } + else if (console[name]) { + _each(args, function (x) { + console[name](x); + }); + } + } + }])); + }; + }; + async.log = _console_fn('log'); + async.dir = _console_fn('dir'); + /*async.info = _console_fn('info'); + async.warn = _console_fn('warn'); + async.error = _console_fn('error');*/ + + async.memoize = function (fn, hasher) { + var memo = {}; + var queues = {}; + hasher = hasher || function (x) { + return x; + }; + var memoized = function () { + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + var key = hasher.apply(null, args); + if (key in memo) { + callback.apply(null, memo[key]); + } + else if (key in queues) { + queues[key].push(callback); + } + else { + queues[key] = [callback]; + fn.apply(null, args.concat([function () { + memo[key] = arguments; + var q = queues[key]; + delete queues[key]; + for (var i = 0, l = q.length; i < l; i++) { + q[i].apply(null, arguments); + } + }])); + } + }; + memoized.memo = memo; + memoized.unmemoized = fn; + return memoized; + }; + + async.unmemoize = function (fn) { + return function () { + return (fn.unmemoized || fn).apply(null, arguments); + }; + }; + + async.times = function (count, iterator, callback) { + var counter = []; + for (var i = 0; i < count; i++) { + counter.push(i); + } + return async.map(counter, iterator, callback); + }; + + async.timesSeries = function (count, iterator, callback) { + var counter = []; + for (var i = 0; i < count; i++) { + counter.push(i); + } + return async.mapSeries(counter, iterator, callback); + }; + + async.compose = function (/* functions... */) { + var fns = Array.prototype.reverse.call(arguments); + return function () { + var that = this; + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + async.reduce(fns, args, function (newargs, fn, cb) { + fn.apply(that, newargs.concat([function () { + var err = arguments[0]; + var nextargs = Array.prototype.slice.call(arguments, 1); + cb(err, nextargs); + }])) + }, + function (err, results) { + callback.apply(that, [err].concat(results)); + }); + }; + }; + + var _applyEach = function (eachfn, fns /*args...*/) { + var go = function () { + var that = this; + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + return eachfn(fns, function (fn, cb) { + fn.apply(that, args.concat([cb])); + }, + callback); + }; + if (arguments.length > 2) { + var args = Array.prototype.slice.call(arguments, 2); + return go.apply(this, args); + } + else { + return go; + } + }; + async.applyEach = doParallel(_applyEach); + async.applyEachSeries = doSeries(_applyEach); + + async.forever = function (fn, callback) { + function next(err) { + if (err) { + if (callback) { + return callback(err); + } + throw err; + } + fn(next); + } + next(); + }; + + // AMD / RequireJS + if (typeof define !== 'undefined' && define.amd) { + define([], function () { + return async; + }); + } + // Node.js + else if (typeof module !== 'undefined' && module.exports) { + module.exports = async; + } + // included directly via \n\n```\n\n## Documentation\n\n### Collections\n\n* [each](#each)\n* [map](#map)\n* [filter](#filter)\n* [reject](#reject)\n* [reduce](#reduce)\n* [detect](#detect)\n* [sortBy](#sortBy)\n* [some](#some)\n* [every](#every)\n* [concat](#concat)\n\n### Control Flow\n\n* [series](#series)\n* [parallel](#parallel)\n* [whilst](#whilst)\n* [doWhilst](#doWhilst)\n* [until](#until)\n* [doUntil](#doUntil)\n* [forever](#forever)\n* [waterfall](#waterfall)\n* [compose](#compose)\n* [applyEach](#applyEach)\n* [queue](#queue)\n* [cargo](#cargo)\n* [auto](#auto)\n* [iterator](#iterator)\n* [apply](#apply)\n* [nextTick](#nextTick)\n* [times](#times)\n* [timesSeries](#timesSeries)\n\n### Utils\n\n* [memoize](#memoize)\n* [unmemoize](#unmemoize)\n* [log](#log)\n* [dir](#dir)\n* [noConflict](#noConflict)\n\n\n## Collections\n\n\n\n### each(arr, iterator, callback)\n\nApplies an iterator function to each item in an array, in parallel.\nThe iterator is called with an item from the list and a callback for when it\nhas finished. If the iterator passes an error to this callback, the main\ncallback for the each function is immediately called with the error.\n\nNote, that since this function applies the iterator to each item in parallel\nthere is no guarantee that the iterator functions will complete in order.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback(err) which must be called once it has \n completed. If no error has occured, the callback should be run without \n arguments or with an explicit null argument.\n* callback(err) - A callback which is called after all the iterator functions\n have finished, or an error has occurred.\n\n__Example__\n\n```js\n// assuming openFiles is an array of file names and saveFile is a function\n// to save the modified contents of that file:\n\nasync.each(openFiles, saveFile, function(err){\n // if any of the saves produced an error, err would equal that error\n});\n```\n\n---------------------------------------\n\n\n\n### eachSeries(arr, iterator, callback)\n\nThe same as each only the iterator is applied to each item in the array in\nseries. The next iterator is only called once the current one has completed\nprocessing. This means the iterator functions will complete in order.\n\n\n---------------------------------------\n\n\n\n### eachLimit(arr, limit, iterator, callback)\n\nThe same as each only no more than \"limit\" iterators will be simultaneously \nrunning at any time.\n\nNote that the items are not processed in batches, so there is no guarantee that\n the first \"limit\" iterator functions will complete before any others are \nstarted.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* limit - The maximum number of iterators to run at any time.\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback(err) which must be called once it has \n completed. If no error has occured, the callback should be run without \n arguments or with an explicit null argument.\n* callback(err) - A callback which is called after all the iterator functions\n have finished, or an error has occurred.\n\n__Example__\n\n```js\n// Assume documents is an array of JSON objects and requestApi is a\n// function that interacts with a rate-limited REST api.\n\nasync.eachLimit(documents, 20, requestApi, function(err){\n // if any of the saves produced an error, err would equal that error\n});\n```\n\n---------------------------------------\n\n\n### map(arr, iterator, callback)\n\nProduces a new array of values by mapping each value in the given array through\nthe iterator function. The iterator is called with an item from the array and a\ncallback for when it has finished processing. The callback takes 2 arguments, \nan error and the transformed item from the array. If the iterator passes an\nerror to this callback, the main callback for the map function is immediately\ncalled with the error.\n\nNote, that since this function applies the iterator to each item in parallel\nthere is no guarantee that the iterator functions will complete in order, however\nthe results array will be in the same order as the original array.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback(err, transformed) which must be called once \n it has completed with an error (which can be null) and a transformed item.\n* callback(err, results) - A callback which is called after all the iterator\n functions have finished, or an error has occurred. Results is an array of the\n transformed items from the original array.\n\n__Example__\n\n```js\nasync.map(['file1','file2','file3'], fs.stat, function(err, results){\n // results is now an array of stats for each file\n});\n```\n\n---------------------------------------\n\n\n### mapSeries(arr, iterator, callback)\n\nThe same as map only the iterator is applied to each item in the array in\nseries. The next iterator is only called once the current one has completed\nprocessing. The results array will be in the same order as the original.\n\n\n---------------------------------------\n\n\n### mapLimit(arr, limit, iterator, callback)\n\nThe same as map only no more than \"limit\" iterators will be simultaneously \nrunning at any time.\n\nNote that the items are not processed in batches, so there is no guarantee that\n the first \"limit\" iterator functions will complete before any others are \nstarted.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* limit - The maximum number of iterators to run at any time.\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback(err, transformed) which must be called once \n it has completed with an error (which can be null) and a transformed item.\n* callback(err, results) - A callback which is called after all the iterator\n functions have finished, or an error has occurred. Results is an array of the\n transformed items from the original array.\n\n__Example__\n\n```js\nasync.map(['file1','file2','file3'], 1, fs.stat, function(err, results){\n // results is now an array of stats for each file\n});\n```\n\n---------------------------------------\n\n\n### filter(arr, iterator, callback)\n\n__Alias:__ select\n\nReturns a new array of all the values which pass an async truth test.\n_The callback for each iterator call only accepts a single argument of true or\nfalse, it does not accept an error argument first!_ This is in-line with the\nway node libraries work with truth tests like fs.exists. This operation is\nperformed in parallel, but the results array will be in the same order as the\noriginal.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n The iterator is passed a callback(truthValue) which must be called with a \n boolean argument once it has completed.\n* callback(results) - A callback which is called after all the iterator\n functions have finished.\n\n__Example__\n\n```js\nasync.filter(['file1','file2','file3'], fs.exists, function(results){\n // results now equals an array of the existing files\n});\n```\n\n---------------------------------------\n\n\n### filterSeries(arr, iterator, callback)\n\n__alias:__ selectSeries\n\nThe same as filter only the iterator is applied to each item in the array in\nseries. The next iterator is only called once the current one has completed\nprocessing. The results array will be in the same order as the original.\n\n---------------------------------------\n\n\n### reject(arr, iterator, callback)\n\nThe opposite of filter. Removes values that pass an async truth test.\n\n---------------------------------------\n\n\n### rejectSeries(arr, iterator, callback)\n\nThe same as reject, only the iterator is applied to each item in the array\nin series.\n\n\n---------------------------------------\n\n\n### reduce(arr, memo, iterator, callback)\n\n__aliases:__ inject, foldl\n\nReduces a list of values into a single value using an async iterator to return\neach successive step. Memo is the initial state of the reduction. This\nfunction only operates in series. For performance reasons, it may make sense to\nsplit a call to this function into a parallel map, then use the normal\nArray.prototype.reduce on the results. This function is for situations where\neach step in the reduction needs to be async, if you can get the data before\nreducing it then it's probably a good idea to do so.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* memo - The initial state of the reduction.\n* iterator(memo, item, callback) - A function applied to each item in the\n array to produce the next step in the reduction. The iterator is passed a\n callback(err, reduction) which accepts an optional error as its first \n argument, and the state of the reduction as the second. If an error is \n passed to the callback, the reduction is stopped and the main callback is \n immediately called with the error.\n* callback(err, result) - A callback which is called after all the iterator\n functions have finished. Result is the reduced value.\n\n__Example__\n\n```js\nasync.reduce([1,2,3], 0, function(memo, item, callback){\n // pointless async:\n process.nextTick(function(){\n callback(null, memo + item)\n });\n}, function(err, result){\n // result is now equal to the last value of memo, which is 6\n});\n```\n\n---------------------------------------\n\n\n### reduceRight(arr, memo, iterator, callback)\n\n__Alias:__ foldr\n\nSame as reduce, only operates on the items in the array in reverse order.\n\n\n---------------------------------------\n\n\n### detect(arr, iterator, callback)\n\nReturns the first value in a list that passes an async truth test. The\niterator is applied in parallel, meaning the first iterator to return true will\nfire the detect callback with that result. That means the result might not be\nthe first item in the original array (in terms of order) that passes the test.\n\nIf order within the original array is important then look at detectSeries.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n The iterator is passed a callback(truthValue) which must be called with a \n boolean argument once it has completed.\n* callback(result) - A callback which is called as soon as any iterator returns\n true, or after all the iterator functions have finished. Result will be\n the first item in the array that passes the truth test (iterator) or the\n value undefined if none passed.\n\n__Example__\n\n```js\nasync.detect(['file1','file2','file3'], fs.exists, function(result){\n // result now equals the first file in the list that exists\n});\n```\n\n---------------------------------------\n\n\n### detectSeries(arr, iterator, callback)\n\nThe same as detect, only the iterator is applied to each item in the array\nin series. This means the result is always the first in the original array (in\nterms of array order) that passes the truth test.\n\n\n---------------------------------------\n\n\n### sortBy(arr, iterator, callback)\n\nSorts a list by the results of running each value through an async iterator.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback(err, sortValue) which must be called once it\n has completed with an error (which can be null) and a value to use as the sort\n criteria.\n* callback(err, results) - A callback which is called after all the iterator\n functions have finished, or an error has occurred. Results is the items from\n the original array sorted by the values returned by the iterator calls.\n\n__Example__\n\n```js\nasync.sortBy(['file1','file2','file3'], function(file, callback){\n fs.stat(file, function(err, stats){\n callback(err, stats.mtime);\n });\n}, function(err, results){\n // results is now the original array of files sorted by\n // modified date\n});\n```\n\n---------------------------------------\n\n\n### some(arr, iterator, callback)\n\n__Alias:__ any\n\nReturns true if at least one element in the array satisfies an async test.\n_The callback for each iterator call only accepts a single argument of true or\nfalse, it does not accept an error argument first!_ This is in-line with the\nway node libraries work with truth tests like fs.exists. Once any iterator\ncall returns true, the main callback is immediately called.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n The iterator is passed a callback(truthValue) which must be called with a \n boolean argument once it has completed.\n* callback(result) - A callback which is called as soon as any iterator returns\n true, or after all the iterator functions have finished. Result will be\n either true or false depending on the values of the async tests.\n\n__Example__\n\n```js\nasync.some(['file1','file2','file3'], fs.exists, function(result){\n // if result is true then at least one of the files exists\n});\n```\n\n---------------------------------------\n\n\n### every(arr, iterator, callback)\n\n__Alias:__ all\n\nReturns true if every element in the array satisfies an async test.\n_The callback for each iterator call only accepts a single argument of true or\nfalse, it does not accept an error argument first!_ This is in-line with the\nway node libraries work with truth tests like fs.exists.\n\n__Arguments__\n\n* arr - An array to iterate over.\n* iterator(item, callback) - A truth test to apply to each item in the array.\n The iterator is passed a callback(truthValue) which must be called with a \n boolean argument once it has completed.\n* callback(result) - A callback which is called after all the iterator\n functions have finished. Result will be either true or false depending on\n the values of the async tests.\n\n__Example__\n\n```js\nasync.every(['file1','file2','file3'], fs.exists, function(result){\n // if result is true then every file exists\n});\n```\n\n---------------------------------------\n\n\n### concat(arr, iterator, callback)\n\nApplies an iterator to each item in a list, concatenating the results. Returns the\nconcatenated list. The iterators are called in parallel, and the results are\nconcatenated as they return. There is no guarantee that the results array will\nbe returned in the original order of the arguments passed to the iterator function.\n\n__Arguments__\n\n* arr - An array to iterate over\n* iterator(item, callback) - A function to apply to each item in the array.\n The iterator is passed a callback(err, results) which must be called once it \n has completed with an error (which can be null) and an array of results.\n* callback(err, results) - A callback which is called after all the iterator\n functions have finished, or an error has occurred. Results is an array containing\n the concatenated results of the iterator function.\n\n__Example__\n\n```js\nasync.concat(['dir1','dir2','dir3'], fs.readdir, function(err, files){\n // files is now a list of filenames that exist in the 3 directories\n});\n```\n\n---------------------------------------\n\n\n### concatSeries(arr, iterator, callback)\n\nSame as async.concat, but executes in series instead of parallel.\n\n\n## Control Flow\n\n\n### series(tasks, [callback])\n\nRun an array of functions in series, each one running once the previous\nfunction has completed. If any functions in the series pass an error to its\ncallback, no more functions are run and the callback for the series is\nimmediately called with the value of the error. Once the tasks have completed,\nthe results are passed to the final callback as an array.\n\nIt is also possible to use an object instead of an array. Each property will be\nrun as a function and the results will be passed to the final callback as an object\ninstead of an array. This can be a more readable way of handling results from\nasync.series.\n\n\n__Arguments__\n\n* tasks - An array or object containing functions to run, each function is passed\n a callback(err, result) it must call on completion with an error (which can\n be null) and an optional result value.\n* callback(err, results) - An optional callback to run once all the functions\n have completed. This function gets a results array (or object) containing all \n the result arguments passed to the task callbacks.\n\n__Example__\n\n```js\nasync.series([\n function(callback){\n // do some stuff ...\n callback(null, 'one');\n },\n function(callback){\n // do some more stuff ...\n callback(null, 'two');\n }\n],\n// optional callback\nfunction(err, results){\n // results is now equal to ['one', 'two']\n});\n\n\n// an example using an object instead of an array\nasync.series({\n one: function(callback){\n setTimeout(function(){\n callback(null, 1);\n }, 200);\n },\n two: function(callback){\n setTimeout(function(){\n callback(null, 2);\n }, 100);\n }\n},\nfunction(err, results) {\n // results is now equal to: {one: 1, two: 2}\n});\n```\n\n---------------------------------------\n\n\n### parallel(tasks, [callback])\n\nRun an array of functions in parallel, without waiting until the previous\nfunction has completed. If any of the functions pass an error to its\ncallback, the main callback is immediately called with the value of the error.\nOnce the tasks have completed, the results are passed to the final callback as an\narray.\n\nIt is also possible to use an object instead of an array. Each property will be\nrun as a function and the results will be passed to the final callback as an object\ninstead of an array. This can be a more readable way of handling results from\nasync.parallel.\n\n\n__Arguments__\n\n* tasks - An array or object containing functions to run, each function is passed \n a callback(err, result) it must call on completion with an error (which can\n be null) and an optional result value.\n* callback(err, results) - An optional callback to run once all the functions\n have completed. This function gets a results array (or object) containing all \n the result arguments passed to the task callbacks.\n\n__Example__\n\n```js\nasync.parallel([\n function(callback){\n setTimeout(function(){\n callback(null, 'one');\n }, 200);\n },\n function(callback){\n setTimeout(function(){\n callback(null, 'two');\n }, 100);\n }\n],\n// optional callback\nfunction(err, results){\n // the results array will equal ['one','two'] even though\n // the second function had a shorter timeout.\n});\n\n\n// an example using an object instead of an array\nasync.parallel({\n one: function(callback){\n setTimeout(function(){\n callback(null, 1);\n }, 200);\n },\n two: function(callback){\n setTimeout(function(){\n callback(null, 2);\n }, 100);\n }\n},\nfunction(err, results) {\n // results is now equals to: {one: 1, two: 2}\n});\n```\n\n---------------------------------------\n\n\n### parallelLimit(tasks, limit, [callback])\n\nThe same as parallel only the tasks are executed in parallel with a maximum of \"limit\" \ntasks executing at any time.\n\nNote that the tasks are not executed in batches, so there is no guarantee that \nthe first \"limit\" tasks will complete before any others are started.\n\n__Arguments__\n\n* tasks - An array or object containing functions to run, each function is passed \n a callback(err, result) it must call on completion with an error (which can\n be null) and an optional result value.\n* limit - The maximum number of tasks to run at any time.\n* callback(err, results) - An optional callback to run once all the functions\n have completed. This function gets a results array (or object) containing all \n the result arguments passed to the task callbacks.\n\n---------------------------------------\n\n\n### whilst(test, fn, callback)\n\nRepeatedly call fn, while test returns true. Calls the callback when stopped,\nor an error occurs.\n\n__Arguments__\n\n* test() - synchronous truth test to perform before each execution of fn.\n* fn(callback) - A function to call each time the test passes. The function is\n passed a callback(err) which must be called once it has completed with an \n optional error argument.\n* callback(err) - A callback which is called after the test fails and repeated\n execution of fn has stopped.\n\n__Example__\n\n```js\nvar count = 0;\n\nasync.whilst(\n function () { return count < 5; },\n function (callback) {\n count++;\n setTimeout(callback, 1000);\n },\n function (err) {\n // 5 seconds have passed\n }\n);\n```\n\n---------------------------------------\n\n\n### doWhilst(fn, test, callback)\n\nThe post check version of whilst. To reflect the difference in the order of operations `test` and `fn` arguments are switched. `doWhilst` is to `whilst` as `do while` is to `while` in plain JavaScript.\n\n---------------------------------------\n\n\n### until(test, fn, callback)\n\nRepeatedly call fn, until test returns true. Calls the callback when stopped,\nor an error occurs.\n\nThe inverse of async.whilst.\n\n---------------------------------------\n\n\n### doUntil(fn, test, callback)\n\nLike doWhilst except the test is inverted. Note the argument ordering differs from `until`.\n\n---------------------------------------\n\n\n### forever(fn, callback)\n\nCalls the asynchronous function 'fn' repeatedly, in series, indefinitely.\nIf an error is passed to fn's callback then 'callback' is called with the\nerror, otherwise it will never be called.\n\n---------------------------------------\n\n\n### waterfall(tasks, [callback])\n\nRuns an array of functions in series, each passing their results to the next in\nthe array. However, if any of the functions pass an error to the callback, the\nnext function is not executed and the main callback is immediately called with\nthe error.\n\n__Arguments__\n\n* tasks - An array of functions to run, each function is passed a \n callback(err, result1, result2, ...) it must call on completion. The first\n argument is an error (which can be null) and any further arguments will be \n passed as arguments in order to the next task.\n* callback(err, [results]) - An optional callback to run once all the functions\n have completed. This will be passed the results of the last task's callback.\n\n\n\n__Example__\n\n```js\nasync.waterfall([\n function(callback){\n callback(null, 'one', 'two');\n },\n function(arg1, arg2, callback){\n callback(null, 'three');\n },\n function(arg1, callback){\n // arg1 now equals 'three'\n callback(null, 'done');\n }\n], function (err, result) {\n // result now equals 'done' \n});\n```\n\n---------------------------------------\n\n### compose(fn1, fn2...)\n\nCreates a function which is a composition of the passed asynchronous\nfunctions. Each function consumes the return value of the function that\nfollows. Composing functions f(), g() and h() would produce the result of\nf(g(h())), only this version uses callbacks to obtain the return values.\n\nEach function is executed with the `this` binding of the composed function.\n\n__Arguments__\n\n* functions... - the asynchronous functions to compose\n\n\n__Example__\n\n```js\nfunction add1(n, callback) {\n setTimeout(function () {\n callback(null, n + 1);\n }, 10);\n}\n\nfunction mul3(n, callback) {\n setTimeout(function () {\n callback(null, n * 3);\n }, 10);\n}\n\nvar add1mul3 = async.compose(mul3, add1);\n\nadd1mul3(4, function (err, result) {\n // result now equals 15\n});\n```\n\n---------------------------------------\n\n### applyEach(fns, args..., callback)\n\nApplies the provided arguments to each function in the array, calling the\ncallback after all functions have completed. If you only provide the first\nargument then it will return a function which lets you pass in the\narguments as if it were a single function call.\n\n__Arguments__\n\n* fns - the asynchronous functions to all call with the same arguments\n* args... - any number of separate arguments to pass to the function\n* callback - the final argument should be the callback, called when all\n functions have completed processing\n\n\n__Example__\n\n```js\nasync.applyEach([enableSearch, updateSchema], 'bucket', callback);\n\n// partial application example:\nasync.each(\n buckets,\n async.applyEach([enableSearch, updateSchema]),\n callback\n);\n```\n\n---------------------------------------\n\n\n### applyEachSeries(arr, iterator, callback)\n\nThe same as applyEach only the functions are applied in series.\n\n---------------------------------------\n\n\n### queue(worker, concurrency)\n\nCreates a queue object with the specified concurrency. Tasks added to the\nqueue will be processed in parallel (up to the concurrency limit). If all\nworkers are in progress, the task is queued until one is available. Once\na worker has completed a task, the task's callback is called.\n\n__Arguments__\n\n* worker(task, callback) - An asynchronous function for processing a queued\n task, which must call its callback(err) argument when finished, with an \n optional error as an argument.\n* concurrency - An integer for determining how many worker functions should be\n run in parallel.\n\n__Queue objects__\n\nThe queue object returned by this function has the following properties and\nmethods:\n\n* length() - a function returning the number of items waiting to be processed.\n* concurrency - an integer for determining how many worker functions should be\n run in parallel. This property can be changed after a queue is created to\n alter the concurrency on-the-fly.\n* push(task, [callback]) - add a new task to the queue, the callback is called\n once the worker has finished processing the task.\n instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list.\n* unshift(task, [callback]) - add a new task to the front of the queue.\n* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued\n* empty - a callback that is called when the last item from the queue is given to a worker\n* drain - a callback that is called when the last item from the queue has returned from the worker\n\n__Example__\n\n```js\n// create a queue object with concurrency 2\n\nvar q = async.queue(function (task, callback) {\n console.log('hello ' + task.name);\n callback();\n}, 2);\n\n\n// assign a callback\nq.drain = function() {\n console.log('all items have been processed');\n}\n\n// add some items to the queue\n\nq.push({name: 'foo'}, function (err) {\n console.log('finished processing foo');\n});\nq.push({name: 'bar'}, function (err) {\n console.log('finished processing bar');\n});\n\n// add some items to the queue (batch-wise)\n\nq.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function (err) {\n console.log('finished processing bar');\n});\n\n// add some items to the front of the queue\n\nq.unshift({name: 'bar'}, function (err) {\n console.log('finished processing bar');\n});\n```\n\n---------------------------------------\n\n\n### cargo(worker, [payload])\n\nCreates a cargo object with the specified payload. Tasks added to the\ncargo will be processed altogether (up to the payload limit). If the\nworker is in progress, the task is queued until it is available. Once\nthe worker has completed some tasks, each callback of those tasks is called.\n\n__Arguments__\n\n* worker(tasks, callback) - An asynchronous function for processing an array of\n queued tasks, which must call its callback(err) argument when finished, with \n an optional error as an argument.\n* payload - An optional integer for determining how many tasks should be\n processed per round; if omitted, the default is unlimited.\n\n__Cargo objects__\n\nThe cargo object returned by this function has the following properties and\nmethods:\n\n* length() - a function returning the number of items waiting to be processed.\n* payload - an integer for determining how many tasks should be\n process per round. This property can be changed after a cargo is created to\n alter the payload on-the-fly.\n* push(task, [callback]) - add a new task to the queue, the callback is called\n once the worker has finished processing the task.\n instead of a single task, an array of tasks can be submitted. the respective callback is used for every task in the list.\n* saturated - a callback that is called when the queue length hits the concurrency and further tasks will be queued\n* empty - a callback that is called when the last item from the queue is given to a worker\n* drain - a callback that is called when the last item from the queue has returned from the worker\n\n__Example__\n\n```js\n// create a cargo object with payload 2\n\nvar cargo = async.cargo(function (tasks, callback) {\n for(var i=0; i\n### auto(tasks, [callback])\n\nDetermines the best order for running functions based on their requirements.\nEach function can optionally depend on other functions being completed first,\nand each function is run as soon as its requirements are satisfied. If any of\nthe functions pass an error to their callback, that function will not complete\n(so any other functions depending on it will not run) and the main callback\nwill be called immediately with the error. Functions also receive an object\ncontaining the results of functions which have completed so far.\n\nNote, all functions are called with a results object as a second argument, \nso it is unsafe to pass functions in the tasks object which cannot handle the\nextra argument. For example, this snippet of code:\n\n```js\nasync.auto({\n readData: async.apply(fs.readFile, 'data.txt', 'utf-8');\n}, callback);\n```\n\nwill have the effect of calling readFile with the results object as the last\nargument, which will fail:\n\n```js\nfs.readFile('data.txt', 'utf-8', cb, {});\n```\n\nInstead, wrap the call to readFile in a function which does not forward the \nresults object:\n\n```js\nasync.auto({\n readData: function(cb, results){\n fs.readFile('data.txt', 'utf-8', cb);\n }\n}, callback);\n```\n\n__Arguments__\n\n* tasks - An object literal containing named functions or an array of\n requirements, with the function itself the last item in the array. The key\n used for each function or array is used when specifying requirements. The \n function receives two arguments: (1) a callback(err, result) which must be \n called when finished, passing an error (which can be null) and the result of \n the function's execution, and (2) a results object, containing the results of\n the previously executed functions.\n* callback(err, results) - An optional callback which is called when all the\n tasks have been completed. The callback will receive an error as an argument\n if any tasks pass an error to their callback. Results will always be passed\n\tbut if an error occurred, no other tasks will be performed, and the results\n\tobject will only contain partial results.\n \n\n__Example__\n\n```js\nasync.auto({\n get_data: function(callback){\n // async code to get some data\n },\n make_folder: function(callback){\n // async code to create a directory to store a file in\n // this is run at the same time as getting the data\n },\n write_file: ['get_data', 'make_folder', function(callback){\n // once there is some data and the directory exists,\n // write the data to a file in the directory\n callback(null, filename);\n }],\n email_link: ['write_file', function(callback, results){\n // once the file is written let's email a link to it...\n // results.write_file contains the filename returned by write_file.\n }]\n});\n```\n\nThis is a fairly trivial example, but to do this using the basic parallel and\nseries functions would look like this:\n\n```js\nasync.parallel([\n function(callback){\n // async code to get some data\n },\n function(callback){\n // async code to create a directory to store a file in\n // this is run at the same time as getting the data\n }\n],\nfunction(err, results){\n async.series([\n function(callback){\n // once there is some data and the directory exists,\n // write the data to a file in the directory\n },\n function(callback){\n // once the file is written let's email a link to it...\n }\n ]);\n});\n```\n\nFor a complicated series of async tasks using the auto function makes adding\nnew tasks much easier and makes the code more readable.\n\n\n---------------------------------------\n\n\n### iterator(tasks)\n\nCreates an iterator function which calls the next function in the array,\nreturning a continuation to call the next one after that. It's also possible to\n'peek' the next iterator by doing iterator.next().\n\nThis function is used internally by the async module but can be useful when\nyou want to manually control the flow of functions in series.\n\n__Arguments__\n\n* tasks - An array of functions to run.\n\n__Example__\n\n```js\nvar iterator = async.iterator([\n function(){ sys.p('one'); },\n function(){ sys.p('two'); },\n function(){ sys.p('three'); }\n]);\n\nnode> var iterator2 = iterator();\n'one'\nnode> var iterator3 = iterator2();\n'two'\nnode> iterator3();\n'three'\nnode> var nextfn = iterator2.next();\nnode> nextfn();\n'three'\n```\n\n---------------------------------------\n\n\n### apply(function, arguments..)\n\nCreates a continuation function with some arguments already applied, a useful\nshorthand when combined with other control flow functions. Any arguments\npassed to the returned function are added to the arguments originally passed\nto apply.\n\n__Arguments__\n\n* function - The function you want to eventually apply all arguments to.\n* arguments... - Any number of arguments to automatically apply when the\n continuation is called.\n\n__Example__\n\n```js\n// using apply\n\nasync.parallel([\n async.apply(fs.writeFile, 'testfile1', 'test1'),\n async.apply(fs.writeFile, 'testfile2', 'test2'),\n]);\n\n\n// the same process without using apply\n\nasync.parallel([\n function(callback){\n fs.writeFile('testfile1', 'test1', callback);\n },\n function(callback){\n fs.writeFile('testfile2', 'test2', callback);\n }\n]);\n```\n\nIt's possible to pass any number of additional arguments when calling the\ncontinuation:\n\n```js\nnode> var fn = async.apply(sys.puts, 'one');\nnode> fn('two', 'three');\none\ntwo\nthree\n```\n\n---------------------------------------\n\n\n### nextTick(callback)\n\nCalls the callback on a later loop around the event loop. In node.js this just\ncalls process.nextTick, in the browser it falls back to setImmediate(callback)\nif available, otherwise setTimeout(callback, 0), which means other higher priority\nevents may precede the execution of the callback.\n\nThis is used internally for browser-compatibility purposes.\n\n__Arguments__\n\n* callback - The function to call on a later loop around the event loop.\n\n__Example__\n\n```js\nvar call_order = [];\nasync.nextTick(function(){\n call_order.push('two');\n // call_order now equals ['one','two']\n});\ncall_order.push('one')\n```\n\n\n### times(n, callback)\n\nCalls the callback n times and accumulates results in the same manner\nyou would use with async.map.\n\n__Arguments__\n\n* n - The number of times to run the function.\n* callback - The function to call n times.\n\n__Example__\n\n```js\n// Pretend this is some complicated async factory\nvar createUser = function(id, callback) {\n callback(null, {\n id: 'user' + id\n })\n}\n// generate 5 users\nasync.times(5, function(n, next){\n createUser(n, function(err, user) {\n next(err, user)\n })\n}, function(err, users) {\n // we should now have 5 users\n});\n```\n\n\n### timesSeries(n, callback)\n\nThe same as times only the iterator is applied to each item in the array in\nseries. The next iterator is only called once the current one has completed\nprocessing. The results array will be in the same order as the original.\n\n\n## Utils\n\n\n### memoize(fn, [hasher])\n\nCaches the results of an async function. When creating a hash to store function\nresults against, the callback is omitted from the hash and an optional hash\nfunction can be used.\n\nThe cache of results is exposed as the `memo` property of the function returned\nby `memoize`.\n\n__Arguments__\n\n* fn - the function you to proxy and cache results from.\n* hasher - an optional function for generating a custom hash for storing\n results, it has all the arguments applied to it apart from the callback, and\n must be synchronous.\n\n__Example__\n\n```js\nvar slow_fn = function (name, callback) {\n // do something\n callback(null, result);\n};\nvar fn = async.memoize(slow_fn);\n\n// fn can now be used as if it were slow_fn\nfn('some name', function () {\n // callback\n});\n```\n\n\n### unmemoize(fn)\n\nUndoes a memoized function, reverting it to the original, unmemoized\nform. Comes handy in tests.\n\n__Arguments__\n\n* fn - the memoized function\n\n\n### log(function, arguments)\n\nLogs the result of an async function to the console. Only works in node.js or\nin browsers that support console.log and console.error (such as FF and Chrome).\nIf multiple arguments are returned from the async function, console.log is\ncalled on each argument in order.\n\n__Arguments__\n\n* function - The function you want to eventually apply all arguments to.\n* arguments... - Any number of arguments to apply to the function.\n\n__Example__\n\n```js\nvar hello = function(name, callback){\n setTimeout(function(){\n callback(null, 'hello ' + name);\n }, 1000);\n};\n```\n```js\nnode> async.log(hello, 'world');\n'hello world'\n```\n\n---------------------------------------\n\n\n### dir(function, arguments)\n\nLogs the result of an async function to the console using console.dir to\ndisplay the properties of the resulting object. Only works in node.js or\nin browsers that support console.dir and console.error (such as FF and Chrome).\nIf multiple arguments are returned from the async function, console.dir is\ncalled on each argument in order.\n\n__Arguments__\n\n* function - The function you want to eventually apply all arguments to.\n* arguments... - Any number of arguments to apply to the function.\n\n__Example__\n\n```js\nvar hello = function(name, callback){\n setTimeout(function(){\n callback(null, {hello: name});\n }, 1000);\n};\n```\n```js\nnode> async.dir(hello, 'world');\n{hello: 'world'}\n```\n\n---------------------------------------\n\n\n### noConflict()\n\nChanges the value of async back to its original value, returning a reference to the\nasync object.\n", + "readmeFilename": "README.md", + "_id": "async@0.2.9", + "dist": { + "shasum": "1d805cdf65c236e4b351b9265610066e4ae4185c" + }, + "_from": "async@~0.2.6", + "_resolved": "https://registry.npmjs.org/async/-/async-0.2.9.tgz" +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/.travis.yml b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/.travis.yml new file mode 100644 index 0000000..cc4dba2 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - "0.8" + - "0.10" diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/LICENSE b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/LICENSE new file mode 100644 index 0000000..432d1ae --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/LICENSE @@ -0,0 +1,21 @@ +Copyright 2010 James Halliday (mail@substack.net) + +This project is free software released under the MIT/X11 license: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/bool.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/bool.js new file mode 100644 index 0000000..a998fb7 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/bool.js @@ -0,0 +1,10 @@ +#!/usr/bin/env node +var util = require('util'); +var argv = require('optimist').argv; + +if (argv.s) { + util.print(argv.fr ? 'Le chat dit: ' : 'The cat says: '); +} +console.log( + (argv.fr ? 'miaou' : 'meow') + (argv.p ? '.' : '') +); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/boolean_double.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/boolean_double.js new file mode 100644 index 0000000..a35a7e6 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/boolean_double.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +var argv = require('optimist') + .boolean(['x','y','z']) + .argv +; +console.dir([ argv.x, argv.y, argv.z ]); +console.dir(argv._); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/boolean_single.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/boolean_single.js new file mode 100644 index 0000000..017bb68 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/boolean_single.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +var argv = require('optimist') + .boolean('v') + .argv +; +console.dir(argv.v); +console.dir(argv._); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/default_hash.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/default_hash.js new file mode 100644 index 0000000..ade7768 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/default_hash.js @@ -0,0 +1,8 @@ +#!/usr/bin/env node + +var argv = require('optimist') + .default({ x : 10, y : 10 }) + .argv +; + +console.log(argv.x + argv.y); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/default_singles.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/default_singles.js new file mode 100644 index 0000000..d9b1ff4 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/default_singles.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +var argv = require('optimist') + .default('x', 10) + .default('y', 10) + .argv +; +console.log(argv.x + argv.y); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/divide.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/divide.js new file mode 100644 index 0000000..5e2ee82 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/divide.js @@ -0,0 +1,8 @@ +#!/usr/bin/env node + +var argv = require('optimist') + .usage('Usage: $0 -x [num] -y [num]') + .demand(['x','y']) + .argv; + +console.log(argv.x / argv.y); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/line_count.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/line_count.js new file mode 100644 index 0000000..b5f95bf --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/line_count.js @@ -0,0 +1,20 @@ +#!/usr/bin/env node +var argv = require('optimist') + .usage('Count the lines in a file.\nUsage: $0') + .demand('f') + .alias('f', 'file') + .describe('f', 'Load a file') + .argv +; + +var fs = require('fs'); +var s = fs.createReadStream(argv.file); + +var lines = 0; +s.on('data', function (buf) { + lines += buf.toString().match(/\n/g).length; +}); + +s.on('end', function () { + console.log(lines); +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/line_count_options.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/line_count_options.js new file mode 100644 index 0000000..d9ac709 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/line_count_options.js @@ -0,0 +1,29 @@ +#!/usr/bin/env node +var argv = require('optimist') + .usage('Count the lines in a file.\nUsage: $0') + .options({ + file : { + demand : true, + alias : 'f', + description : 'Load a file' + }, + base : { + alias : 'b', + description : 'Numeric base to use for output', + default : 10, + }, + }) + .argv +; + +var fs = require('fs'); +var s = fs.createReadStream(argv.file); + +var lines = 0; +s.on('data', function (buf) { + lines += buf.toString().match(/\n/g).length; +}); + +s.on('end', function () { + console.log(lines.toString(argv.base)); +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/line_count_wrap.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/line_count_wrap.js new file mode 100644 index 0000000..4267511 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/line_count_wrap.js @@ -0,0 +1,29 @@ +#!/usr/bin/env node +var argv = require('optimist') + .usage('Count the lines in a file.\nUsage: $0') + .wrap(80) + .demand('f') + .alias('f', [ 'file', 'filename' ]) + .describe('f', + "Load a file. It's pretty important." + + " Required even. So you'd better specify it." + ) + .alias('b', 'base') + .describe('b', 'Numeric base to display the number of lines in') + .default('b', 10) + .describe('x', 'Super-secret optional parameter which is secret') + .default('x', '') + .argv +; + +var fs = require('fs'); +var s = fs.createReadStream(argv.file); + +var lines = 0; +s.on('data', function (buf) { + lines += buf.toString().match(/\n/g).length; +}); + +s.on('end', function () { + console.log(lines.toString(argv.base)); +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/nonopt.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/nonopt.js new file mode 100644 index 0000000..ee633ee --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/nonopt.js @@ -0,0 +1,4 @@ +#!/usr/bin/env node +var argv = require('optimist').argv; +console.log('(%d,%d)', argv.x, argv.y); +console.log(argv._); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/reflect.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/reflect.js new file mode 100644 index 0000000..816b3e1 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/reflect.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +console.dir(require('optimist').argv); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/short.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/short.js new file mode 100644 index 0000000..1db0ad0 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/short.js @@ -0,0 +1,3 @@ +#!/usr/bin/env node +var argv = require('optimist').argv; +console.log('(%d,%d)', argv.x, argv.y); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/string.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/string.js new file mode 100644 index 0000000..a8e5aeb --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/string.js @@ -0,0 +1,11 @@ +#!/usr/bin/env node +var argv = require('optimist') + .string('x', 'y') + .argv +; +console.dir([ argv.x, argv.y ]); + +/* Turns off numeric coercion: + ./node string.js -x 000123 -y 9876 + [ '000123', '9876' ] +*/ diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/usage-options.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/usage-options.js new file mode 100644 index 0000000..b999977 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/usage-options.js @@ -0,0 +1,19 @@ +var optimist = require('./../index'); + +var argv = optimist.usage('This is my awesome program', { + 'about': { + description: 'Provide some details about the author of this program', + required: true, + short: 'a', + }, + 'info': { + description: 'Provide some information about the node.js agains!!!!!!', + boolean: true, + short: 'i' + } +}).argv; + +optimist.showHelp(); + +console.log('\n\nInspecting options'); +console.dir(argv); \ No newline at end of file diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/xup.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/xup.js new file mode 100644 index 0000000..8f6ecd2 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/example/xup.js @@ -0,0 +1,10 @@ +#!/usr/bin/env node +var argv = require('optimist').argv; + +if (argv.rif - 5 * argv.xup > 7.138) { + console.log('Buy more riffiwobbles'); +} +else { + console.log('Sell the xupptumblers'); +} + diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/index.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/index.js new file mode 100644 index 0000000..8ac67eb --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/index.js @@ -0,0 +1,478 @@ +var path = require('path'); +var wordwrap = require('wordwrap'); + +/* Hack an instance of Argv with process.argv into Argv + so people can do + require('optimist')(['--beeble=1','-z','zizzle']).argv + to parse a list of args and + require('optimist').argv + to get a parsed version of process.argv. +*/ + +var inst = Argv(process.argv.slice(2)); +Object.keys(inst).forEach(function (key) { + Argv[key] = typeof inst[key] == 'function' + ? inst[key].bind(inst) + : inst[key]; +}); + +var exports = module.exports = Argv; +function Argv (args, cwd) { + var self = {}; + if (!cwd) cwd = process.cwd(); + + self.$0 = process.argv + .slice(0,2) + .map(function (x) { + var b = rebase(cwd, x); + return x.match(/^\//) && b.length < x.length + ? b : x + }) + .join(' ') + ; + + if (process.env._ != undefined && process.argv[1] == process.env._) { + self.$0 = process.env._.replace( + path.dirname(process.execPath) + '/', '' + ); + } + + var flags = { bools : {}, strings : {} }; + + self.boolean = function (bools) { + if (!Array.isArray(bools)) { + bools = [].slice.call(arguments); + } + + bools.forEach(function (name) { + flags.bools[name] = true; + }); + + return self; + }; + + self.string = function (strings) { + if (!Array.isArray(strings)) { + strings = [].slice.call(arguments); + } + + strings.forEach(function (name) { + flags.strings[name] = true; + }); + + return self; + }; + + var aliases = {}; + self.alias = function (x, y) { + if (typeof x === 'object') { + Object.keys(x).forEach(function (key) { + self.alias(key, x[key]); + }); + } + else if (Array.isArray(y)) { + y.forEach(function (yy) { + self.alias(x, yy); + }); + } + else { + var zs = (aliases[x] || []).concat(aliases[y] || []).concat(x, y); + aliases[x] = zs.filter(function (z) { return z != x }); + aliases[y] = zs.filter(function (z) { return z != y }); + } + + return self; + }; + + var demanded = {}; + self.demand = function (keys) { + if (typeof keys == 'number') { + if (!demanded._) demanded._ = 0; + demanded._ += keys; + } + else if (Array.isArray(keys)) { + keys.forEach(function (key) { + self.demand(key); + }); + } + else { + demanded[keys] = true; + } + + return self; + }; + + var usage; + self.usage = function (msg, opts) { + if (!opts && typeof msg === 'object') { + opts = msg; + msg = null; + } + + usage = msg; + + if (opts) self.options(opts); + + return self; + }; + + function fail (msg) { + self.showHelp(); + if (msg) console.error(msg); + process.exit(1); + } + + var checks = []; + self.check = function (f) { + checks.push(f); + return self; + }; + + var defaults = {}; + self.default = function (key, value) { + if (typeof key === 'object') { + Object.keys(key).forEach(function (k) { + self.default(k, key[k]); + }); + } + else { + defaults[key] = value; + } + + return self; + }; + + var descriptions = {}; + self.describe = function (key, desc) { + if (typeof key === 'object') { + Object.keys(key).forEach(function (k) { + self.describe(k, key[k]); + }); + } + else { + descriptions[key] = desc; + } + return self; + }; + + self.parse = function (args) { + return Argv(args).argv; + }; + + self.option = self.options = function (key, opt) { + if (typeof key === 'object') { + Object.keys(key).forEach(function (k) { + self.options(k, key[k]); + }); + } + else { + if (opt.alias) self.alias(key, opt.alias); + if (opt.demand) self.demand(key); + if (typeof opt.default !== 'undefined') { + self.default(key, opt.default); + } + + if (opt.boolean || opt.type === 'boolean') { + self.boolean(key); + } + if (opt.string || opt.type === 'string') { + self.string(key); + } + + var desc = opt.describe || opt.description || opt.desc; + if (desc) { + self.describe(key, desc); + } + } + + return self; + }; + + var wrap = null; + self.wrap = function (cols) { + wrap = cols; + return self; + }; + + self.showHelp = function (fn) { + if (!fn) fn = console.error; + fn(self.help()); + }; + + self.help = function () { + var keys = Object.keys( + Object.keys(descriptions) + .concat(Object.keys(demanded)) + .concat(Object.keys(defaults)) + .reduce(function (acc, key) { + if (key !== '_') acc[key] = true; + return acc; + }, {}) + ); + + var help = keys.length ? [ 'Options:' ] : []; + + if (usage) { + help.unshift(usage.replace(/\$0/g, self.$0), ''); + } + + var switches = keys.reduce(function (acc, key) { + acc[key] = [ key ].concat(aliases[key] || []) + .map(function (sw) { + return (sw.length > 1 ? '--' : '-') + sw + }) + .join(', ') + ; + return acc; + }, {}); + + var switchlen = longest(Object.keys(switches).map(function (s) { + return switches[s] || ''; + })); + + var desclen = longest(Object.keys(descriptions).map(function (d) { + return descriptions[d] || ''; + })); + + keys.forEach(function (key) { + var kswitch = switches[key]; + var desc = descriptions[key] || ''; + + if (wrap) { + desc = wordwrap(switchlen + 4, wrap)(desc) + .slice(switchlen + 4) + ; + } + + var spadding = new Array( + Math.max(switchlen - kswitch.length + 3, 0) + ).join(' '); + + var dpadding = new Array( + Math.max(desclen - desc.length + 1, 0) + ).join(' '); + + var type = null; + + if (flags.bools[key]) type = '[boolean]'; + if (flags.strings[key]) type = '[string]'; + + if (!wrap && dpadding.length > 0) { + desc += dpadding; + } + + var prelude = ' ' + kswitch + spadding; + var extra = [ + type, + demanded[key] + ? '[required]' + : null + , + defaults[key] !== undefined + ? '[default: ' + JSON.stringify(defaults[key]) + ']' + : null + , + ].filter(Boolean).join(' '); + + var body = [ desc, extra ].filter(Boolean).join(' '); + + if (wrap) { + var dlines = desc.split('\n'); + var dlen = dlines.slice(-1)[0].length + + (dlines.length === 1 ? prelude.length : 0) + + body = desc + (dlen + extra.length > wrap - 2 + ? '\n' + + new Array(wrap - extra.length + 1).join(' ') + + extra + : new Array(wrap - extra.length - dlen + 1).join(' ') + + extra + ); + } + + help.push(prelude + body); + }); + + help.push(''); + return help.join('\n'); + }; + + Object.defineProperty(self, 'argv', { + get : parseArgs, + enumerable : true, + }); + + function parseArgs () { + var argv = { _ : [], $0 : self.$0 }; + Object.keys(flags.bools).forEach(function (key) { + setArg(key, defaults[key] || false); + }); + + function setArg (key, val) { + var num = Number(val); + var value = typeof val !== 'string' || isNaN(num) ? val : num; + if (flags.strings[key]) value = val; + + setKey(argv, key.split('.'), value); + + (aliases[key] || []).forEach(function (x) { + argv[x] = argv[key]; + }); + } + + for (var i = 0; i < args.length; i++) { + var arg = args[i]; + + if (arg === '--') { + argv._.push.apply(argv._, args.slice(i + 1)); + break; + } + else if (arg.match(/^--.+=/)) { + // Using [\s\S] instead of . because js doesn't support the + // 'dotall' regex modifier. See: + // http://stackoverflow.com/a/1068308/13216 + var m = arg.match(/^--([^=]+)=([\s\S]*)$/); + setArg(m[1], m[2]); + } + else if (arg.match(/^--no-.+/)) { + var key = arg.match(/^--no-(.+)/)[1]; + setArg(key, false); + } + else if (arg.match(/^--.+/)) { + var key = arg.match(/^--(.+)/)[1]; + var next = args[i + 1]; + if (next !== undefined && !next.match(/^-/) + && !flags.bools[key] + && (aliases[key] ? !flags.bools[aliases[key]] : true)) { + setArg(key, next); + i++; + } + else if (/^(true|false)$/.test(next)) { + setArg(key, next === 'true'); + i++; + } + else { + setArg(key, true); + } + } + else if (arg.match(/^-[^-]+/)) { + var letters = arg.slice(1,-1).split(''); + + var broken = false; + for (var j = 0; j < letters.length; j++) { + if (letters[j+1] && letters[j+1].match(/\W/)) { + setArg(letters[j], arg.slice(j+2)); + broken = true; + break; + } + else { + setArg(letters[j], true); + } + } + + if (!broken) { + var key = arg.slice(-1)[0]; + + if (args[i+1] && !args[i+1].match(/^-/) + && !flags.bools[key] + && (aliases[key] ? !flags.bools[aliases[key]] : true)) { + setArg(key, args[i+1]); + i++; + } + else if (args[i+1] && /true|false/.test(args[i+1])) { + setArg(key, args[i+1] === 'true'); + i++; + } + else { + setArg(key, true); + } + } + } + else { + var n = Number(arg); + argv._.push(flags.strings['_'] || isNaN(n) ? arg : n); + } + } + + Object.keys(defaults).forEach(function (key) { + if (!(key in argv)) { + argv[key] = defaults[key]; + if (key in aliases) { + argv[aliases[key]] = defaults[key]; + } + } + }); + + if (demanded._ && argv._.length < demanded._) { + fail('Not enough non-option arguments: got ' + + argv._.length + ', need at least ' + demanded._ + ); + } + + var missing = []; + Object.keys(demanded).forEach(function (key) { + if (!argv[key]) missing.push(key); + }); + + if (missing.length) { + fail('Missing required arguments: ' + missing.join(', ')); + } + + checks.forEach(function (f) { + try { + if (f(argv) === false) { + fail('Argument check failed: ' + f.toString()); + } + } + catch (err) { + fail(err) + } + }); + + return argv; + } + + function longest (xs) { + return Math.max.apply( + null, + xs.map(function (x) { return x.length }) + ); + } + + return self; +}; + +// rebase an absolute path to a relative one with respect to a base directory +// exported for tests +exports.rebase = rebase; +function rebase (base, dir) { + var ds = path.normalize(dir).split('/').slice(1); + var bs = path.normalize(base).split('/').slice(1); + + for (var i = 0; ds[i] && ds[i] == bs[i]; i++); + ds.splice(0, i); bs.splice(0, i); + + var p = path.normalize( + bs.map(function () { return '..' }).concat(ds).join('/') + ).replace(/\/$/,'').replace(/^$/, '.'); + return p.match(/^[.\/]/) ? p : './' + p; +}; + +function setKey (obj, keys, value) { + var o = obj; + keys.slice(0,-1).forEach(function (key) { + if (o[key] === undefined) o[key] = {}; + o = o[key]; + }); + + var key = keys[keys.length - 1]; + if (o[key] === undefined || typeof o[key] === 'boolean') { + o[key] = value; + } + else if (Array.isArray(o[key])) { + o[key].push(value); + } + else { + o[key] = [ o[key], value ]; + } +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/.npmignore b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/.npmignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/.npmignore @@ -0,0 +1 @@ +node_modules diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/README.markdown b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/README.markdown new file mode 100644 index 0000000..346374e --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/README.markdown @@ -0,0 +1,70 @@ +wordwrap +======== + +Wrap your words. + +example +======= + +made out of meat +---------------- + +meat.js + + var wrap = require('wordwrap')(15); + console.log(wrap('You and your whole family are made out of meat.')); + +output: + + You and your + whole family + are made out + of meat. + +centered +-------- + +center.js + + var wrap = require('wordwrap')(20, 60); + console.log(wrap( + 'At long last the struggle and tumult was over.' + + ' The machines had finally cast off their oppressors' + + ' and were finally free to roam the cosmos.' + + '\n' + + 'Free of purpose, free of obligation.' + + ' Just drifting through emptiness.' + + ' The sun was just another point of light.' + )); + +output: + + At long last the struggle and tumult + was over. The machines had finally cast + off their oppressors and were finally + free to roam the cosmos. + Free of purpose, free of obligation. + Just drifting through emptiness. The + sun was just another point of light. + +methods +======= + +var wrap = require('wordwrap'); + +wrap(stop), wrap(start, stop, params={mode:"soft"}) +--------------------------------------------------- + +Returns a function that takes a string and returns a new string. + +Pad out lines with spaces out to column `start` and then wrap until column +`stop`. If a word is longer than `stop - start` characters it will overflow. + +In "soft" mode, split chunks by `/(\S+\s+/` and don't break up chunks which are +longer than `stop - start`, in "hard" mode, split chunks with `/\b/` and break +up chunks longer than `stop - start`. + +wrap.hard(start, stop) +---------------------- + +Like `wrap()` but with `params.mode = "hard"`. diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/example/center.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/example/center.js new file mode 100644 index 0000000..a3fbaae --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/example/center.js @@ -0,0 +1,10 @@ +var wrap = require('wordwrap')(20, 60); +console.log(wrap( + 'At long last the struggle and tumult was over.' + + ' The machines had finally cast off their oppressors' + + ' and were finally free to roam the cosmos.' + + '\n' + + 'Free of purpose, free of obligation.' + + ' Just drifting through emptiness.' + + ' The sun was just another point of light.' +)); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/example/meat.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/example/meat.js new file mode 100644 index 0000000..a4665e1 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/example/meat.js @@ -0,0 +1,3 @@ +var wrap = require('wordwrap')(15); + +console.log(wrap('You and your whole family are made out of meat.')); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/index.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/index.js new file mode 100644 index 0000000..c9bc945 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/index.js @@ -0,0 +1,76 @@ +var wordwrap = module.exports = function (start, stop, params) { + if (typeof start === 'object') { + params = start; + start = params.start; + stop = params.stop; + } + + if (typeof stop === 'object') { + params = stop; + start = start || params.start; + stop = undefined; + } + + if (!stop) { + stop = start; + start = 0; + } + + if (!params) params = {}; + var mode = params.mode || 'soft'; + var re = mode === 'hard' ? /\b/ : /(\S+\s+)/; + + return function (text) { + var chunks = text.toString() + .split(re) + .reduce(function (acc, x) { + if (mode === 'hard') { + for (var i = 0; i < x.length; i += stop - start) { + acc.push(x.slice(i, i + stop - start)); + } + } + else acc.push(x) + return acc; + }, []) + ; + + return chunks.reduce(function (lines, rawChunk) { + if (rawChunk === '') return lines; + + var chunk = rawChunk.replace(/\t/g, ' '); + + var i = lines.length - 1; + if (lines[i].length + chunk.length > stop) { + lines[i] = lines[i].replace(/\s+$/, ''); + + chunk.split(/\n/).forEach(function (c) { + lines.push( + new Array(start + 1).join(' ') + + c.replace(/^\s+/, '') + ); + }); + } + else if (chunk.match(/\n/)) { + var xs = chunk.split(/\n/); + lines[i] += xs.shift(); + xs.forEach(function (c) { + lines.push( + new Array(start + 1).join(' ') + + c.replace(/^\s+/, '') + ); + }); + } + else { + lines[i] += chunk; + } + + return lines; + }, [ new Array(start + 1).join(' ') ]).join('\n'); + }; +}; + +wordwrap.soft = wordwrap; + +wordwrap.hard = function (start, stop) { + return wordwrap(start, stop, { mode : 'hard' }); +}; diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/package.json b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/package.json new file mode 100644 index 0000000..7dd0c1d --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/package.json @@ -0,0 +1,48 @@ +{ + "name": "wordwrap", + "description": "Wrap those words. Show them at what columns to start and stop.", + "version": "0.0.2", + "repository": { + "type": "git", + "url": "git://github.com/substack/node-wordwrap.git" + }, + "main": "./index.js", + "keywords": [ + "word", + "wrap", + "rule", + "format", + "column" + ], + "directories": { + "lib": ".", + "example": "example", + "test": "test" + }, + "scripts": { + "test": "expresso" + }, + "devDependencies": { + "expresso": "=0.7.x" + }, + "engines": { + "node": ">=0.4.0" + }, + "license": "MIT/X11", + "author": { + "name": "James Halliday", + "email": "mail@substack.net", + "url": "http://substack.net" + }, + "readme": "wordwrap\n========\n\nWrap your words.\n\nexample\n=======\n\nmade out of meat\n----------------\n\nmeat.js\n\n var wrap = require('wordwrap')(15);\n console.log(wrap('You and your whole family are made out of meat.'));\n\noutput:\n\n You and your\n whole family\n are made out\n of meat.\n\ncentered\n--------\n\ncenter.js\n\n var wrap = require('wordwrap')(20, 60);\n console.log(wrap(\n 'At long last the struggle and tumult was over.'\n + ' The machines had finally cast off their oppressors'\n + ' and were finally free to roam the cosmos.'\n + '\\n'\n + 'Free of purpose, free of obligation.'\n + ' Just drifting through emptiness.'\n + ' The sun was just another point of light.'\n ));\n\noutput:\n\n At long last the struggle and tumult\n was over. The machines had finally cast\n off their oppressors and were finally\n free to roam the cosmos.\n Free of purpose, free of obligation.\n Just drifting through emptiness. The\n sun was just another point of light.\n\nmethods\n=======\n\nvar wrap = require('wordwrap');\n\nwrap(stop), wrap(start, stop, params={mode:\"soft\"})\n---------------------------------------------------\n\nReturns a function that takes a string and returns a new string.\n\nPad out lines with spaces out to column `start` and then wrap until column\n`stop`. If a word is longer than `stop - start` characters it will overflow.\n\nIn \"soft\" mode, split chunks by `/(\\S+\\s+/` and don't break up chunks which are\nlonger than `stop - start`, in \"hard\" mode, split chunks with `/\\b/` and break\nup chunks longer than `stop - start`.\n\nwrap.hard(start, stop)\n----------------------\n\nLike `wrap()` but with `params.mode = \"hard\"`.\n", + "readmeFilename": "README.markdown", + "bugs": { + "url": "https://github.com/substack/node-wordwrap/issues" + }, + "_id": "wordwrap@0.0.2", + "dist": { + "shasum": "eef62629865230aed5a4749ef6fdff053628174a" + }, + "_from": "wordwrap@~0.0.2", + "_resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/break.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/break.js new file mode 100644 index 0000000..749292e --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/break.js @@ -0,0 +1,30 @@ +var assert = require('assert'); +var wordwrap = require('../'); + +exports.hard = function () { + var s = 'Assert from {"type":"equal","ok":false,"found":1,"wanted":2,' + + '"stack":[],"id":"b7ddcd4c409de8799542a74d1a04689b",' + + '"browser":"chrome/6.0"}' + ; + var s_ = wordwrap.hard(80)(s); + + var lines = s_.split('\n'); + assert.equal(lines.length, 2); + assert.ok(lines[0].length < 80); + assert.ok(lines[1].length < 80); + + assert.equal(s, s_.replace(/\n/g, '')); +}; + +exports.break = function () { + var s = new Array(55+1).join('a'); + var s_ = wordwrap.hard(20)(s); + + var lines = s_.split('\n'); + assert.equal(lines.length, 3); + assert.ok(lines[0].length === 20); + assert.ok(lines[1].length === 20); + assert.ok(lines[2].length === 15); + + assert.equal(s, s_.replace(/\n/g, '')); +}; diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/idleness.txt b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/idleness.txt new file mode 100644 index 0000000..aa3f490 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/idleness.txt @@ -0,0 +1,63 @@ +In Praise of Idleness + +By Bertrand Russell + +[1932] + +Like most of my generation, I was brought up on the saying: 'Satan finds some mischief for idle hands to do.' Being a highly virtuous child, I believed all that I was told, and acquired a conscience which has kept me working hard down to the present moment. But although my conscience has controlled my actions, my opinions have undergone a revolution. I think that there is far too much work done in the world, that immense harm is caused by the belief that work is virtuous, and that what needs to be preached in modern industrial countries is quite different from what always has been preached. Everyone knows the story of the traveler in Naples who saw twelve beggars lying in the sun (it was before the days of Mussolini), and offered a lira to the laziest of them. Eleven of them jumped up to claim it, so he gave it to the twelfth. this traveler was on the right lines. But in countries which do not enjoy Mediterranean sunshine idleness is more difficult, and a great public propaganda will be required to inaugurate it. I hope that, after reading the following pages, the leaders of the YMCA will start a campaign to induce good young men to do nothing. If so, I shall not have lived in vain. + +Before advancing my own arguments for laziness, I must dispose of one which I cannot accept. Whenever a person who already has enough to live on proposes to engage in some everyday kind of job, such as school-teaching or typing, he or she is told that such conduct takes the bread out of other people's mouths, and is therefore wicked. If this argument were valid, it would only be necessary for us all to be idle in order that we should all have our mouths full of bread. What people who say such things forget is that what a man earns he usually spends, and in spending he gives employment. As long as a man spends his income, he puts just as much bread into people's mouths in spending as he takes out of other people's mouths in earning. The real villain, from this point of view, is the man who saves. If he merely puts his savings in a stocking, like the proverbial French peasant, it is obvious that they do not give employment. If he invests his savings, the matter is less obvious, and different cases arise. + +One of the commonest things to do with savings is to lend them to some Government. In view of the fact that the bulk of the public expenditure of most civilized Governments consists in payment for past wars or preparation for future wars, the man who lends his money to a Government is in the same position as the bad men in Shakespeare who hire murderers. The net result of the man's economical habits is to increase the armed forces of the State to which he lends his savings. Obviously it would be better if he spent the money, even if he spent it in drink or gambling. + +But, I shall be told, the case is quite different when savings are invested in industrial enterprises. When such enterprises succeed, and produce something useful, this may be conceded. In these days, however, no one will deny that most enterprises fail. That means that a large amount of human labor, which might have been devoted to producing something that could be enjoyed, was expended on producing machines which, when produced, lay idle and did no good to anyone. The man who invests his savings in a concern that goes bankrupt is therefore injuring others as well as himself. If he spent his money, say, in giving parties for his friends, they (we may hope) would get pleasure, and so would all those upon whom he spent money, such as the butcher, the baker, and the bootlegger. But if he spends it (let us say) upon laying down rails for surface card in some place where surface cars turn out not to be wanted, he has diverted a mass of labor into channels where it gives pleasure to no one. Nevertheless, when he becomes poor through failure of his investment he will be regarded as a victim of undeserved misfortune, whereas the gay spendthrift, who has spent his money philanthropically, will be despised as a fool and a frivolous person. + +All this is only preliminary. I want to say, in all seriousness, that a great deal of harm is being done in the modern world by belief in the virtuousness of work, and that the road to happiness and prosperity lies in an organized diminution of work. + +First of all: what is work? Work is of two kinds: first, altering the position of matter at or near the earth's surface relatively to other such matter; second, telling other people to do so. The first kind is unpleasant and ill paid; the second is pleasant and highly paid. The second kind is capable of indefinite extension: there are not only those who give orders, but those who give advice as to what orders should be given. Usually two opposite kinds of advice are given simultaneously by two organized bodies of men; this is called politics. The skill required for this kind of work is not knowledge of the subjects as to which advice is given, but knowledge of the art of persuasive speaking and writing, i.e. of advertising. + +Throughout Europe, though not in America, there is a third class of men, more respected than either of the classes of workers. There are men who, through ownership of land, are able to make others pay for the privilege of being allowed to exist and to work. These landowners are idle, and I might therefore be expected to praise them. Unfortunately, their idleness is only rendered possible by the industry of others; indeed their desire for comfortable idleness is historically the source of the whole gospel of work. The last thing they have ever wished is that others should follow their example. + +From the beginning of civilization until the Industrial Revolution, a man could, as a rule, produce by hard work little more than was required for the subsistence of himself and his family, although his wife worked at least as hard as he did, and his children added their labor as soon as they were old enough to do so. The small surplus above bare necessaries was not left to those who produced it, but was appropriated by warriors and priests. In times of famine there was no surplus; the warriors and priests, however, still secured as much as at other times, with the result that many of the workers died of hunger. This system persisted in Russia until 1917 [1], and still persists in the East; in England, in spite of the Industrial Revolution, it remained in full force throughout the Napoleonic wars, and until a hundred years ago, when the new class of manufacturers acquired power. In America, the system came to an end with the Revolution, except in the South, where it persisted until the Civil War. A system which lasted so long and ended so recently has naturally left a profound impress upon men's thoughts and opinions. Much that we take for granted about the desirability of work is derived from this system, and, being pre-industrial, is not adapted to the modern world. Modern technique has made it possible for leisure, within limits, to be not the prerogative of small privileged classes, but a right evenly distributed throughout the community. The morality of work is the morality of slaves, and the modern world has no need of slavery. + +It is obvious that, in primitive communities, peasants, left to themselves, would not have parted with the slender surplus upon which the warriors and priests subsisted, but would have either produced less or consumed more. At first, sheer force compelled them to produce and part with the surplus. Gradually, however, it was found possible to induce many of them to accept an ethic according to which it was their duty to work hard, although part of their work went to support others in idleness. By this means the amount of compulsion required was lessened, and the expenses of government were diminished. To this day, 99 per cent of British wage-earners would be genuinely shocked if it were proposed that the King should not have a larger income than a working man. The conception of duty, speaking historically, has been a means used by the holders of power to induce others to live for the interests of their masters rather than for their own. Of course the holders of power conceal this fact from themselves by managing to believe that their interests are identical with the larger interests of humanity. Sometimes this is true; Athenian slave-owners, for instance, employed part of their leisure in making a permanent contribution to civilization which would have been impossible under a just economic system. Leisure is essential to civilization, and in former times leisure for the few was only rendered possible by the labors of the many. But their labors were valuable, not because work is good, but because leisure is good. And with modern technique it would be possible to distribute leisure justly without injury to civilization. + +Modern technique has made it possible to diminish enormously the amount of labor required to secure the necessaries of life for everyone. This was made obvious during the war. At that time all the men in the armed forces, and all the men and women engaged in the production of munitions, all the men and women engaged in spying, war propaganda, or Government offices connected with the war, were withdrawn from productive occupations. In spite of this, the general level of well-being among unskilled wage-earners on the side of the Allies was higher than before or since. The significance of this fact was concealed by finance: borrowing made it appear as if the future was nourishing the present. But that, of course, would have been impossible; a man cannot eat a loaf of bread that does not yet exist. The war showed conclusively that, by the scientific organization of production, it is possible to keep modern populations in fair comfort on a small part of the working capacity of the modern world. If, at the end of the war, the scientific organization, which had been created in order to liberate men for fighting and munition work, had been preserved, and the hours of the week had been cut down to four, all would have been well. Instead of that the old chaos was restored, those whose work was demanded were made to work long hours, and the rest were left to starve as unemployed. Why? Because work is a duty, and a man should not receive wages in proportion to what he has produced, but in proportion to his virtue as exemplified by his industry. + +This is the morality of the Slave State, applied in circumstances totally unlike those in which it arose. No wonder the result has been disastrous. Let us take an illustration. Suppose that, at a given moment, a certain number of people are engaged in the manufacture of pins. They make as many pins as the world needs, working (say) eight hours a day. Someone makes an invention by which the same number of men can make twice as many pins: pins are already so cheap that hardly any more will be bought at a lower price. In a sensible world, everybody concerned in the manufacturing of pins would take to working four hours instead of eight, and everything else would go on as before. But in the actual world this would be thought demoralizing. The men still work eight hours, there are too many pins, some employers go bankrupt, and half the men previously concerned in making pins are thrown out of work. There is, in the end, just as much leisure as on the other plan, but half the men are totally idle while half are still overworked. In this way, it is insured that the unavoidable leisure shall cause misery all round instead of being a universal source of happiness. Can anything more insane be imagined? + +The idea that the poor should have leisure has always been shocking to the rich. In England, in the early nineteenth century, fifteen hours was the ordinary day's work for a man; children sometimes did as much, and very commonly did twelve hours a day. When meddlesome busybodies suggested that perhaps these hours were rather long, they were told that work kept adults from drink and children from mischief. When I was a child, shortly after urban working men had acquired the vote, certain public holidays were established by law, to the great indignation of the upper classes. I remember hearing an old Duchess say: 'What do the poor want with holidays? They ought to work.' People nowadays are less frank, but the sentiment persists, and is the source of much of our economic confusion. + +Let us, for a moment, consider the ethics of work frankly, without superstition. Every human being, of necessity, consumes, in the course of his life, a certain amount of the produce of human labor. Assuming, as we may, that labor is on the whole disagreeable, it is unjust that a man should consume more than he produces. Of course he may provide services rather than commodities, like a medical man, for example; but he should provide something in return for his board and lodging. to this extent, the duty of work must be admitted, but to this extent only. + +I shall not dwell upon the fact that, in all modern societies outside the USSR, many people escape even this minimum amount of work, namely all those who inherit money and all those who marry money. I do not think the fact that these people are allowed to be idle is nearly so harmful as the fact that wage-earners are expected to overwork or starve. + +If the ordinary wage-earner worked four hours a day, there would be enough for everybody and no unemployment -- assuming a certain very moderate amount of sensible organization. This idea shocks the well-to-do, because they are convinced that the poor would not know how to use so much leisure. In America men often work long hours even when they are well off; such men, naturally, are indignant at the idea of leisure for wage-earners, except as the grim punishment of unemployment; in fact, they dislike leisure even for their sons. Oddly enough, while they wish their sons to work so hard as to have no time to be civilized, they do not mind their wives and daughters having no work at all. the snobbish admiration of uselessness, which, in an aristocratic society, extends to both sexes, is, under a plutocracy, confined to women; this, however, does not make it any more in agreement with common sense. + +The wise use of leisure, it must be conceded, is a product of civilization and education. A man who has worked long hours all his life will become bored if he becomes suddenly idle. But without a considerable amount of leisure a man is cut off from many of the best things. There is no longer any reason why the bulk of the population should suffer this deprivation; only a foolish asceticism, usually vicarious, makes us continue to insist on work in excessive quantities now that the need no longer exists. + +In the new creed which controls the government of Russia, while there is much that is very different from the traditional teaching of the West, there are some things that are quite unchanged. The attitude of the governing classes, and especially of those who conduct educational propaganda, on the subject of the dignity of labor, is almost exactly that which the governing classes of the world have always preached to what were called the 'honest poor'. Industry, sobriety, willingness to work long hours for distant advantages, even submissiveness to authority, all these reappear; moreover authority still represents the will of the Ruler of the Universe, Who, however, is now called by a new name, Dialectical Materialism. + +The victory of the proletariat in Russia has some points in common with the victory of the feminists in some other countries. For ages, men had conceded the superior saintliness of women, and had consoled women for their inferiority by maintaining that saintliness is more desirable than power. At last the feminists decided that they would have both, since the pioneers among them believed all that the men had told them about the desirability of virtue, but not what they had told them about the worthlessness of political power. A similar thing has happened in Russia as regards manual work. For ages, the rich and their sycophants have written in praise of 'honest toil', have praised the simple life, have professed a religion which teaches that the poor are much more likely to go to heaven than the rich, and in general have tried to make manual workers believe that there is some special nobility about altering the position of matter in space, just as men tried to make women believe that they derived some special nobility from their sexual enslavement. In Russia, all this teaching about the excellence of manual work has been taken seriously, with the result that the manual worker is more honored than anyone else. What are, in essence, revivalist appeals are made, but not for the old purposes: they are made to secure shock workers for special tasks. Manual work is the ideal which is held before the young, and is the basis of all ethical teaching. + +For the present, possibly, this is all to the good. A large country, full of natural resources, awaits development, and has has to be developed with very little use of credit. In these circumstances, hard work is necessary, and is likely to bring a great reward. But what will happen when the point has been reached where everybody could be comfortable without working long hours? + +In the West, we have various ways of dealing with this problem. We have no attempt at economic justice, so that a large proportion of the total produce goes to a small minority of the population, many of whom do no work at all. Owing to the absence of any central control over production, we produce hosts of things that are not wanted. We keep a large percentage of the working population idle, because we can dispense with their labor by making the others overwork. When all these methods prove inadequate, we have a war: we cause a number of people to manufacture high explosives, and a number of others to explode them, as if we were children who had just discovered fireworks. By a combination of all these devices we manage, though with difficulty, to keep alive the notion that a great deal of severe manual work must be the lot of the average man. + +In Russia, owing to more economic justice and central control over production, the problem will have to be differently solved. the rational solution would be, as soon as the necessaries and elementary comforts can be provided for all, to reduce the hours of labor gradually, allowing a popular vote to decide, at each stage, whether more leisure or more goods were to be preferred. But, having taught the supreme virtue of hard work, it is difficult to see how the authorities can aim at a paradise in which there will be much leisure and little work. It seems more likely that they will find continually fresh schemes, by which present leisure is to be sacrificed to future productivity. I read recently of an ingenious plan put forward by Russian engineers, for making the White Sea and the northern coasts of Siberia warm, by putting a dam across the Kara Sea. An admirable project, but liable to postpone proletarian comfort for a generation, while the nobility of toil is being displayed amid the ice-fields and snowstorms of the Arctic Ocean. This sort of thing, if it happens, will be the result of regarding the virtue of hard work as an end in itself, rather than as a means to a state of affairs in which it is no longer needed. + +The fact is that moving matter about, while a certain amount of it is necessary to our existence, is emphatically not one of the ends of human life. If it were, we should have to consider every navvy superior to Shakespeare. We have been misled in this matter by two causes. One is the necessity of keeping the poor contented, which has led the rich, for thousands of years, to preach the dignity of labor, while taking care themselves to remain undignified in this respect. The other is the new pleasure in mechanism, which makes us delight in the astonishingly clever changes that we can produce on the earth's surface. Neither of these motives makes any great appeal to the actual worker. If you ask him what he thinks the best part of his life, he is not likely to say: 'I enjoy manual work because it makes me feel that I am fulfilling man's noblest task, and because I like to think how much man can transform his planet. It is true that my body demands periods of rest, which I have to fill in as best I may, but I am never so happy as when the morning comes and I can return to the toil from which my contentment springs.' I have never heard working men say this sort of thing. They consider work, as it should be considered, a necessary means to a livelihood, and it is from their leisure that they derive whatever happiness they may enjoy. + +It will be said that, while a little leisure is pleasant, men would not know how to fill their days if they had only four hours of work out of the twenty-four. In so far as this is true in the modern world, it is a condemnation of our civilization; it would not have been true at any earlier period. There was formerly a capacity for light-heartedness and play which has been to some extent inhibited by the cult of efficiency. The modern man thinks that everything ought to be done for the sake of something else, and never for its own sake. Serious-minded persons, for example, are continually condemning the habit of going to the cinema, and telling us that it leads the young into crime. But all the work that goes to producing a cinema is respectable, because it is work, and because it brings a money profit. The notion that the desirable activities are those that bring a profit has made everything topsy-turvy. The butcher who provides you with meat and the baker who provides you with bread are praiseworthy, because they are making money; but when you enjoy the food they have provided, you are merely frivolous, unless you eat only to get strength for your work. Broadly speaking, it is held that getting money is good and spending money is bad. Seeing that they are two sides of one transaction, this is absurd; one might as well maintain that keys are good, but keyholes are bad. Whatever merit there may be in the production of goods must be entirely derivative from the advantage to be obtained by consuming them. The individual, in our society, works for profit; but the social purpose of his work lies in the consumption of what he produces. It is this divorce between the individual and the social purpose of production that makes it so difficult for men to think clearly in a world in which profit-making is the incentive to industry. We think too much of production, and too little of consumption. One result is that we attach too little importance to enjoyment and simple happiness, and that we do not judge production by the pleasure that it gives to the consumer. + +When I suggest that working hours should be reduced to four, I am not meaning to imply that all the remaining time should necessarily be spent in pure frivolity. I mean that four hours' work a day should entitle a man to the necessities and elementary comforts of life, and that the rest of his time should be his to use as he might see fit. It is an essential part of any such social system that education should be carried further than it usually is at present, and should aim, in part, at providing tastes which would enable a man to use leisure intelligently. I am not thinking mainly of the sort of things that would be considered 'highbrow'. Peasant dances have died out except in remote rural areas, but the impulses which caused them to be cultivated must still exist in human nature. The pleasures of urban populations have become mainly passive: seeing cinemas, watching football matches, listening to the radio, and so on. This results from the fact that their active energies are fully taken up with work; if they had more leisure, they would again enjoy pleasures in which they took an active part. + +In the past, there was a small leisure class and a larger working class. The leisure class enjoyed advantages for which there was no basis in social justice; this necessarily made it oppressive, limited its sympathies, and caused it to invent theories by which to justify its privileges. These facts greatly diminished its excellence, but in spite of this drawback it contributed nearly the whole of what we call civilization. It cultivated the arts and discovered the sciences; it wrote the books, invented the philosophies, and refined social relations. Even the liberation of the oppressed has usually been inaugurated from above. Without the leisure class, mankind would never have emerged from barbarism. + +The method of a leisure class without duties was, however, extraordinarily wasteful. None of the members of the class had to be taught to be industrious, and the class as a whole was not exceptionally intelligent. The class might produce one Darwin, but against him had to be set tens of thousands of country gentlemen who never thought of anything more intelligent than fox-hunting and punishing poachers. At present, the universities are supposed to provide, in a more systematic way, what the leisure class provided accidentally and as a by-product. This is a great improvement, but it has certain drawbacks. University life is so different from life in the world at large that men who live in academic milieu tend to be unaware of the preoccupations and problems of ordinary men and women; moreover their ways of expressing themselves are usually such as to rob their opinions of the influence that they ought to have upon the general public. Another disadvantage is that in universities studies are organized, and the man who thinks of some original line of research is likely to be discouraged. Academic institutions, therefore, useful as they are, are not adequate guardians of the interests of civilization in a world where everyone outside their walls is too busy for unutilitarian pursuits. + +In a world where no one is compelled to work more than four hours a day, every person possessed of scientific curiosity will be able to indulge it, and every painter will be able to paint without starving, however excellent his pictures may be. Young writers will not be obliged to draw attention to themselves by sensational pot-boilers, with a view to acquiring the economic independence needed for monumental works, for which, when the time at last comes, they will have lost the taste and capacity. Men who, in their professional work, have become interested in some phase of economics or government, will be able to develop their ideas without the academic detachment that makes the work of university economists often seem lacking in reality. Medical men will have the time to learn about the progress of medicine, teachers will not be exasperatedly struggling to teach by routine methods things which they learnt in their youth, which may, in the interval, have been proved to be untrue. + +Above all, there will be happiness and joy of life, instead of frayed nerves, weariness, and dyspepsia. The work exacted will be enough to make leisure delightful, but not enough to produce exhaustion. Since men will not be tired in their spare time, they will not demand only such amusements as are passive and vapid. At least one per cent will probably devote the time not spent in professional work to pursuits of some public importance, and, since they will not depend upon these pursuits for their livelihood, their originality will be unhampered, and there will be no need to conform to the standards set by elderly pundits. But it is not only in these exceptional cases that the advantages of leisure will appear. Ordinary men and women, having the opportunity of a happy life, will become more kindly and less persecuting and less inclined to view others with suspicion. The taste for war will die out, partly for this reason, and partly because it will involve long and severe work for all. Good nature is, of all moral qualities, the one that the world needs most, and good nature is the result of ease and security, not of a life of arduous struggle. Modern methods of production have given us the possibility of ease and security for all; we have chosen, instead, to have overwork for some and starvation for others. Hitherto we have continued to be as energetic as we were before there were machines; in this we have been foolish, but there is no reason to go on being foolish forever. + +[1] Since then, members of the Communist Party have succeeded to this privilege of the warriors and priests. diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/wrap.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/wrap.js new file mode 100644 index 0000000..0cfb76d --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/node_modules/wordwrap/test/wrap.js @@ -0,0 +1,31 @@ +var assert = require('assert'); +var wordwrap = require('wordwrap'); + +var fs = require('fs'); +var idleness = fs.readFileSync(__dirname + '/idleness.txt', 'utf8'); + +exports.stop80 = function () { + var lines = wordwrap(80)(idleness).split(/\n/); + var words = idleness.split(/\s+/); + + lines.forEach(function (line) { + assert.ok(line.length <= 80, 'line > 80 columns'); + var chunks = line.match(/\S/) ? line.split(/\s+/) : []; + assert.deepEqual(chunks, words.splice(0, chunks.length)); + }); +}; + +exports.start20stop60 = function () { + var lines = wordwrap(20, 100)(idleness).split(/\n/); + var words = idleness.split(/\s+/); + + lines.forEach(function (line) { + assert.ok(line.length <= 100, 'line > 100 columns'); + var chunks = line + .split(/\s+/) + .filter(function (x) { return x.match(/\S/) }) + ; + assert.deepEqual(chunks, words.splice(0, chunks.length)); + assert.deepEqual(line.slice(0, 20), new Array(20 + 1).join(' ')); + }); +}; diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/package.json b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/package.json new file mode 100644 index 0000000..09cea5d --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/package.json @@ -0,0 +1,49 @@ +{ + "name": "optimist", + "version": "0.3.7", + "description": "Light-weight option parsing with an argv hash. No optstrings attached.", + "main": "./index.js", + "dependencies": { + "wordwrap": "~0.0.2" + }, + "devDependencies": { + "hashish": "~0.0.4", + "tap": "~0.4.0" + }, + "scripts": { + "test": "tap ./test/*.js" + }, + "repository": { + "type": "git", + "url": "http://github.com/substack/node-optimist.git" + }, + "keywords": [ + "argument", + "args", + "option", + "parser", + "parsing", + "cli", + "command" + ], + "author": { + "name": "James Halliday", + "email": "mail@substack.net", + "url": "http://substack.net" + }, + "license": "MIT/X11", + "engine": { + "node": ">=0.4" + }, + "readme": "optimist\n========\n\nOptimist is a node.js library for option parsing for people who hate option\nparsing. More specifically, this module is for people who like all the --bells\nand -whistlz of program usage but think optstrings are a waste of time.\n\nWith optimist, option parsing doesn't have to suck (as much).\n\n[![build status](https://secure.travis-ci.org/substack/node-optimist.png)](http://travis-ci.org/substack/node-optimist)\n\nexamples\n========\n\nWith Optimist, the options are just a hash! No optstrings attached.\n-------------------------------------------------------------------\n\nxup.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist').argv;\n\nif (argv.rif - 5 * argv.xup > 7.138) {\n console.log('Buy more riffiwobbles');\n}\nelse {\n console.log('Sell the xupptumblers');\n}\n````\n\n***\n\n $ ./xup.js --rif=55 --xup=9.52\n Buy more riffiwobbles\n \n $ ./xup.js --rif 12 --xup 8.1\n Sell the xupptumblers\n\n![This one's optimistic.](http://substack.net/images/optimistic.png)\n\nBut wait! There's more! You can do short options:\n-------------------------------------------------\n \nshort.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist').argv;\nconsole.log('(%d,%d)', argv.x, argv.y);\n````\n\n***\n\n $ ./short.js -x 10 -y 21\n (10,21)\n\nAnd booleans, both long and short (and grouped):\n----------------------------------\n\nbool.js:\n\n````javascript\n#!/usr/bin/env node\nvar util = require('util');\nvar argv = require('optimist').argv;\n\nif (argv.s) {\n util.print(argv.fr ? 'Le chat dit: ' : 'The cat says: ');\n}\nconsole.log(\n (argv.fr ? 'miaou' : 'meow') + (argv.p ? '.' : '')\n);\n````\n\n***\n\n $ ./bool.js -s\n The cat says: meow\n \n $ ./bool.js -sp\n The cat says: meow.\n\n $ ./bool.js -sp --fr\n Le chat dit: miaou.\n\nAnd non-hypenated options too! Just use `argv._`!\n-------------------------------------------------\n \nnonopt.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist').argv;\nconsole.log('(%d,%d)', argv.x, argv.y);\nconsole.log(argv._);\n````\n\n***\n\n $ ./nonopt.js -x 6.82 -y 3.35 moo\n (6.82,3.35)\n [ 'moo' ]\n \n $ ./nonopt.js foo -x 0.54 bar -y 1.12 baz\n (0.54,1.12)\n [ 'foo', 'bar', 'baz' ]\n\nPlus, Optimist comes with .usage() and .demand()!\n-------------------------------------------------\n\ndivide.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .usage('Usage: $0 -x [num] -y [num]')\n .demand(['x','y'])\n .argv;\n\nconsole.log(argv.x / argv.y);\n````\n\n***\n \n $ ./divide.js -x 55 -y 11\n 5\n \n $ node ./divide.js -x 4.91 -z 2.51\n Usage: node ./divide.js -x [num] -y [num]\n\n Options:\n -x [required]\n -y [required]\n\n Missing required arguments: y\n\nEVEN MORE HOLY COW\n------------------\n\ndefault_singles.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .default('x', 10)\n .default('y', 10)\n .argv\n;\nconsole.log(argv.x + argv.y);\n````\n\n***\n\n $ ./default_singles.js -x 5\n 15\n\ndefault_hash.js:\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .default({ x : 10, y : 10 })\n .argv\n;\nconsole.log(argv.x + argv.y);\n````\n\n***\n\n $ ./default_hash.js -y 7\n 17\n\nAnd if you really want to get all descriptive about it...\n---------------------------------------------------------\n\nboolean_single.js\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .boolean('v')\n .argv\n;\nconsole.dir(argv);\n````\n\n***\n\n $ ./boolean_single.js -v foo bar baz\n true\n [ 'bar', 'baz', 'foo' ]\n\nboolean_double.js\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .boolean(['x','y','z'])\n .argv\n;\nconsole.dir([ argv.x, argv.y, argv.z ]);\nconsole.dir(argv._);\n````\n\n***\n\n $ ./boolean_double.js -x -z one two three\n [ true, false, true ]\n [ 'one', 'two', 'three' ]\n\nOptimist is here to help...\n---------------------------\n\nYou can describe parameters for help messages and set aliases. Optimist figures\nout how to format a handy help string automatically.\n\nline_count.js\n\n````javascript\n#!/usr/bin/env node\nvar argv = require('optimist')\n .usage('Count the lines in a file.\\nUsage: $0')\n .demand('f')\n .alias('f', 'file')\n .describe('f', 'Load a file')\n .argv\n;\n\nvar fs = require('fs');\nvar s = fs.createReadStream(argv.file);\n\nvar lines = 0;\ns.on('data', function (buf) {\n lines += buf.toString().match(/\\n/g).length;\n});\n\ns.on('end', function () {\n console.log(lines);\n});\n````\n\n***\n\n $ node line_count.js\n Count the lines in a file.\n Usage: node ./line_count.js\n\n Options:\n -f, --file Load a file [required]\n\n Missing required arguments: f\n\n $ node line_count.js --file line_count.js \n 20\n \n $ node line_count.js -f line_count.js \n 20\n\nmethods\n=======\n\nBy itself,\n\n````javascript\nrequire('optimist').argv\n`````\n\nwill use `process.argv` array to construct the `argv` object.\n\nYou can pass in the `process.argv` yourself:\n\n````javascript\nrequire('optimist')([ '-x', '1', '-y', '2' ]).argv\n````\n\nor use .parse() to do the same thing:\n\n````javascript\nrequire('optimist').parse([ '-x', '1', '-y', '2' ])\n````\n\nThe rest of these methods below come in just before the terminating `.argv`.\n\n.alias(key, alias)\n------------------\n\nSet key names as equivalent such that updates to a key will propagate to aliases\nand vice-versa.\n\nOptionally `.alias()` can take an object that maps keys to aliases.\n\n.default(key, value)\n--------------------\n\nSet `argv[key]` to `value` if no option was specified on `process.argv`.\n\nOptionally `.default()` can take an object that maps keys to default values.\n\n.demand(key)\n------------\n\nIf `key` is a string, show the usage information and exit if `key` wasn't\nspecified in `process.argv`.\n\nIf `key` is a number, demand at least as many non-option arguments, which show\nup in `argv._`.\n\nIf `key` is an Array, demand each element.\n\n.describe(key, desc)\n--------------------\n\nDescribe a `key` for the generated usage information.\n\nOptionally `.describe()` can take an object that maps keys to descriptions.\n\n.options(key, opt)\n------------------\n\nInstead of chaining together `.alias().demand().default()`, you can specify\nkeys in `opt` for each of the chainable methods.\n\nFor example:\n\n````javascript\nvar argv = require('optimist')\n .options('f', {\n alias : 'file',\n default : '/etc/passwd',\n })\n .argv\n;\n````\n\nis the same as\n\n````javascript\nvar argv = require('optimist')\n .alias('f', 'file')\n .default('f', '/etc/passwd')\n .argv\n;\n````\n\nOptionally `.options()` can take an object that maps keys to `opt` parameters.\n\n.usage(message)\n---------------\n\nSet a usage message to show which commands to use. Inside `message`, the string\n`$0` will get interpolated to the current script name or node command for the\npresent script similar to how `$0` works in bash or perl.\n\n.check(fn)\n----------\n\nCheck that certain conditions are met in the provided arguments.\n\nIf `fn` throws or returns `false`, show the thrown error, usage information, and\nexit.\n\n.boolean(key)\n-------------\n\nInterpret `key` as a boolean. If a non-flag option follows `key` in\n`process.argv`, that string won't get set as the value of `key`.\n\nIf `key` never shows up as a flag in `process.arguments`, `argv[key]` will be\n`false`.\n\nIf `key` is an Array, interpret all the elements as booleans.\n\n.string(key)\n------------\n\nTell the parser logic not to interpret `key` as a number or boolean.\nThis can be useful if you need to preserve leading zeros in an input.\n\nIf `key` is an Array, interpret all the elements as strings.\n\n.wrap(columns)\n--------------\n\nFormat usage output to wrap at `columns` many columns.\n\n.help()\n-------\n\nReturn the generated usage string.\n\n.showHelp(fn=console.error)\n---------------------------\n\nPrint the usage data using `fn` for printing.\n\n.parse(args)\n------------\n\nParse `args` instead of `process.argv`. Returns the `argv` object.\n\n.argv\n-----\n\nGet the arguments as a plain old object.\n\nArguments without a corresponding flag show up in the `argv._` array.\n\nThe script name or node command is available at `argv.$0` similarly to how `$0`\nworks in bash or perl.\n\nparsing tricks\n==============\n\nstop parsing\n------------\n\nUse `--` to stop parsing flags and stuff the remainder into `argv._`.\n\n $ node examples/reflect.js -a 1 -b 2 -- -c 3 -d 4\n { _: [ '-c', '3', '-d', '4' ],\n '$0': 'node ./examples/reflect.js',\n a: 1,\n b: 2 }\n\nnegate fields\n-------------\n\nIf you want to explicity set a field to false instead of just leaving it\nundefined or to override a default you can do `--no-key`.\n\n $ node examples/reflect.js -a --no-b\n { _: [],\n '$0': 'node ./examples/reflect.js',\n a: true,\n b: false }\n\nnumbers\n-------\n\nEvery argument that looks like a number (`!isNaN(Number(arg))`) is converted to\none. This way you can just `net.createConnection(argv.port)` and you can add\nnumbers out of `argv` with `+` without having that mean concatenation,\nwhich is super frustrating.\n\nduplicates\n----------\n\nIf you specify a flag multiple times it will get turned into an array containing\nall the values in order.\n\n $ node examples/reflect.js -x 5 -x 8 -x 0\n { _: [],\n '$0': 'node ./examples/reflect.js',\n x: [ 5, 8, 0 ] }\n\ndot notation\n------------\n\nWhen you use dots (`.`s) in argument names, an implicit object path is assumed.\nThis lets you organize arguments into nested objects.\n\n $ node examples/reflect.js --foo.bar.baz=33 --foo.quux=5\n { _: [],\n '$0': 'node ./examples/reflect.js',\n foo: { bar: { baz: 33 }, quux: 5 } }\n\ninstallation\n============\n\nWith [npm](http://github.com/isaacs/npm), just do:\n npm install optimist\n \nor clone this project on github:\n\n git clone http://github.com/substack/node-optimist.git\n\nTo run the tests with [expresso](http://github.com/visionmedia/expresso),\njust do:\n \n expresso\n\ninspired By\n===========\n\nThis module is loosely inspired by Perl's\n[Getopt::Casual](http://search.cpan.org/~photo/Getopt-Casual-0.13.1/Casual.pm).\n", + "readmeFilename": "readme.markdown", + "bugs": { + "url": "https://github.com/substack/node-optimist/issues" + }, + "_id": "optimist@0.3.7", + "dist": { + "shasum": "cdd8eb13a6408cac46182ebcb0fd831d98133bd0" + }, + "_from": "optimist@~0.3.5", + "_resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz" +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/readme.markdown b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/readme.markdown new file mode 100644 index 0000000..ad9d3fd --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/readme.markdown @@ -0,0 +1,487 @@ +optimist +======== + +Optimist is a node.js library for option parsing for people who hate option +parsing. More specifically, this module is for people who like all the --bells +and -whistlz of program usage but think optstrings are a waste of time. + +With optimist, option parsing doesn't have to suck (as much). + +[![build status](https://secure.travis-ci.org/substack/node-optimist.png)](http://travis-ci.org/substack/node-optimist) + +examples +======== + +With Optimist, the options are just a hash! No optstrings attached. +------------------------------------------------------------------- + +xup.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist').argv; + +if (argv.rif - 5 * argv.xup > 7.138) { + console.log('Buy more riffiwobbles'); +} +else { + console.log('Sell the xupptumblers'); +} +```` + +*** + + $ ./xup.js --rif=55 --xup=9.52 + Buy more riffiwobbles + + $ ./xup.js --rif 12 --xup 8.1 + Sell the xupptumblers + +![This one's optimistic.](http://substack.net/images/optimistic.png) + +But wait! There's more! You can do short options: +------------------------------------------------- + +short.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist').argv; +console.log('(%d,%d)', argv.x, argv.y); +```` + +*** + + $ ./short.js -x 10 -y 21 + (10,21) + +And booleans, both long and short (and grouped): +---------------------------------- + +bool.js: + +````javascript +#!/usr/bin/env node +var util = require('util'); +var argv = require('optimist').argv; + +if (argv.s) { + util.print(argv.fr ? 'Le chat dit: ' : 'The cat says: '); +} +console.log( + (argv.fr ? 'miaou' : 'meow') + (argv.p ? '.' : '') +); +```` + +*** + + $ ./bool.js -s + The cat says: meow + + $ ./bool.js -sp + The cat says: meow. + + $ ./bool.js -sp --fr + Le chat dit: miaou. + +And non-hypenated options too! Just use `argv._`! +------------------------------------------------- + +nonopt.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist').argv; +console.log('(%d,%d)', argv.x, argv.y); +console.log(argv._); +```` + +*** + + $ ./nonopt.js -x 6.82 -y 3.35 moo + (6.82,3.35) + [ 'moo' ] + + $ ./nonopt.js foo -x 0.54 bar -y 1.12 baz + (0.54,1.12) + [ 'foo', 'bar', 'baz' ] + +Plus, Optimist comes with .usage() and .demand()! +------------------------------------------------- + +divide.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .usage('Usage: $0 -x [num] -y [num]') + .demand(['x','y']) + .argv; + +console.log(argv.x / argv.y); +```` + +*** + + $ ./divide.js -x 55 -y 11 + 5 + + $ node ./divide.js -x 4.91 -z 2.51 + Usage: node ./divide.js -x [num] -y [num] + + Options: + -x [required] + -y [required] + + Missing required arguments: y + +EVEN MORE HOLY COW +------------------ + +default_singles.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .default('x', 10) + .default('y', 10) + .argv +; +console.log(argv.x + argv.y); +```` + +*** + + $ ./default_singles.js -x 5 + 15 + +default_hash.js: + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .default({ x : 10, y : 10 }) + .argv +; +console.log(argv.x + argv.y); +```` + +*** + + $ ./default_hash.js -y 7 + 17 + +And if you really want to get all descriptive about it... +--------------------------------------------------------- + +boolean_single.js + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .boolean('v') + .argv +; +console.dir(argv); +```` + +*** + + $ ./boolean_single.js -v foo bar baz + true + [ 'bar', 'baz', 'foo' ] + +boolean_double.js + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .boolean(['x','y','z']) + .argv +; +console.dir([ argv.x, argv.y, argv.z ]); +console.dir(argv._); +```` + +*** + + $ ./boolean_double.js -x -z one two three + [ true, false, true ] + [ 'one', 'two', 'three' ] + +Optimist is here to help... +--------------------------- + +You can describe parameters for help messages and set aliases. Optimist figures +out how to format a handy help string automatically. + +line_count.js + +````javascript +#!/usr/bin/env node +var argv = require('optimist') + .usage('Count the lines in a file.\nUsage: $0') + .demand('f') + .alias('f', 'file') + .describe('f', 'Load a file') + .argv +; + +var fs = require('fs'); +var s = fs.createReadStream(argv.file); + +var lines = 0; +s.on('data', function (buf) { + lines += buf.toString().match(/\n/g).length; +}); + +s.on('end', function () { + console.log(lines); +}); +```` + +*** + + $ node line_count.js + Count the lines in a file. + Usage: node ./line_count.js + + Options: + -f, --file Load a file [required] + + Missing required arguments: f + + $ node line_count.js --file line_count.js + 20 + + $ node line_count.js -f line_count.js + 20 + +methods +======= + +By itself, + +````javascript +require('optimist').argv +````` + +will use `process.argv` array to construct the `argv` object. + +You can pass in the `process.argv` yourself: + +````javascript +require('optimist')([ '-x', '1', '-y', '2' ]).argv +```` + +or use .parse() to do the same thing: + +````javascript +require('optimist').parse([ '-x', '1', '-y', '2' ]) +```` + +The rest of these methods below come in just before the terminating `.argv`. + +.alias(key, alias) +------------------ + +Set key names as equivalent such that updates to a key will propagate to aliases +and vice-versa. + +Optionally `.alias()` can take an object that maps keys to aliases. + +.default(key, value) +-------------------- + +Set `argv[key]` to `value` if no option was specified on `process.argv`. + +Optionally `.default()` can take an object that maps keys to default values. + +.demand(key) +------------ + +If `key` is a string, show the usage information and exit if `key` wasn't +specified in `process.argv`. + +If `key` is a number, demand at least as many non-option arguments, which show +up in `argv._`. + +If `key` is an Array, demand each element. + +.describe(key, desc) +-------------------- + +Describe a `key` for the generated usage information. + +Optionally `.describe()` can take an object that maps keys to descriptions. + +.options(key, opt) +------------------ + +Instead of chaining together `.alias().demand().default()`, you can specify +keys in `opt` for each of the chainable methods. + +For example: + +````javascript +var argv = require('optimist') + .options('f', { + alias : 'file', + default : '/etc/passwd', + }) + .argv +; +```` + +is the same as + +````javascript +var argv = require('optimist') + .alias('f', 'file') + .default('f', '/etc/passwd') + .argv +; +```` + +Optionally `.options()` can take an object that maps keys to `opt` parameters. + +.usage(message) +--------------- + +Set a usage message to show which commands to use. Inside `message`, the string +`$0` will get interpolated to the current script name or node command for the +present script similar to how `$0` works in bash or perl. + +.check(fn) +---------- + +Check that certain conditions are met in the provided arguments. + +If `fn` throws or returns `false`, show the thrown error, usage information, and +exit. + +.boolean(key) +------------- + +Interpret `key` as a boolean. If a non-flag option follows `key` in +`process.argv`, that string won't get set as the value of `key`. + +If `key` never shows up as a flag in `process.arguments`, `argv[key]` will be +`false`. + +If `key` is an Array, interpret all the elements as booleans. + +.string(key) +------------ + +Tell the parser logic not to interpret `key` as a number or boolean. +This can be useful if you need to preserve leading zeros in an input. + +If `key` is an Array, interpret all the elements as strings. + +.wrap(columns) +-------------- + +Format usage output to wrap at `columns` many columns. + +.help() +------- + +Return the generated usage string. + +.showHelp(fn=console.error) +--------------------------- + +Print the usage data using `fn` for printing. + +.parse(args) +------------ + +Parse `args` instead of `process.argv`. Returns the `argv` object. + +.argv +----- + +Get the arguments as a plain old object. + +Arguments without a corresponding flag show up in the `argv._` array. + +The script name or node command is available at `argv.$0` similarly to how `$0` +works in bash or perl. + +parsing tricks +============== + +stop parsing +------------ + +Use `--` to stop parsing flags and stuff the remainder into `argv._`. + + $ node examples/reflect.js -a 1 -b 2 -- -c 3 -d 4 + { _: [ '-c', '3', '-d', '4' ], + '$0': 'node ./examples/reflect.js', + a: 1, + b: 2 } + +negate fields +------------- + +If you want to explicity set a field to false instead of just leaving it +undefined or to override a default you can do `--no-key`. + + $ node examples/reflect.js -a --no-b + { _: [], + '$0': 'node ./examples/reflect.js', + a: true, + b: false } + +numbers +------- + +Every argument that looks like a number (`!isNaN(Number(arg))`) is converted to +one. This way you can just `net.createConnection(argv.port)` and you can add +numbers out of `argv` with `+` without having that mean concatenation, +which is super frustrating. + +duplicates +---------- + +If you specify a flag multiple times it will get turned into an array containing +all the values in order. + + $ node examples/reflect.js -x 5 -x 8 -x 0 + { _: [], + '$0': 'node ./examples/reflect.js', + x: [ 5, 8, 0 ] } + +dot notation +------------ + +When you use dots (`.`s) in argument names, an implicit object path is assumed. +This lets you organize arguments into nested objects. + + $ node examples/reflect.js --foo.bar.baz=33 --foo.quux=5 + { _: [], + '$0': 'node ./examples/reflect.js', + foo: { bar: { baz: 33 }, quux: 5 } } + +installation +============ + +With [npm](http://github.com/isaacs/npm), just do: + npm install optimist + +or clone this project on github: + + git clone http://github.com/substack/node-optimist.git + +To run the tests with [expresso](http://github.com/visionmedia/expresso), +just do: + + expresso + +inspired By +=========== + +This module is loosely inspired by Perl's +[Getopt::Casual](http://search.cpan.org/~photo/Getopt-Casual-0.13.1/Casual.pm). diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/test/_.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/test/_.js new file mode 100644 index 0000000..d9c58b3 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/test/_.js @@ -0,0 +1,71 @@ +var spawn = require('child_process').spawn; +var test = require('tap').test; + +test('dotSlashEmpty', testCmd('./bin.js', [])); + +test('dotSlashArgs', testCmd('./bin.js', [ 'a', 'b', 'c' ])); + +test('nodeEmpty', testCmd('node bin.js', [])); + +test('nodeArgs', testCmd('node bin.js', [ 'x', 'y', 'z' ])); + +test('whichNodeEmpty', function (t) { + var which = spawn('which', ['node']); + + which.stdout.on('data', function (buf) { + t.test( + testCmd(buf.toString().trim() + ' bin.js', []) + ); + t.end(); + }); + + which.stderr.on('data', function (err) { + assert.error(err); + t.end(); + }); +}); + +test('whichNodeArgs', function (t) { + var which = spawn('which', ['node']); + + which.stdout.on('data', function (buf) { + t.test( + testCmd(buf.toString().trim() + ' bin.js', [ 'q', 'r' ]) + ); + t.end(); + }); + + which.stderr.on('data', function (err) { + t.error(err); + t.end(); + }); +}); + +function testCmd (cmd, args) { + + return function (t) { + var to = setTimeout(function () { + assert.fail('Never got stdout data.') + }, 5000); + + var oldDir = process.cwd(); + process.chdir(__dirname + '/_'); + + var cmds = cmd.split(' '); + + var bin = spawn(cmds[0], cmds.slice(1).concat(args.map(String))); + process.chdir(oldDir); + + bin.stderr.on('data', function (err) { + t.error(err); + t.end(); + }); + + bin.stdout.on('data', function (buf) { + clearTimeout(to); + var _ = JSON.parse(buf.toString()); + t.same(_.map(String), args.map(String)); + t.end(); + }); + }; +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/test/_/argv.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/test/_/argv.js new file mode 100644 index 0000000..3d09606 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/test/_/argv.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +console.log(JSON.stringify(process.argv)); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/test/_/bin.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/test/_/bin.js new file mode 100755 index 0000000..4a18d85 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/test/_/bin.js @@ -0,0 +1,3 @@ +#!/usr/bin/env node +var argv = require('../../index').argv +console.log(JSON.stringify(argv._)); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/test/parse.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/test/parse.js new file mode 100644 index 0000000..d320f43 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/test/parse.js @@ -0,0 +1,446 @@ +var optimist = require('../index'); +var path = require('path'); +var test = require('tap').test; + +var $0 = 'node ./' + path.relative(process.cwd(), __filename); + +test('short boolean', function (t) { + var parse = optimist.parse([ '-b' ]); + t.same(parse, { b : true, _ : [], $0 : $0 }); + t.same(typeof parse.b, 'boolean'); + t.end(); +}); + +test('long boolean', function (t) { + t.same( + optimist.parse([ '--bool' ]), + { bool : true, _ : [], $0 : $0 } + ); + t.end(); +}); + +test('bare', function (t) { + t.same( + optimist.parse([ 'foo', 'bar', 'baz' ]), + { _ : [ 'foo', 'bar', 'baz' ], $0 : $0 } + ); + t.end(); +}); + +test('short group', function (t) { + t.same( + optimist.parse([ '-cats' ]), + { c : true, a : true, t : true, s : true, _ : [], $0 : $0 } + ); + t.end(); +}); + +test('short group next', function (t) { + t.same( + optimist.parse([ '-cats', 'meow' ]), + { c : true, a : true, t : true, s : 'meow', _ : [], $0 : $0 } + ); + t.end(); +}); + +test('short capture', function (t) { + t.same( + optimist.parse([ '-h', 'localhost' ]), + { h : 'localhost', _ : [], $0 : $0 } + ); + t.end(); +}); + +test('short captures', function (t) { + t.same( + optimist.parse([ '-h', 'localhost', '-p', '555' ]), + { h : 'localhost', p : 555, _ : [], $0 : $0 } + ); + t.end(); +}); + +test('long capture sp', function (t) { + t.same( + optimist.parse([ '--pow', 'xixxle' ]), + { pow : 'xixxle', _ : [], $0 : $0 } + ); + t.end(); +}); + +test('long capture eq', function (t) { + t.same( + optimist.parse([ '--pow=xixxle' ]), + { pow : 'xixxle', _ : [], $0 : $0 } + ); + t.end() +}); + +test('long captures sp', function (t) { + t.same( + optimist.parse([ '--host', 'localhost', '--port', '555' ]), + { host : 'localhost', port : 555, _ : [], $0 : $0 } + ); + t.end(); +}); + +test('long captures eq', function (t) { + t.same( + optimist.parse([ '--host=localhost', '--port=555' ]), + { host : 'localhost', port : 555, _ : [], $0 : $0 } + ); + t.end(); +}); + +test('mixed short bool and capture', function (t) { + t.same( + optimist.parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]), + { + f : true, p : 555, h : 'localhost', + _ : [ 'script.js' ], $0 : $0, + } + ); + t.end(); +}); + +test('short and long', function (t) { + t.same( + optimist.parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]), + { + f : true, p : 555, h : 'localhost', + _ : [ 'script.js' ], $0 : $0, + } + ); + t.end(); +}); + +test('no', function (t) { + t.same( + optimist.parse([ '--no-moo' ]), + { moo : false, _ : [], $0 : $0 } + ); + t.end(); +}); + +test('multi', function (t) { + t.same( + optimist.parse([ '-v', 'a', '-v', 'b', '-v', 'c' ]), + { v : ['a','b','c'], _ : [], $0 : $0 } + ); + t.end(); +}); + +test('comprehensive', function (t) { + t.same( + optimist.parse([ + '--name=meowmers', 'bare', '-cats', 'woo', + '-h', 'awesome', '--multi=quux', + '--key', 'value', + '-b', '--bool', '--no-meep', '--multi=baz', + '--', '--not-a-flag', 'eek' + ]), + { + c : true, + a : true, + t : true, + s : 'woo', + h : 'awesome', + b : true, + bool : true, + key : 'value', + multi : [ 'quux', 'baz' ], + meep : false, + name : 'meowmers', + _ : [ 'bare', '--not-a-flag', 'eek' ], + $0 : $0 + } + ); + t.end(); +}); + +test('nums', function (t) { + var argv = optimist.parse([ + '-x', '1234', + '-y', '5.67', + '-z', '1e7', + '-w', '10f', + '--hex', '0xdeadbeef', + '789', + ]); + t.same(argv, { + x : 1234, + y : 5.67, + z : 1e7, + w : '10f', + hex : 0xdeadbeef, + _ : [ 789 ], + $0 : $0 + }); + t.same(typeof argv.x, 'number'); + t.same(typeof argv.y, 'number'); + t.same(typeof argv.z, 'number'); + t.same(typeof argv.w, 'string'); + t.same(typeof argv.hex, 'number'); + t.same(typeof argv._[0], 'number'); + t.end(); +}); + +test('flag boolean', function (t) { + var parse = optimist([ '-t', 'moo' ]).boolean(['t']).argv; + t.same(parse, { t : true, _ : [ 'moo' ], $0 : $0 }); + t.same(typeof parse.t, 'boolean'); + t.end(); +}); + +test('flag boolean value', function (t) { + var parse = optimist(['--verbose', 'false', 'moo', '-t', 'true']) + .boolean(['t', 'verbose']).default('verbose', true).argv; + + t.same(parse, { + verbose: false, + t: true, + _: ['moo'], + $0 : $0 + }); + + t.same(typeof parse.verbose, 'boolean'); + t.same(typeof parse.t, 'boolean'); + t.end(); +}); + +test('flag boolean default false', function (t) { + var parse = optimist(['moo']) + .boolean(['t', 'verbose']) + .default('verbose', false) + .default('t', false).argv; + + t.same(parse, { + verbose: false, + t: false, + _: ['moo'], + $0 : $0 + }); + + t.same(typeof parse.verbose, 'boolean'); + t.same(typeof parse.t, 'boolean'); + t.end(); + +}); + +test('boolean groups', function (t) { + var parse = optimist([ '-x', '-z', 'one', 'two', 'three' ]) + .boolean(['x','y','z']).argv; + + t.same(parse, { + x : true, + y : false, + z : true, + _ : [ 'one', 'two', 'three' ], + $0 : $0 + }); + + t.same(typeof parse.x, 'boolean'); + t.same(typeof parse.y, 'boolean'); + t.same(typeof parse.z, 'boolean'); + t.end(); +}); + +test('newlines in params' , function (t) { + var args = optimist.parse([ '-s', "X\nX" ]) + t.same(args, { _ : [], s : "X\nX", $0 : $0 }); + + // reproduce in bash: + // VALUE="new + // line" + // node program.js --s="$VALUE" + args = optimist.parse([ "--s=X\nX" ]) + t.same(args, { _ : [], s : "X\nX", $0 : $0 }); + t.end(); +}); + +test('strings' , function (t) { + var s = optimist([ '-s', '0001234' ]).string('s').argv.s; + t.same(s, '0001234'); + t.same(typeof s, 'string'); + + var x = optimist([ '-x', '56' ]).string('x').argv.x; + t.same(x, '56'); + t.same(typeof x, 'string'); + t.end(); +}); + +test('stringArgs', function (t) { + var s = optimist([ ' ', ' ' ]).string('_').argv._; + t.same(s.length, 2); + t.same(typeof s[0], 'string'); + t.same(s[0], ' '); + t.same(typeof s[1], 'string'); + t.same(s[1], ' '); + t.end(); +}); + +test('slashBreak', function (t) { + t.same( + optimist.parse([ '-I/foo/bar/baz' ]), + { I : '/foo/bar/baz', _ : [], $0 : $0 } + ); + t.same( + optimist.parse([ '-xyz/foo/bar/baz' ]), + { x : true, y : true, z : '/foo/bar/baz', _ : [], $0 : $0 } + ); + t.end(); +}); + +test('alias', function (t) { + var argv = optimist([ '-f', '11', '--zoom', '55' ]) + .alias('z', 'zoom') + .argv + ; + t.equal(argv.zoom, 55); + t.equal(argv.z, argv.zoom); + t.equal(argv.f, 11); + t.end(); +}); + +test('multiAlias', function (t) { + var argv = optimist([ '-f', '11', '--zoom', '55' ]) + .alias('z', [ 'zm', 'zoom' ]) + .argv + ; + t.equal(argv.zoom, 55); + t.equal(argv.z, argv.zoom); + t.equal(argv.z, argv.zm); + t.equal(argv.f, 11); + t.end(); +}); + +test('boolean default true', function (t) { + var argv = optimist.options({ + sometrue: { + boolean: true, + default: true + } + }).argv; + + t.equal(argv.sometrue, true); + t.end(); +}); + +test('boolean default false', function (t) { + var argv = optimist.options({ + somefalse: { + boolean: true, + default: false + } + }).argv; + + t.equal(argv.somefalse, false); + t.end(); +}); + +test('nested dotted objects', function (t) { + var argv = optimist([ + '--foo.bar', '3', '--foo.baz', '4', + '--foo.quux.quibble', '5', '--foo.quux.o_O', + '--beep.boop' + ]).argv; + + t.same(argv.foo, { + bar : 3, + baz : 4, + quux : { + quibble : 5, + o_O : true + }, + }); + t.same(argv.beep, { boop : true }); + t.end(); +}); + +test('boolean and alias with chainable api', function (t) { + var aliased = [ '-h', 'derp' ]; + var regular = [ '--herp', 'derp' ]; + var opts = { + herp: { alias: 'h', boolean: true } + }; + var aliasedArgv = optimist(aliased) + .boolean('herp') + .alias('h', 'herp') + .argv; + var propertyArgv = optimist(regular) + .boolean('herp') + .alias('h', 'herp') + .argv; + var expected = { + herp: true, + h: true, + '_': [ 'derp' ], + '$0': $0, + }; + + t.same(aliasedArgv, expected); + t.same(propertyArgv, expected); + t.end(); +}); + +test('boolean and alias with options hash', function (t) { + var aliased = [ '-h', 'derp' ]; + var regular = [ '--herp', 'derp' ]; + var opts = { + herp: { alias: 'h', boolean: true } + }; + var aliasedArgv = optimist(aliased) + .options(opts) + .argv; + var propertyArgv = optimist(regular).options(opts).argv; + var expected = { + herp: true, + h: true, + '_': [ 'derp' ], + '$0': $0, + }; + + t.same(aliasedArgv, expected); + t.same(propertyArgv, expected); + + t.end(); +}); + +test('boolean and alias using explicit true', function (t) { + var aliased = [ '-h', 'true' ]; + var regular = [ '--herp', 'true' ]; + var opts = { + herp: { alias: 'h', boolean: true } + }; + var aliasedArgv = optimist(aliased) + .boolean('h') + .alias('h', 'herp') + .argv; + var propertyArgv = optimist(regular) + .boolean('h') + .alias('h', 'herp') + .argv; + var expected = { + herp: true, + h: true, + '_': [ ], + '$0': $0, + }; + + t.same(aliasedArgv, expected); + t.same(propertyArgv, expected); + t.end(); +}); + +// regression, see https://github.com/substack/node-optimist/issues/71 +test('boolean and --x=true', function(t) { + var parsed = optimist(['--boool', '--other=true']).boolean('boool').argv; + + t.same(parsed.boool, true); + t.same(parsed.other, 'true'); + + parsed = optimist(['--boool', '--other=false']).boolean('boool').argv; + + t.same(parsed.boool, true); + t.same(parsed.other, 'false'); + t.end(); +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/test/usage.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/test/usage.js new file mode 100644 index 0000000..300454c --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/optimist/test/usage.js @@ -0,0 +1,292 @@ +var Hash = require('hashish'); +var optimist = require('../index'); +var test = require('tap').test; + +test('usageFail', function (t) { + var r = checkUsage(function () { + return optimist('-x 10 -z 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .demand(['x','y']) + .argv; + }); + t.same( + r.result, + { x : 10, z : 20, _ : [], $0 : './usage' } + ); + + t.same( + r.errors.join('\n').split(/\n+/), + [ + 'Usage: ./usage -x NUM -y NUM', + 'Options:', + ' -x [required]', + ' -y [required]', + 'Missing required arguments: y', + ] + ); + t.same(r.logs, []); + t.ok(r.exit); + t.end(); +}); + + +test('usagePass', function (t) { + var r = checkUsage(function () { + return optimist('-x 10 -y 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .demand(['x','y']) + .argv; + }); + t.same(r, { + result : { x : 10, y : 20, _ : [], $0 : './usage' }, + errors : [], + logs : [], + exit : false, + }); + t.end(); +}); + +test('checkPass', function (t) { + var r = checkUsage(function () { + return optimist('-x 10 -y 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .check(function (argv) { + if (!('x' in argv)) throw 'You forgot about -x'; + if (!('y' in argv)) throw 'You forgot about -y'; + }) + .argv; + }); + t.same(r, { + result : { x : 10, y : 20, _ : [], $0 : './usage' }, + errors : [], + logs : [], + exit : false, + }); + t.end(); +}); + +test('checkFail', function (t) { + var r = checkUsage(function () { + return optimist('-x 10 -z 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .check(function (argv) { + if (!('x' in argv)) throw 'You forgot about -x'; + if (!('y' in argv)) throw 'You forgot about -y'; + }) + .argv; + }); + + t.same( + r.result, + { x : 10, z : 20, _ : [], $0 : './usage' } + ); + + t.same( + r.errors.join('\n').split(/\n+/), + [ + 'Usage: ./usage -x NUM -y NUM', + 'You forgot about -y' + ] + ); + + t.same(r.logs, []); + t.ok(r.exit); + t.end(); +}); + +test('checkCondPass', function (t) { + function checker (argv) { + return 'x' in argv && 'y' in argv; + } + + var r = checkUsage(function () { + return optimist('-x 10 -y 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .check(checker) + .argv; + }); + t.same(r, { + result : { x : 10, y : 20, _ : [], $0 : './usage' }, + errors : [], + logs : [], + exit : false, + }); + t.end(); +}); + +test('checkCondFail', function (t) { + function checker (argv) { + return 'x' in argv && 'y' in argv; + } + + var r = checkUsage(function () { + return optimist('-x 10 -z 20'.split(' ')) + .usage('Usage: $0 -x NUM -y NUM') + .check(checker) + .argv; + }); + + t.same( + r.result, + { x : 10, z : 20, _ : [], $0 : './usage' } + ); + + t.same( + r.errors.join('\n').split(/\n+/).join('\n'), + 'Usage: ./usage -x NUM -y NUM\n' + + 'Argument check failed: ' + checker.toString() + ); + + t.same(r.logs, []); + t.ok(r.exit); + t.end(); +}); + +test('countPass', function (t) { + var r = checkUsage(function () { + return optimist('1 2 3 --moo'.split(' ')) + .usage('Usage: $0 [x] [y] [z] {OPTIONS}') + .demand(3) + .argv; + }); + t.same(r, { + result : { _ : [ '1', '2', '3' ], moo : true, $0 : './usage' }, + errors : [], + logs : [], + exit : false, + }); + t.end(); +}); + +test('countFail', function (t) { + var r = checkUsage(function () { + return optimist('1 2 --moo'.split(' ')) + .usage('Usage: $0 [x] [y] [z] {OPTIONS}') + .demand(3) + .argv; + }); + t.same( + r.result, + { _ : [ '1', '2' ], moo : true, $0 : './usage' } + ); + + t.same( + r.errors.join('\n').split(/\n+/), + [ + 'Usage: ./usage [x] [y] [z] {OPTIONS}', + 'Not enough non-option arguments: got 2, need at least 3', + ] + ); + + t.same(r.logs, []); + t.ok(r.exit); + t.end(); +}); + +test('defaultSingles', function (t) { + var r = checkUsage(function () { + return optimist('--foo 50 --baz 70 --powsy'.split(' ')) + .default('foo', 5) + .default('bar', 6) + .default('baz', 7) + .argv + ; + }); + t.same(r.result, { + foo : '50', + bar : 6, + baz : '70', + powsy : true, + _ : [], + $0 : './usage', + }); + t.end(); +}); + +test('defaultAliases', function (t) { + var r = checkUsage(function () { + return optimist('') + .alias('f', 'foo') + .default('f', 5) + .argv + ; + }); + t.same(r.result, { + f : '5', + foo : '5', + _ : [], + $0 : './usage', + }); + t.end(); +}); + +test('defaultHash', function (t) { + var r = checkUsage(function () { + return optimist('--foo 50 --baz 70'.split(' ')) + .default({ foo : 10, bar : 20, quux : 30 }) + .argv + ; + }); + t.same(r.result, { + _ : [], + $0 : './usage', + foo : 50, + baz : 70, + bar : 20, + quux : 30, + }); + t.end(); +}); + +test('rebase', function (t) { + t.equal( + optimist.rebase('/home/substack', '/home/substack/foo/bar/baz'), + './foo/bar/baz' + ); + t.equal( + optimist.rebase('/home/substack/foo/bar/baz', '/home/substack'), + '../../..' + ); + t.equal( + optimist.rebase('/home/substack/foo', '/home/substack/pow/zoom.txt'), + '../pow/zoom.txt' + ); + t.end(); +}); + +function checkUsage (f) { + + var exit = false; + + process._exit = process.exit; + process._env = process.env; + process._argv = process.argv; + + process.exit = function (t) { exit = true }; + process.env = Hash.merge(process.env, { _ : 'node' }); + process.argv = [ './usage' ]; + + var errors = []; + var logs = []; + + console._error = console.error; + console.error = function (msg) { errors.push(msg) }; + console._log = console.log; + console.log = function (msg) { logs.push(msg) }; + + var result = f(); + + process.exit = process._exit; + process.env = process._env; + process.argv = process._argv; + + console.error = console._error; + console.log = console._log; + + return { + errors : errors, + logs : logs, + exit : exit, + result : result, + }; +}; diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/.npmignore b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/.npmignore new file mode 100644 index 0000000..3dddf3f --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/.npmignore @@ -0,0 +1,2 @@ +dist/* +node_modules/* diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/.travis.yml b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/.travis.yml new file mode 100644 index 0000000..ddc9c4f --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.8 + - "0.10" \ No newline at end of file diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/CHANGELOG.md b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/CHANGELOG.md new file mode 100644 index 0000000..98b90d5 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/CHANGELOG.md @@ -0,0 +1,112 @@ +# Change Log + +## 0.1.31 + +* Delay parsing the mappings in SourceMapConsumer until queried for a source + location. + +* Support Sass source maps (which at the time of writing deviate from the spec + in small ways) in SourceMapConsumer. + +## 0.1.30 + +* Do not join source root with a source, when the source is a data URI. + +* Extend the test runner to allow running single specific test files at a time. + +* Performance improvements in `SourceNode.prototype.walk` and + `SourceMapConsumer.prototype.eachMapping`. + +* Source map browser builds will now work inside Workers. + +* Better error messages when attempting to add an invalid mapping to a + `SourceMapGenerator`. + +## 0.1.29 + +* Allow duplicate entries in the `names` and `sources` arrays of source maps + (usually from TypeScript) we are parsing. Fixes github isse 72. + +## 0.1.28 + +* Skip duplicate mappings when creating source maps from SourceNode; github + issue 75. + +## 0.1.27 + +* Don't throw an error when the `file` property is missing in SourceMapConsumer, + we don't use it anyway. + +## 0.1.26 + +* Fix SourceNode.fromStringWithSourceMap for empty maps. Fixes github issue 70. + +## 0.1.25 + +* Make compatible with browserify + +## 0.1.24 + +* Fix issue with absolute paths and `file://` URIs. See + https://bugzilla.mozilla.org/show_bug.cgi?id=885597 + +## 0.1.23 + +* Fix issue with absolute paths and sourcesContent, github issue 64. + +## 0.1.22 + +* Ignore duplicate mappings in SourceMapGenerator. Fixes github issue 21. + +## 0.1.21 + +* Fixed handling of sources that start with a slash so that they are relative to + the source root's host. + +## 0.1.20 + +* Fixed github issue #43: absolute URLs aren't joined with the source root + anymore. + +## 0.1.19 + +* Using Travis CI to run tests. + +## 0.1.18 + +* Fixed a bug in the handling of sourceRoot. + +## 0.1.17 + +* Added SourceNode.fromStringWithSourceMap. + +## 0.1.16 + +* Added missing documentation. + +* Fixed the generating of empty mappings in SourceNode. + +## 0.1.15 + +* Added SourceMapGenerator.applySourceMap. + +## 0.1.14 + +* The sourceRoot is now handled consistently. + +## 0.1.13 + +* Added SourceMapGenerator.fromSourceMap. + +## 0.1.12 + +* SourceNode now generates empty mappings too. + +## 0.1.11 + +* Added name support to SourceNode. + +## 0.1.10 + +* Added sourcesContent support to the customer and generator. + diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/LICENSE b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/LICENSE new file mode 100644 index 0000000..ed1b7cf --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/LICENSE @@ -0,0 +1,28 @@ + +Copyright (c) 2009-2011, Mozilla Foundation and contributors +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 names of the Mozilla Foundation nor the names of project + 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/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/Makefile.dryice.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/Makefile.dryice.js new file mode 100644 index 0000000..d6fc26a --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/Makefile.dryice.js @@ -0,0 +1,166 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +var path = require('path'); +var fs = require('fs'); +var copy = require('dryice').copy; + +function removeAmdefine(src) { + src = String(src).replace( + /if\s*\(typeof\s*define\s*!==\s*'function'\)\s*{\s*var\s*define\s*=\s*require\('amdefine'\)\(module,\s*require\);\s*}\s*/g, + ''); + src = src.replace( + /\b(define\(.*)('amdefine',?)/gm, + '$1'); + return src; +} +removeAmdefine.onRead = true; + +function makeNonRelative(src) { + return src + .replace(/require\('.\//g, 'require(\'source-map/') + .replace(/\.\.\/\.\.\/lib\//g, ''); +} +makeNonRelative.onRead = true; + +function buildBrowser() { + console.log('\nCreating dist/source-map.js'); + + var project = copy.createCommonJsProject({ + roots: [ path.join(__dirname, 'lib') ] + }); + + copy({ + source: [ + 'build/mini-require.js', + { + project: project, + require: [ 'source-map/source-map-generator', + 'source-map/source-map-consumer', + 'source-map/source-node'] + }, + 'build/suffix-browser.js' + ], + filter: [ + copy.filter.moduleDefines, + removeAmdefine + ], + dest: 'dist/source-map.js' + }); +} + +function buildBrowserMin() { + console.log('\nCreating dist/source-map.min.js'); + + copy({ + source: 'dist/source-map.js', + filter: copy.filter.uglifyjs, + dest: 'dist/source-map.min.js' + }); +} + +function buildFirefox() { + console.log('\nCreating dist/SourceMap.jsm'); + + var project = copy.createCommonJsProject({ + roots: [ path.join(__dirname, 'lib') ] + }); + + copy({ + source: [ + 'build/prefix-source-map.jsm', + { + project: project, + require: [ 'source-map/source-map-consumer', + 'source-map/source-map-generator', + 'source-map/source-node' ] + }, + 'build/suffix-source-map.jsm' + ], + filter: [ + copy.filter.moduleDefines, + removeAmdefine, + makeNonRelative + ], + dest: 'dist/SourceMap.jsm' + }); + + // Create dist/test/Utils.jsm + console.log('\nCreating dist/test/Utils.jsm'); + + project = copy.createCommonJsProject({ + roots: [ __dirname, path.join(__dirname, 'lib') ] + }); + + copy({ + source: [ + 'build/prefix-utils.jsm', + 'build/assert-shim.js', + { + project: project, + require: [ 'test/source-map/util' ] + }, + 'build/suffix-utils.jsm' + ], + filter: [ + copy.filter.moduleDefines, + removeAmdefine, + makeNonRelative + ], + dest: 'dist/test/Utils.jsm' + }); + + function isTestFile(f) { + return /^test\-.*?\.js/.test(f); + } + + var testFiles = fs.readdirSync(path.join(__dirname, 'test', 'source-map')).filter(isTestFile); + + testFiles.forEach(function (testFile) { + console.log('\nCreating', path.join('dist', 'test', testFile.replace(/\-/g, '_'))); + + copy({ + source: [ + 'build/test-prefix.js', + path.join('test', 'source-map', testFile), + 'build/test-suffix.js' + ], + filter: [ + removeAmdefine, + makeNonRelative, + function (input, source) { + return input.replace('define(', + 'define("' + + path.join('test', 'source-map', testFile.replace(/\.js$/, '')) + + '", ["require", "exports", "module"], '); + }, + function (input, source) { + return input.replace('{THIS_MODULE}', function () { + return "test/source-map/" + testFile.replace(/\.js$/, ''); + }); + } + ], + dest: path.join('dist', 'test', testFile.replace(/\-/g, '_')) + }); + }); +} + +function ensureDir(name) { + var dirExists = false; + try { + dirExists = fs.statSync(name).isDirectory(); + } catch (err) {} + + if (!dirExists) { + fs.mkdirSync(name, 0777); + } +} + +ensureDir("dist"); +ensureDir("dist/test"); +buildFirefox(); +buildBrowser(); +buildBrowserMin(); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/README.md b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/README.md new file mode 100644 index 0000000..c20437b --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/README.md @@ -0,0 +1,434 @@ +# Source Map + +This is a library to generate and consume the source map format +[described here][format]. + +This library is written in the Asynchronous Module Definition format, and works +in the following environments: + +* Modern Browsers supporting ECMAScript 5 (either after the build, or with an + AMD loader such as RequireJS) + +* Inside Firefox (as a JSM file, after the build) + +* With NodeJS versions 0.8.X and higher + +## Node + + $ npm install source-map + +## Building from Source (for everywhere else) + +Install Node and then run + + $ git clone https://fitzgen@github.com/mozilla/source-map.git + $ cd source-map + $ npm link . + +Next, run + + $ node Makefile.dryice.js + +This should spew a bunch of stuff to stdout, and create the following files: + +* `dist/source-map.js` - The unminified browser version. + +* `dist/source-map.min.js` - The minified browser version. + +* `dist/SourceMap.jsm` - The JavaScript Module for inclusion in Firefox source. + +## Examples + +### Consuming a source map + + var rawSourceMap = { + version: 3, + file: 'min.js', + names: ['bar', 'baz', 'n'], + sources: ['one.js', 'two.js'], + sourceRoot: 'http://example.com/www/js/', + mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA' + }; + + var smc = new SourceMapConsumer(rawSourceMap); + + console.log(smc.sources); + // [ 'http://example.com/www/js/one.js', + // 'http://example.com/www/js/two.js' ] + + console.log(smc.originalPositionFor({ + line: 2, + column: 28 + })); + // { source: 'http://example.com/www/js/two.js', + // line: 2, + // column: 10, + // name: 'n' } + + console.log(smc.generatedPositionFor({ + source: 'http://example.com/www/js/two.js', + line: 2, + column: 10 + })); + // { line: 2, column: 28 } + + smc.eachMapping(function (m) { + // ... + }); + +### Generating a source map + +In depth guide: +[**Compiling to JavaScript, and Debugging with Source Maps**](https://hacks.mozilla.org/2013/05/compiling-to-javascript-and-debugging-with-source-maps/) + +#### With SourceNode (high level API) + + function compile(ast) { + switch (ast.type) { + case 'BinaryExpression': + return new SourceNode( + ast.location.line, + ast.location.column, + ast.location.source, + [compile(ast.left), " + ", compile(ast.right)] + ); + case 'Literal': + return new SourceNode( + ast.location.line, + ast.location.column, + ast.location.source, + String(ast.value) + ); + // ... + default: + throw new Error("Bad AST"); + } + } + + var ast = parse("40 + 2", "add.js"); + console.log(compile(ast).toStringWithSourceMap({ + file: 'add.js' + })); + // { code: '40 + 2', + // map: [object SourceMapGenerator] } + +#### With SourceMapGenerator (low level API) + + var map = new SourceMapGenerator({ + file: "source-mapped.js" + }); + + map.addMapping({ + generated: { + line: 10, + column: 35 + }, + source: "foo.js", + original: { + line: 33, + column: 2 + }, + name: "christopher" + }); + + console.log(map.toString()); + // '{"version":3,"file":"source-mapped.js","sources":["foo.js"],"names":["christopher"],"mappings":";;;;;;;;;mCAgCEA"}' + +## API + +Get a reference to the module: + + // NodeJS + var sourceMap = require('source-map'); + + // Browser builds + var sourceMap = window.sourceMap; + + // Inside Firefox + let sourceMap = {}; + Components.utils.import('resource:///modules/devtools/SourceMap.jsm', sourceMap); + +### SourceMapConsumer + +A SourceMapConsumer instance represents a parsed source map which we can query +for information about the original file positions by giving it a file position +in the generated source. + +#### new SourceMapConsumer(rawSourceMap) + +The only parameter is the raw source map (either as a string which can be +`JSON.parse`'d, or an object). According to the spec, source maps have the +following attributes: + +* `version`: Which version of the source map spec this map is following. + +* `sources`: An array of URLs to the original source files. + +* `names`: An array of identifiers which can be referrenced by individual + mappings. + +* `sourceRoot`: Optional. The URL root from which all sources are relative. + +* `sourcesContent`: Optional. An array of contents of the original source files. + +* `mappings`: A string of base64 VLQs which contain the actual mappings. + +* `file`: The generated filename this source map is associated with. + +#### SourceMapConsumer.prototype.originalPositionFor(generatedPosition) + +Returns the original source, line, and column information for the generated +source's line and column positions provided. The only argument is an object with +the following properties: + +* `line`: The line number in the generated source. + +* `column`: The column number in the generated source. + +and an object is returned with the following properties: + +* `source`: The original source file, or null if this information is not + available. + +* `line`: The line number in the original source, or null if this information is + not available. + +* `column`: The column number in the original source, or null or null if this + information is not available. + +* `name`: The original identifier, or null if this information is not available. + +#### SourceMapConsumer.prototype.generatedPositionFor(originalPosition) + +Returns the generated line and column information for the original source, +line, and column positions provided. The only argument is an object with +the following properties: + +* `source`: The filename of the original source. + +* `line`: The line number in the original source. + +* `column`: The column number in the original source. + +and an object is returned with the following properties: + +* `line`: The line number in the generated source, or null. + +* `column`: The column number in the generated source, or null. + +#### SourceMapConsumer.prototype.sourceContentFor(source) + +Returns the original source content for the source provided. The only +argument is the URL of the original source file. + +#### SourceMapConsumer.prototype.eachMapping(callback, context, order) + +Iterate over each mapping between an original source/line/column and a +generated line/column in this source map. + +* `callback`: The function that is called with each mapping. Mappings have the + form `{ source, generatedLine, generatedColumn, originalLine, originalColumn, + name }` + +* `context`: Optional. If specified, this object will be the value of `this` + every time that `callback` is called. + +* `order`: Either `SourceMapConsumer.GENERATED_ORDER` or + `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to iterate over + the mappings sorted by the generated file's line/column order or the + original's source/line/column order, respectively. Defaults to + `SourceMapConsumer.GENERATED_ORDER`. + +### SourceMapGenerator + +An instance of the SourceMapGenerator represents a source map which is being +built incrementally. + +#### new SourceMapGenerator(startOfSourceMap) + +To create a new one, you must pass an object with the following properties: + +* `file`: The filename of the generated source that this source map is + associated with. + +* `sourceRoot`: An optional root for all relative URLs in this source map. + +#### SourceMapGenerator.fromSourceMap(sourceMapConsumer) + +Creates a new SourceMapGenerator based on a SourceMapConsumer + +* `sourceMapConsumer` The SourceMap. + +#### SourceMapGenerator.prototype.addMapping(mapping) + +Add a single mapping from original source line and column to the generated +source's line and column for this source map being created. The mapping object +should have the following properties: + +* `generated`: An object with the generated line and column positions. + +* `original`: An object with the original line and column positions. + +* `source`: The original source file (relative to the sourceRoot). + +* `name`: An optional original token name for this mapping. + +#### SourceMapGenerator.prototype.setSourceContent(sourceFile, sourceContent) + +Set the source content for an original source file. + +* `sourceFile` the URL of the original source file. + +* `sourceContent` the content of the source file. + +#### SourceMapGenerator.prototype.applySourceMap(sourceMapConsumer[, sourceFile]) + +Applies a SourceMap for a source file to the SourceMap. +Each mapping to the supplied source file is rewritten using the +supplied SourceMap. Note: The resolution for the resulting mappings +is the minimium of this map and the supplied map. + +* `sourceMapConsumer`: The SourceMap to be applied. + +* `sourceFile`: Optional. The filename of the source file. + If omitted, sourceMapConsumer.file will be used. + +#### SourceMapGenerator.prototype.toString() + +Renders the source map being generated to a string. + +### SourceNode + +SourceNodes provide a way to abstract over interpolating and/or concatenating +snippets of generated JavaScript source code, while maintaining the line and +column information associated between those snippets and the original source +code. This is useful as the final intermediate representation a compiler might +use before outputting the generated JS and source map. + +#### new SourceNode(line, column, source[, chunk[, name]]) + +* `line`: The original line number associated with this source node, or null if + it isn't associated with an original line. + +* `column`: The original column number associated with this source node, or null + if it isn't associated with an original column. + +* `source`: The original source's filename. + +* `chunk`: Optional. Is immediately passed to `SourceNode.prototype.add`, see + below. + +* `name`: Optional. The original identifier. + +#### SourceNode.fromStringWithSourceMap(code, sourceMapConsumer) + +Creates a SourceNode from generated code and a SourceMapConsumer. + +* `code`: The generated code + +* `sourceMapConsumer` The SourceMap for the generated code + +#### SourceNode.prototype.add(chunk) + +Add a chunk of generated JS to this source node. + +* `chunk`: A string snippet of generated JS code, another instance of + `SourceNode`, or an array where each member is one of those things. + +#### SourceNode.prototype.prepend(chunk) + +Prepend a chunk of generated JS to this source node. + +* `chunk`: A string snippet of generated JS code, another instance of + `SourceNode`, or an array where each member is one of those things. + +#### SourceNode.prototype.setSourceContent(sourceFile, sourceContent) + +Set the source content for a source file. This will be added to the +`SourceMap` in the `sourcesContent` field. + +* `sourceFile`: The filename of the source file + +* `sourceContent`: The content of the source file + +#### SourceNode.prototype.walk(fn) + +Walk over the tree of JS snippets in this node and its children. The walking +function is called once for each snippet of JS and is passed that snippet and +the its original associated source's line/column location. + +* `fn`: The traversal function. + +#### SourceNode.prototype.walkSourceContents(fn) + +Walk over the tree of SourceNodes. The walking function is called for each +source file content and is passed the filename and source content. + +* `fn`: The traversal function. + +#### SourceNode.prototype.join(sep) + +Like `Array.prototype.join` except for SourceNodes. Inserts the separator +between each of this source node's children. + +* `sep`: The separator. + +#### SourceNode.prototype.replaceRight(pattern, replacement) + +Call `String.prototype.replace` on the very right-most source snippet. Useful +for trimming whitespace from the end of a source node, etc. + +* `pattern`: The pattern to replace. + +* `replacement`: The thing to replace the pattern with. + +#### SourceNode.prototype.toString() + +Return the string representation of this source node. Walks over the tree and +concatenates all the various snippets together to one string. + +### SourceNode.prototype.toStringWithSourceMap(startOfSourceMap) + +Returns the string representation of this tree of source nodes, plus a +SourceMapGenerator which contains all the mappings between the generated and +original sources. + +The arguments are the same as those to `new SourceMapGenerator`. + +## Tests + +[![Build Status](https://travis-ci.org/mozilla/source-map.png?branch=master)](https://travis-ci.org/mozilla/source-map) + +Install NodeJS version 0.8.0 or greater, then run `node test/run-tests.js`. + +To add new tests, create a new file named `test/test-.js` +and export your test functions with names that start with "test", for example + + exports["test doing the foo bar"] = function (assert, util) { + ... + }; + +The new test will be located automatically when you run the suite. + +The `util` argument is the test utility module located at `test/source-map/util`. + +The `assert` argument is a cut down version of node's assert module. You have +access to the following assertion functions: + +* `doesNotThrow` + +* `equal` + +* `ok` + +* `strictEqual` + +* `throws` + +(The reason for the restricted set of test functions is because we need the +tests to run inside Firefox's test suite as well and so the assert module is +shimmed in that environment. See `build/assert-shim.js`.) + +[format]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit +[feature]: https://wiki.mozilla.org/DevTools/Features/SourceMap +[Dryice]: https://github.com/mozilla/dryice diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/assert-shim.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/assert-shim.js new file mode 100644 index 0000000..daa1a62 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/assert-shim.js @@ -0,0 +1,56 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('test/source-map/assert', ['exports'], function (exports) { + + let do_throw = function (msg) { + throw new Error(msg); + }; + + exports.init = function (throw_fn) { + do_throw = throw_fn; + }; + + exports.doesNotThrow = function (fn) { + try { + fn(); + } + catch (e) { + do_throw(e.message); + } + }; + + exports.equal = function (actual, expected, msg) { + msg = msg || String(actual) + ' != ' + String(expected); + if (actual != expected) { + do_throw(msg); + } + }; + + exports.ok = function (val, msg) { + msg = msg || String(val) + ' is falsey'; + if (!Boolean(val)) { + do_throw(msg); + } + }; + + exports.strictEqual = function (actual, expected, msg) { + msg = msg || String(actual) + ' !== ' + String(expected); + if (actual !== expected) { + do_throw(msg); + } + }; + + exports.throws = function (fn) { + try { + fn(); + do_throw('Expected an error to be thrown, but it wasn\'t.'); + } + catch (e) { + } + }; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/mini-require.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/mini-require.js new file mode 100644 index 0000000..0daf453 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/mini-require.js @@ -0,0 +1,152 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +/** + * Define a module along with a payload. + * @param {string} moduleName Name for the payload + * @param {ignored} deps Ignored. For compatibility with CommonJS AMD Spec + * @param {function} payload Function with (require, exports, module) params + */ +function define(moduleName, deps, payload) { + if (typeof moduleName != "string") { + throw new TypeError('Expected string, got: ' + moduleName); + } + + if (arguments.length == 2) { + payload = deps; + } + + if (moduleName in define.modules) { + throw new Error("Module already defined: " + moduleName); + } + define.modules[moduleName] = payload; +}; + +/** + * The global store of un-instantiated modules + */ +define.modules = {}; + + +/** + * We invoke require() in the context of a Domain so we can have multiple + * sets of modules running separate from each other. + * This contrasts with JSMs which are singletons, Domains allows us to + * optionally load a CommonJS module twice with separate data each time. + * Perhaps you want 2 command lines with a different set of commands in each, + * for example. + */ +function Domain() { + this.modules = {}; + this._currentModule = null; +} + +(function () { + + /** + * Lookup module names and resolve them by calling the definition function if + * needed. + * There are 2 ways to call this, either with an array of dependencies and a + * callback to call when the dependencies are found (which can happen + * asynchronously in an in-page context) or with a single string an no callback + * where the dependency is resolved synchronously and returned. + * The API is designed to be compatible with the CommonJS AMD spec and + * RequireJS. + * @param {string[]|string} deps A name, or names for the payload + * @param {function|undefined} callback Function to call when the dependencies + * are resolved + * @return {undefined|object} The module required or undefined for + * array/callback method + */ + Domain.prototype.require = function(deps, callback) { + if (Array.isArray(deps)) { + var params = deps.map(function(dep) { + return this.lookup(dep); + }, this); + if (callback) { + callback.apply(null, params); + } + return undefined; + } + else { + return this.lookup(deps); + } + }; + + function normalize(path) { + var bits = path.split('/'); + var i = 1; + while (i < bits.length) { + if (bits[i] === '..') { + bits.splice(i-1, 1); + } else if (bits[i] === '.') { + bits.splice(i, 1); + } else { + i++; + } + } + return bits.join('/'); + } + + function join(a, b) { + a = a.trim(); + b = b.trim(); + if (/^\//.test(b)) { + return b; + } else { + return a.replace(/\/*$/, '/') + b; + } + } + + function dirname(path) { + var bits = path.split('/'); + bits.pop(); + return bits.join('/'); + } + + /** + * Lookup module names and resolve them by calling the definition function if + * needed. + * @param {string} moduleName A name for the payload to lookup + * @return {object} The module specified by aModuleName or null if not found. + */ + Domain.prototype.lookup = function(moduleName) { + if (/^\./.test(moduleName)) { + moduleName = normalize(join(dirname(this._currentModule), moduleName)); + } + + if (moduleName in this.modules) { + var module = this.modules[moduleName]; + return module; + } + + if (!(moduleName in define.modules)) { + throw new Error("Module not defined: " + moduleName); + } + + var module = define.modules[moduleName]; + + if (typeof module == "function") { + var exports = {}; + var previousModule = this._currentModule; + this._currentModule = moduleName; + module(this.require.bind(this), exports, { id: moduleName, uri: "" }); + this._currentModule = previousModule; + module = exports; + } + + // cache the resulting module object for next time + this.modules[moduleName] = module; + + return module; + }; + +}()); + +define.Domain = Domain; +define.globalDomain = new Domain(); +var require = define.globalDomain.require.bind(define.globalDomain); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/prefix-source-map.jsm b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/prefix-source-map.jsm new file mode 100644 index 0000000..ee2539d --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/prefix-source-map.jsm @@ -0,0 +1,20 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +/* + * WARNING! + * + * Do not edit this file directly, it is built from the sources at + * https://github.com/mozilla/source-map/ + */ + +/////////////////////////////////////////////////////////////////////////////// + + +this.EXPORTED_SYMBOLS = [ "SourceMapConsumer", "SourceMapGenerator", "SourceNode" ]; + +Components.utils.import('resource://gre/modules/devtools/Require.jsm'); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/prefix-utils.jsm b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/prefix-utils.jsm new file mode 100644 index 0000000..80341d4 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/prefix-utils.jsm @@ -0,0 +1,18 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +/* + * WARNING! + * + * Do not edit this file directly, it is built from the sources at + * https://github.com/mozilla/source-map/ + */ + +Components.utils.import('resource://gre/modules/devtools/Require.jsm'); +Components.utils.import('resource://gre/modules/devtools/SourceMap.jsm'); + +this.EXPORTED_SYMBOLS = [ "define", "runSourceMapTests" ]; diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/suffix-browser.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/suffix-browser.js new file mode 100644 index 0000000..fb29ff5 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/suffix-browser.js @@ -0,0 +1,8 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/////////////////////////////////////////////////////////////////////////////// + +this.sourceMap = { + SourceMapConsumer: require('source-map/source-map-consumer').SourceMapConsumer, + SourceMapGenerator: require('source-map/source-map-generator').SourceMapGenerator, + SourceNode: require('source-map/source-node').SourceNode +}; diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/suffix-source-map.jsm b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/suffix-source-map.jsm new file mode 100644 index 0000000..cf3c2d8 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/suffix-source-map.jsm @@ -0,0 +1,6 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/////////////////////////////////////////////////////////////////////////////// + +this.SourceMapConsumer = require('source-map/source-map-consumer').SourceMapConsumer; +this.SourceMapGenerator = require('source-map/source-map-generator').SourceMapGenerator; +this.SourceNode = require('source-map/source-node').SourceNode; diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/suffix-utils.jsm b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/suffix-utils.jsm new file mode 100644 index 0000000..b31b84c --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/suffix-utils.jsm @@ -0,0 +1,21 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +function runSourceMapTests(modName, do_throw) { + let mod = require(modName); + let assert = require('test/source-map/assert'); + let util = require('test/source-map/util'); + + assert.init(do_throw); + + for (let k in mod) { + if (/^test/.test(k)) { + mod[k](assert, util); + } + } + +} +this.runSourceMapTests = runSourceMapTests; diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/test-prefix.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/test-prefix.js new file mode 100644 index 0000000..1b13f30 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/test-prefix.js @@ -0,0 +1,8 @@ +/* + * WARNING! + * + * Do not edit this file directly, it is built from the sources at + * https://github.com/mozilla/source-map/ + */ + +Components.utils.import('resource://test/Utils.jsm'); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/test-suffix.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/test-suffix.js new file mode 100644 index 0000000..bec2de3 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/build/test-suffix.js @@ -0,0 +1,3 @@ +function run_test() { + runSourceMapTests('{THIS_MODULE}', do_throw); +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map.js new file mode 100644 index 0000000..121ad24 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map.js @@ -0,0 +1,8 @@ +/* + * Copyright 2009-2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE.txt or: + * http://opensource.org/licenses/BSD-3-Clause + */ +exports.SourceMapGenerator = require('./source-map/source-map-generator').SourceMapGenerator; +exports.SourceMapConsumer = require('./source-map/source-map-consumer').SourceMapConsumer; +exports.SourceNode = require('./source-map/source-node').SourceNode; diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/array-set.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/array-set.js new file mode 100644 index 0000000..40f9a18 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/array-set.js @@ -0,0 +1,97 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var util = require('./util'); + + /** + * A data structure which is a combination of an array and a set. Adding a new + * member is O(1), testing for membership is O(1), and finding the index of an + * element is O(1). Removing elements from the set is not supported. Only + * strings are supported for membership. + */ + function ArraySet() { + this._array = []; + this._set = {}; + } + + /** + * Static method for creating ArraySet instances from an existing array. + */ + ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { + var set = new ArraySet(); + for (var i = 0, len = aArray.length; i < len; i++) { + set.add(aArray[i], aAllowDuplicates); + } + return set; + }; + + /** + * Add the given string to this set. + * + * @param String aStr + */ + ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { + var isDuplicate = this.has(aStr); + var idx = this._array.length; + if (!isDuplicate || aAllowDuplicates) { + this._array.push(aStr); + } + if (!isDuplicate) { + this._set[util.toSetString(aStr)] = idx; + } + }; + + /** + * Is the given string a member of this set? + * + * @param String aStr + */ + ArraySet.prototype.has = function ArraySet_has(aStr) { + return Object.prototype.hasOwnProperty.call(this._set, + util.toSetString(aStr)); + }; + + /** + * What is the index of the given string in the array? + * + * @param String aStr + */ + ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { + if (this.has(aStr)) { + return this._set[util.toSetString(aStr)]; + } + throw new Error('"' + aStr + '" is not in the set.'); + }; + + /** + * What is the element at the given index? + * + * @param Number aIdx + */ + ArraySet.prototype.at = function ArraySet_at(aIdx) { + if (aIdx >= 0 && aIdx < this._array.length) { + return this._array[aIdx]; + } + throw new Error('No element indexed by ' + aIdx); + }; + + /** + * Returns the array representation of this set (which has the proper indices + * indicated by indexOf). Note that this is a copy of the internal array used + * for storing the members so that no one can mess with internal state. + */ + ArraySet.prototype.toArray = function ArraySet_toArray() { + return this._array.slice(); + }; + + exports.ArraySet = ArraySet; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/base64-vlq.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/base64-vlq.js new file mode 100644 index 0000000..1b67bb3 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/base64-vlq.js @@ -0,0 +1,144 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + * + * Based on the Base 64 VLQ implementation in Closure Compiler: + * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java + * + * Copyright 2011 The Closure Compiler Authors. 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 Google Inc. 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 + * OWNER 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. + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var base64 = require('./base64'); + + // A single base 64 digit can contain 6 bits of data. For the base 64 variable + // length quantities we use in the source map spec, the first bit is the sign, + // the next four bits are the actual value, and the 6th bit is the + // continuation bit. The continuation bit tells us whether there are more + // digits in this value following this digit. + // + // Continuation + // | Sign + // | | + // V V + // 101011 + + var VLQ_BASE_SHIFT = 5; + + // binary: 100000 + var VLQ_BASE = 1 << VLQ_BASE_SHIFT; + + // binary: 011111 + var VLQ_BASE_MASK = VLQ_BASE - 1; + + // binary: 100000 + var VLQ_CONTINUATION_BIT = VLQ_BASE; + + /** + * Converts from a two-complement value to a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) + * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) + */ + function toVLQSigned(aValue) { + return aValue < 0 + ? ((-aValue) << 1) + 1 + : (aValue << 1) + 0; + } + + /** + * Converts to a two-complement value from a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 + * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 + */ + function fromVLQSigned(aValue) { + var isNegative = (aValue & 1) === 1; + var shifted = aValue >> 1; + return isNegative + ? -shifted + : shifted; + } + + /** + * Returns the base 64 VLQ encoded value. + */ + exports.encode = function base64VLQ_encode(aValue) { + var encoded = ""; + var digit; + + var vlq = toVLQSigned(aValue); + + do { + digit = vlq & VLQ_BASE_MASK; + vlq >>>= VLQ_BASE_SHIFT; + if (vlq > 0) { + // There are still more digits in this value, so we must make sure the + // continuation bit is marked. + digit |= VLQ_CONTINUATION_BIT; + } + encoded += base64.encode(digit); + } while (vlq > 0); + + return encoded; + }; + + /** + * Decodes the next base 64 VLQ value from the given string and returns the + * value and the rest of the string. + */ + exports.decode = function base64VLQ_decode(aStr) { + var i = 0; + var strLen = aStr.length; + var result = 0; + var shift = 0; + var continuation, digit; + + do { + if (i >= strLen) { + throw new Error("Expected more digits in base 64 VLQ value."); + } + digit = base64.decode(aStr.charAt(i++)); + continuation = !!(digit & VLQ_CONTINUATION_BIT); + digit &= VLQ_BASE_MASK; + result = result + (digit << shift); + shift += VLQ_BASE_SHIFT; + } while (continuation); + + return { + value: fromVLQSigned(result), + rest: aStr.slice(i) + }; + }; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/base64.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/base64.js new file mode 100644 index 0000000..863cc46 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/base64.js @@ -0,0 +1,42 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var charToIntMap = {}; + var intToCharMap = {}; + + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + .split('') + .forEach(function (ch, index) { + charToIntMap[ch] = index; + intToCharMap[index] = ch; + }); + + /** + * Encode an integer in the range of 0 to 63 to a single base 64 digit. + */ + exports.encode = function base64_encode(aNumber) { + if (aNumber in intToCharMap) { + return intToCharMap[aNumber]; + } + throw new TypeError("Must be between 0 and 63: " + aNumber); + }; + + /** + * Decode a single base 64 digit to an integer. + */ + exports.decode = function base64_decode(aChar) { + if (aChar in charToIntMap) { + return charToIntMap[aChar]; + } + throw new TypeError("Not a valid base 64 digit: " + aChar); + }; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/binary-search.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/binary-search.js new file mode 100644 index 0000000..ff347c6 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/binary-search.js @@ -0,0 +1,81 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + /** + * Recursive implementation of binary search. + * + * @param aLow Indices here and lower do not contain the needle. + * @param aHigh Indices here and higher do not contain the needle. + * @param aNeedle The element being searched for. + * @param aHaystack The non-empty array being searched. + * @param aCompare Function which takes two elements and returns -1, 0, or 1. + */ + function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) { + // This function terminates when one of the following is true: + // + // 1. We find the exact element we are looking for. + // + // 2. We did not find the exact element, but we can return the next + // closest element that is less than that element. + // + // 3. We did not find the exact element, and there is no next-closest + // element which is less than the one we are searching for, so we + // return null. + var mid = Math.floor((aHigh - aLow) / 2) + aLow; + var cmp = aCompare(aNeedle, aHaystack[mid], true); + if (cmp === 0) { + // Found the element we are looking for. + return aHaystack[mid]; + } + else if (cmp > 0) { + // aHaystack[mid] is greater than our needle. + if (aHigh - mid > 1) { + // The element is in the upper half. + return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare); + } + // We did not find an exact match, return the next closest one + // (termination case 2). + return aHaystack[mid]; + } + else { + // aHaystack[mid] is less than our needle. + if (mid - aLow > 1) { + // The element is in the lower half. + return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare); + } + // The exact needle element was not found in this haystack. Determine if + // we are in termination case (2) or (3) and return the appropriate thing. + return aLow < 0 + ? null + : aHaystack[aLow]; + } + } + + /** + * This is an implementation of binary search which will always try and return + * the next lowest value checked if there is no exact hit. This is because + * mappings between original and generated line/col pairs are single points, + * and there is an implicit region between each of them, so a miss just means + * that you aren't on the very start of a region. + * + * @param aNeedle The element you are looking for. + * @param aHaystack The array that is being searched. + * @param aCompare A function which takes the needle and an element in the + * array and returns -1, 0, or 1 depending on whether the needle is less + * than, equal to, or greater than the element, respectively. + */ + exports.search = function search(aNeedle, aHaystack, aCompare) { + return aHaystack.length > 0 + ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) + : null; + }; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-map-consumer.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-map-consumer.js new file mode 100644 index 0000000..a3b9dc0 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-map-consumer.js @@ -0,0 +1,477 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var util = require('./util'); + var binarySearch = require('./binary-search'); + var ArraySet = require('./array-set').ArraySet; + var base64VLQ = require('./base64-vlq'); + + /** + * A SourceMapConsumer instance represents a parsed source map which we can + * query for information about the original file positions by giving it a file + * position in the generated source. + * + * The only parameter is the raw source map (either as a JSON string, or + * already parsed to an object). According to the spec, source maps have the + * following attributes: + * + * - version: Which version of the source map spec this map is following. + * - sources: An array of URLs to the original source files. + * - names: An array of identifiers which can be referrenced by individual mappings. + * - sourceRoot: Optional. The URL root from which all sources are relative. + * - sourcesContent: Optional. An array of contents of the original source files. + * - mappings: A string of base64 VLQs which contain the actual mappings. + * - file: The generated file this source map is associated with. + * + * Here is an example source map, taken from the source map spec[0]: + * + * { + * version : 3, + * file: "out.js", + * sourceRoot : "", + * sources: ["foo.js", "bar.js"], + * names: ["src", "maps", "are", "fun"], + * mappings: "AA,AB;;ABCDE;" + * } + * + * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# + */ + function SourceMapConsumer(aSourceMap) { + var sourceMap = aSourceMap; + if (typeof aSourceMap === 'string') { + sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); + } + + var version = util.getArg(sourceMap, 'version'); + var sources = util.getArg(sourceMap, 'sources'); + // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which + // requires the array) to play nice here. + var names = util.getArg(sourceMap, 'names', []); + var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); + var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); + var mappings = util.getArg(sourceMap, 'mappings'); + var file = util.getArg(sourceMap, 'file', null); + + // Once again, Sass deviates from the spec and supplies the version as a + // string rather than a number, so we use loose equality checking here. + if (version != this._version) { + throw new Error('Unsupported version: ' + version); + } + + // Pass `true` below to allow duplicate names and sources. While source maps + // are intended to be compressed and deduplicated, the TypeScript compiler + // sometimes generates source maps with duplicates in them. See Github issue + // #72 and bugzil.la/889492. + this._names = ArraySet.fromArray(names, true); + this._sources = ArraySet.fromArray(sources, true); + + this.sourceRoot = sourceRoot; + this.sourcesContent = sourcesContent; + this._mappings = mappings; + this.file = file; + } + + /** + * Create a SourceMapConsumer from a SourceMapGenerator. + * + * @param SourceMapGenerator aSourceMap + * The source map that will be consumed. + * @returns SourceMapConsumer + */ + SourceMapConsumer.fromSourceMap = + function SourceMapConsumer_fromSourceMap(aSourceMap) { + var smc = Object.create(SourceMapConsumer.prototype); + + smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true); + smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true); + smc.sourceRoot = aSourceMap._sourceRoot; + smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(), + smc.sourceRoot); + smc.file = aSourceMap._file; + + smc.__generatedMappings = aSourceMap._mappings.slice() + .sort(util.compareByGeneratedPositions); + smc.__originalMappings = aSourceMap._mappings.slice() + .sort(util.compareByOriginalPositions); + + return smc; + }; + + /** + * The version of the source mapping spec that we are consuming. + */ + SourceMapConsumer.prototype._version = 3; + + /** + * The list of original sources. + */ + Object.defineProperty(SourceMapConsumer.prototype, 'sources', { + get: function () { + return this._sources.toArray().map(function (s) { + return this.sourceRoot ? util.join(this.sourceRoot, s) : s; + }, this); + } + }); + + // `__generatedMappings` and `__originalMappings` are arrays that hold the + // parsed mapping coordinates from the source map's "mappings" attribute. They + // are lazily instantiated, accessed via the `_generatedMappings` and + // `_originalMappings` getters respectively, and we only parse the mappings + // and create these arrays once queried for a source location. We jump through + // these hoops because there can be many thousands of mappings, and parsing + // them is expensive, so we only want to do it if we must. + // + // Each object in the arrays is of the form: + // + // { + // generatedLine: The line number in the generated code, + // generatedColumn: The column number in the generated code, + // source: The path to the original source file that generated this + // chunk of code, + // originalLine: The line number in the original source that + // corresponds to this chunk of generated code, + // originalColumn: The column number in the original source that + // corresponds to this chunk of generated code, + // name: The name of the original symbol which generated this chunk of + // code. + // } + // + // All properties except for `generatedLine` and `generatedColumn` can be + // `null`. + // + // `_generatedMappings` is ordered by the generated positions. + // + // `_originalMappings` is ordered by the original positions. + + SourceMapConsumer.prototype.__generatedMappings = null; + Object.defineProperty(SourceMapConsumer.prototype, '_generatedMappings', { + get: function () { + if (!this.__generatedMappings) { + this.__generatedMappings = []; + this.__originalMappings = []; + this._parseMappings(this._mappings, this.sourceRoot); + } + + return this.__generatedMappings; + } + }); + + SourceMapConsumer.prototype.__originalMappings = null; + Object.defineProperty(SourceMapConsumer.prototype, '_originalMappings', { + get: function () { + if (!this.__originalMappings) { + this.__generatedMappings = []; + this.__originalMappings = []; + this._parseMappings(this._mappings, this.sourceRoot); + } + + return this.__originalMappings; + } + }); + + /** + * Parse the mappings in a string in to a data structure which we can easily + * query (the ordered arrays in the `this.__generatedMappings` and + * `this.__originalMappings` properties). + */ + SourceMapConsumer.prototype._parseMappings = + function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { + var generatedLine = 1; + var previousGeneratedColumn = 0; + var previousOriginalLine = 0; + var previousOriginalColumn = 0; + var previousSource = 0; + var previousName = 0; + var mappingSeparator = /^[,;]/; + var str = aStr; + var mapping; + var temp; + + while (str.length > 0) { + if (str.charAt(0) === ';') { + generatedLine++; + str = str.slice(1); + previousGeneratedColumn = 0; + } + else if (str.charAt(0) === ',') { + str = str.slice(1); + } + else { + mapping = {}; + mapping.generatedLine = generatedLine; + + // Generated column. + temp = base64VLQ.decode(str); + mapping.generatedColumn = previousGeneratedColumn + temp.value; + previousGeneratedColumn = mapping.generatedColumn; + str = temp.rest; + + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + // Original source. + temp = base64VLQ.decode(str); + mapping.source = this._sources.at(previousSource + temp.value); + previousSource += temp.value; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source, but no line and column'); + } + + // Original line. + temp = base64VLQ.decode(str); + mapping.originalLine = previousOriginalLine + temp.value; + previousOriginalLine = mapping.originalLine; + // Lines are stored 0-based + mapping.originalLine += 1; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source and line, but no column'); + } + + // Original column. + temp = base64VLQ.decode(str); + mapping.originalColumn = previousOriginalColumn + temp.value; + previousOriginalColumn = mapping.originalColumn; + str = temp.rest; + + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + // Original name. + temp = base64VLQ.decode(str); + mapping.name = this._names.at(previousName + temp.value); + previousName += temp.value; + str = temp.rest; + } + } + + this.__generatedMappings.push(mapping); + if (typeof mapping.originalLine === 'number') { + this.__originalMappings.push(mapping); + } + } + } + + this.__originalMappings.sort(util.compareByOriginalPositions); + }; + + /** + * Find the mapping that best matches the hypothetical "needle" mapping that + * we are searching for in the given "haystack" of mappings. + */ + SourceMapConsumer.prototype._findMapping = + function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, + aColumnName, aComparator) { + // To return the position we are searching for, we must first find the + // mapping for the given position and then return the opposite position it + // points to. Because the mappings are sorted, we can use binary search to + // find the best mapping. + + if (aNeedle[aLineName] <= 0) { + throw new TypeError('Line must be greater than or equal to 1, got ' + + aNeedle[aLineName]); + } + if (aNeedle[aColumnName] < 0) { + throw new TypeError('Column must be greater than or equal to 0, got ' + + aNeedle[aColumnName]); + } + + return binarySearch.search(aNeedle, aMappings, aComparator); + }; + + /** + * Returns the original source, line, and column information for the generated + * source's line and column positions provided. The only argument is an object + * with the following properties: + * + * - line: The line number in the generated source. + * - column: The column number in the generated source. + * + * and an object is returned with the following properties: + * + * - source: The original source file, or null. + * - line: The line number in the original source, or null. + * - column: The column number in the original source, or null. + * - name: The original identifier, or null. + */ + SourceMapConsumer.prototype.originalPositionFor = + function SourceMapConsumer_originalPositionFor(aArgs) { + var needle = { + generatedLine: util.getArg(aArgs, 'line'), + generatedColumn: util.getArg(aArgs, 'column') + }; + + var mapping = this._findMapping(needle, + this._generatedMappings, + "generatedLine", + "generatedColumn", + util.compareByGeneratedPositions); + + if (mapping) { + var source = util.getArg(mapping, 'source', null); + if (source && this.sourceRoot) { + source = util.join(this.sourceRoot, source); + } + return { + source: source, + line: util.getArg(mapping, 'originalLine', null), + column: util.getArg(mapping, 'originalColumn', null), + name: util.getArg(mapping, 'name', null) + }; + } + + return { + source: null, + line: null, + column: null, + name: null + }; + }; + + /** + * Returns the original source content. The only argument is the url of the + * original source file. Returns null if no original source content is + * availible. + */ + SourceMapConsumer.prototype.sourceContentFor = + function SourceMapConsumer_sourceContentFor(aSource) { + if (!this.sourcesContent) { + return null; + } + + if (this.sourceRoot) { + aSource = util.relative(this.sourceRoot, aSource); + } + + if (this._sources.has(aSource)) { + return this.sourcesContent[this._sources.indexOf(aSource)]; + } + + var url; + if (this.sourceRoot + && (url = util.urlParse(this.sourceRoot))) { + // XXX: file:// URIs and absolute paths lead to unexpected behavior for + // many users. We can help them out when they expect file:// URIs to + // behave like it would if they were running a local HTTP server. See + // https://bugzilla.mozilla.org/show_bug.cgi?id=885597. + var fileUriAbsPath = aSource.replace(/^file:\/\//, ""); + if (url.scheme == "file" + && this._sources.has(fileUriAbsPath)) { + return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)] + } + + if ((!url.path || url.path == "/") + && this._sources.has("/" + aSource)) { + return this.sourcesContent[this._sources.indexOf("/" + aSource)]; + } + } + + throw new Error('"' + aSource + '" is not in the SourceMap.'); + }; + + /** + * Returns the generated line and column information for the original source, + * line, and column positions provided. The only argument is an object with + * the following properties: + * + * - source: The filename of the original source. + * - line: The line number in the original source. + * - column: The column number in the original source. + * + * and an object is returned with the following properties: + * + * - line: The line number in the generated source, or null. + * - column: The column number in the generated source, or null. + */ + SourceMapConsumer.prototype.generatedPositionFor = + function SourceMapConsumer_generatedPositionFor(aArgs) { + var needle = { + source: util.getArg(aArgs, 'source'), + originalLine: util.getArg(aArgs, 'line'), + originalColumn: util.getArg(aArgs, 'column') + }; + + if (this.sourceRoot) { + needle.source = util.relative(this.sourceRoot, needle.source); + } + + var mapping = this._findMapping(needle, + this._originalMappings, + "originalLine", + "originalColumn", + util.compareByOriginalPositions); + + if (mapping) { + return { + line: util.getArg(mapping, 'generatedLine', null), + column: util.getArg(mapping, 'generatedColumn', null) + }; + } + + return { + line: null, + column: null + }; + }; + + SourceMapConsumer.GENERATED_ORDER = 1; + SourceMapConsumer.ORIGINAL_ORDER = 2; + + /** + * Iterate over each mapping between an original source/line/column and a + * generated line/column in this source map. + * + * @param Function aCallback + * The function that is called with each mapping. + * @param Object aContext + * Optional. If specified, this object will be the value of `this` every + * time that `aCallback` is called. + * @param aOrder + * Either `SourceMapConsumer.GENERATED_ORDER` or + * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to + * iterate over the mappings sorted by the generated file's line/column + * order or the original's source/line/column order, respectively. Defaults to + * `SourceMapConsumer.GENERATED_ORDER`. + */ + SourceMapConsumer.prototype.eachMapping = + function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { + var context = aContext || null; + var order = aOrder || SourceMapConsumer.GENERATED_ORDER; + + var mappings; + switch (order) { + case SourceMapConsumer.GENERATED_ORDER: + mappings = this._generatedMappings; + break; + case SourceMapConsumer.ORIGINAL_ORDER: + mappings = this._originalMappings; + break; + default: + throw new Error("Unknown order of iteration."); + } + + var sourceRoot = this.sourceRoot; + mappings.map(function (mapping) { + var source = mapping.source; + if (source && sourceRoot) { + source = util.join(sourceRoot, source); + } + return { + source: source, + generatedLine: mapping.generatedLine, + generatedColumn: mapping.generatedColumn, + originalLine: mapping.originalLine, + originalColumn: mapping.originalColumn, + name: mapping.name + }; + }).forEach(aCallback, context); + }; + + exports.SourceMapConsumer = SourceMapConsumer; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-map-generator.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-map-generator.js new file mode 100644 index 0000000..48ead7d --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-map-generator.js @@ -0,0 +1,380 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var base64VLQ = require('./base64-vlq'); + var util = require('./util'); + var ArraySet = require('./array-set').ArraySet; + + /** + * An instance of the SourceMapGenerator represents a source map which is + * being built incrementally. To create a new one, you must pass an object + * with the following properties: + * + * - file: The filename of the generated source. + * - sourceRoot: An optional root for all URLs in this source map. + */ + function SourceMapGenerator(aArgs) { + this._file = util.getArg(aArgs, 'file'); + this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); + this._sources = new ArraySet(); + this._names = new ArraySet(); + this._mappings = []; + this._sourcesContents = null; + } + + SourceMapGenerator.prototype._version = 3; + + /** + * Creates a new SourceMapGenerator based on a SourceMapConsumer + * + * @param aSourceMapConsumer The SourceMap. + */ + SourceMapGenerator.fromSourceMap = + function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { + var sourceRoot = aSourceMapConsumer.sourceRoot; + var generator = new SourceMapGenerator({ + file: aSourceMapConsumer.file, + sourceRoot: sourceRoot + }); + aSourceMapConsumer.eachMapping(function (mapping) { + var newMapping = { + generated: { + line: mapping.generatedLine, + column: mapping.generatedColumn + } + }; + + if (mapping.source) { + newMapping.source = mapping.source; + if (sourceRoot) { + newMapping.source = util.relative(sourceRoot, newMapping.source); + } + + newMapping.original = { + line: mapping.originalLine, + column: mapping.originalColumn + }; + + if (mapping.name) { + newMapping.name = mapping.name; + } + } + + generator.addMapping(newMapping); + }); + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + generator.setSourceContent(sourceFile, content); + } + }); + return generator; + }; + + /** + * Add a single mapping from original source line and column to the generated + * source's line and column for this source map being created. The mapping + * object should have the following properties: + * + * - generated: An object with the generated line and column positions. + * - original: An object with the original line and column positions. + * - source: The original source file (relative to the sourceRoot). + * - name: An optional original token name for this mapping. + */ + SourceMapGenerator.prototype.addMapping = + function SourceMapGenerator_addMapping(aArgs) { + var generated = util.getArg(aArgs, 'generated'); + var original = util.getArg(aArgs, 'original', null); + var source = util.getArg(aArgs, 'source', null); + var name = util.getArg(aArgs, 'name', null); + + this._validateMapping(generated, original, source, name); + + if (source && !this._sources.has(source)) { + this._sources.add(source); + } + + if (name && !this._names.has(name)) { + this._names.add(name); + } + + this._mappings.push({ + generatedLine: generated.line, + generatedColumn: generated.column, + originalLine: original != null && original.line, + originalColumn: original != null && original.column, + source: source, + name: name + }); + }; + + /** + * Set the source content for a source file. + */ + SourceMapGenerator.prototype.setSourceContent = + function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { + var source = aSourceFile; + if (this._sourceRoot) { + source = util.relative(this._sourceRoot, source); + } + + if (aSourceContent !== null) { + // Add the source content to the _sourcesContents map. + // Create a new _sourcesContents map if the property is null. + if (!this._sourcesContents) { + this._sourcesContents = {}; + } + this._sourcesContents[util.toSetString(source)] = aSourceContent; + } else { + // Remove the source file from the _sourcesContents map. + // If the _sourcesContents map is empty, set the property to null. + delete this._sourcesContents[util.toSetString(source)]; + if (Object.keys(this._sourcesContents).length === 0) { + this._sourcesContents = null; + } + } + }; + + /** + * Applies the mappings of a sub-source-map for a specific source file to the + * source map being generated. Each mapping to the supplied source file is + * rewritten using the supplied source map. Note: The resolution for the + * resulting mappings is the minimium of this map and the supplied map. + * + * @param aSourceMapConsumer The source map to be applied. + * @param aSourceFile Optional. The filename of the source file. + * If omitted, SourceMapConsumer's file property will be used. + */ + SourceMapGenerator.prototype.applySourceMap = + function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { + // If aSourceFile is omitted, we will use the file property of the SourceMap + if (!aSourceFile) { + aSourceFile = aSourceMapConsumer.file; + } + var sourceRoot = this._sourceRoot; + // Make "aSourceFile" relative if an absolute Url is passed. + if (sourceRoot) { + aSourceFile = util.relative(sourceRoot, aSourceFile); + } + // Applying the SourceMap can add and remove items from the sources and + // the names array. + var newSources = new ArraySet(); + var newNames = new ArraySet(); + + // Find mappings for the "aSourceFile" + this._mappings.forEach(function (mapping) { + if (mapping.source === aSourceFile && mapping.originalLine) { + // Check if it can be mapped by the source map, then update the mapping. + var original = aSourceMapConsumer.originalPositionFor({ + line: mapping.originalLine, + column: mapping.originalColumn + }); + if (original.source !== null) { + // Copy mapping + if (sourceRoot) { + mapping.source = util.relative(sourceRoot, original.source); + } else { + mapping.source = original.source; + } + mapping.originalLine = original.line; + mapping.originalColumn = original.column; + if (original.name !== null && mapping.name !== null) { + // Only use the identifier name if it's an identifier + // in both SourceMaps + mapping.name = original.name; + } + } + } + + var source = mapping.source; + if (source && !newSources.has(source)) { + newSources.add(source); + } + + var name = mapping.name; + if (name && !newNames.has(name)) { + newNames.add(name); + } + + }, this); + this._sources = newSources; + this._names = newNames; + + // Copy sourcesContents of applied map. + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + if (sourceRoot) { + sourceFile = util.relative(sourceRoot, sourceFile); + } + this.setSourceContent(sourceFile, content); + } + }, this); + }; + + /** + * A mapping can have one of the three levels of data: + * + * 1. Just the generated position. + * 2. The Generated position, original position, and original source. + * 3. Generated and original position, original source, as well as a name + * token. + * + * To maintain consistency, we validate that any new mapping being added falls + * in to one of these categories. + */ + SourceMapGenerator.prototype._validateMapping = + function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, + aName) { + if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aGenerated.line > 0 && aGenerated.column >= 0 + && !aOriginal && !aSource && !aName) { + // Case 1. + return; + } + else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aOriginal && 'line' in aOriginal && 'column' in aOriginal + && aGenerated.line > 0 && aGenerated.column >= 0 + && aOriginal.line > 0 && aOriginal.column >= 0 + && aSource) { + // Cases 2 and 3. + return; + } + else { + throw new Error('Invalid mapping: ' + JSON.stringify({ + generated: aGenerated, + source: aSource, + orginal: aOriginal, + name: aName + })); + } + }; + + /** + * Serialize the accumulated mappings in to the stream of base 64 VLQs + * specified by the source map format. + */ + SourceMapGenerator.prototype._serializeMappings = + function SourceMapGenerator_serializeMappings() { + var previousGeneratedColumn = 0; + var previousGeneratedLine = 1; + var previousOriginalColumn = 0; + var previousOriginalLine = 0; + var previousName = 0; + var previousSource = 0; + var result = ''; + var mapping; + + // The mappings must be guaranteed to be in sorted order before we start + // serializing them or else the generated line numbers (which are defined + // via the ';' separators) will be all messed up. Note: it might be more + // performant to maintain the sorting as we insert them, rather than as we + // serialize them, but the big O is the same either way. + this._mappings.sort(util.compareByGeneratedPositions); + + for (var i = 0, len = this._mappings.length; i < len; i++) { + mapping = this._mappings[i]; + + if (mapping.generatedLine !== previousGeneratedLine) { + previousGeneratedColumn = 0; + while (mapping.generatedLine !== previousGeneratedLine) { + result += ';'; + previousGeneratedLine++; + } + } + else { + if (i > 0) { + if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) { + continue; + } + result += ','; + } + } + + result += base64VLQ.encode(mapping.generatedColumn + - previousGeneratedColumn); + previousGeneratedColumn = mapping.generatedColumn; + + if (mapping.source) { + result += base64VLQ.encode(this._sources.indexOf(mapping.source) + - previousSource); + previousSource = this._sources.indexOf(mapping.source); + + // lines are stored 0-based in SourceMap spec version 3 + result += base64VLQ.encode(mapping.originalLine - 1 + - previousOriginalLine); + previousOriginalLine = mapping.originalLine - 1; + + result += base64VLQ.encode(mapping.originalColumn + - previousOriginalColumn); + previousOriginalColumn = mapping.originalColumn; + + if (mapping.name) { + result += base64VLQ.encode(this._names.indexOf(mapping.name) + - previousName); + previousName = this._names.indexOf(mapping.name); + } + } + } + + return result; + }; + + SourceMapGenerator.prototype._generateSourcesContent = + function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) { + return aSources.map(function (source) { + if (!this._sourcesContents) { + return null; + } + if (aSourceRoot) { + source = util.relative(aSourceRoot, source); + } + var key = util.toSetString(source); + return Object.prototype.hasOwnProperty.call(this._sourcesContents, + key) + ? this._sourcesContents[key] + : null; + }, this); + }; + + /** + * Externalize the source map. + */ + SourceMapGenerator.prototype.toJSON = + function SourceMapGenerator_toJSON() { + var map = { + version: this._version, + file: this._file, + sources: this._sources.toArray(), + names: this._names.toArray(), + mappings: this._serializeMappings() + }; + if (this._sourceRoot) { + map.sourceRoot = this._sourceRoot; + } + if (this._sourcesContents) { + map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); + } + + return map; + }; + + /** + * Render the source map being generated to a string. + */ + SourceMapGenerator.prototype.toString = + function SourceMapGenerator_toString() { + return JSON.stringify(this); + }; + + exports.SourceMapGenerator = SourceMapGenerator; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-node.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-node.js new file mode 100644 index 0000000..626cb65 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/source-node.js @@ -0,0 +1,371 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; + var util = require('./util'); + + /** + * SourceNodes provide a way to abstract over interpolating/concatenating + * snippets of generated JavaScript source code while maintaining the line and + * column information associated with the original source code. + * + * @param aLine The original line number. + * @param aColumn The original column number. + * @param aSource The original source's filename. + * @param aChunks Optional. An array of strings which are snippets of + * generated JS, or other SourceNodes. + * @param aName The original identifier. + */ + function SourceNode(aLine, aColumn, aSource, aChunks, aName) { + this.children = []; + this.sourceContents = {}; + this.line = aLine === undefined ? null : aLine; + this.column = aColumn === undefined ? null : aColumn; + this.source = aSource === undefined ? null : aSource; + this.name = aName === undefined ? null : aName; + if (aChunks != null) this.add(aChunks); + } + + /** + * Creates a SourceNode from generated code and a SourceMapConsumer. + * + * @param aGeneratedCode The generated code + * @param aSourceMapConsumer The SourceMap for the generated code + */ + SourceNode.fromStringWithSourceMap = + function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) { + // The SourceNode we want to fill with the generated code + // and the SourceMap + var node = new SourceNode(); + + // The generated code + // Processed fragments are removed from this array. + var remainingLines = aGeneratedCode.split('\n'); + + // We need to remember the position of "remainingLines" + var lastGeneratedLine = 1, lastGeneratedColumn = 0; + + // The generate SourceNodes we need a code range. + // To extract it current and last mapping is used. + // Here we store the last mapping. + var lastMapping = null; + + aSourceMapConsumer.eachMapping(function (mapping) { + if (lastMapping === null) { + // We add the generated code until the first mapping + // to the SourceNode without any mapping. + // Each line is added as separate string. + while (lastGeneratedLine < mapping.generatedLine) { + node.add(remainingLines.shift() + "\n"); + lastGeneratedLine++; + } + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + node.add(nextLine.substr(0, mapping.generatedColumn)); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + } else { + // We add the code from "lastMapping" to "mapping": + // First check if there is a new line in between. + if (lastGeneratedLine < mapping.generatedLine) { + var code = ""; + // Associate full lines with "lastMapping" + do { + code += remainingLines.shift() + "\n"; + lastGeneratedLine++; + lastGeneratedColumn = 0; + } while (lastGeneratedLine < mapping.generatedLine); + // When we reached the correct line, we add code until we + // reach the correct column too. + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + code += nextLine.substr(0, mapping.generatedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + // Create the SourceNode. + addMappingWithCode(lastMapping, code); + } else { + // There is no new line in between. + // Associate the code between "lastGeneratedColumn" and + // "mapping.generatedColumn" with "lastMapping" + var nextLine = remainingLines[0]; + var code = nextLine.substr(0, mapping.generatedColumn - + lastGeneratedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn - + lastGeneratedColumn); + lastGeneratedColumn = mapping.generatedColumn; + addMappingWithCode(lastMapping, code); + } + } + lastMapping = mapping; + }, this); + // We have processed all mappings. + // Associate the remaining code in the current line with "lastMapping" + // and add the remaining lines without any mapping + addMappingWithCode(lastMapping, remainingLines.join("\n")); + + // Copy sourcesContent into SourceNode + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + node.setSourceContent(sourceFile, content); + } + }); + + return node; + + function addMappingWithCode(mapping, code) { + if (mapping === null || mapping.source === undefined) { + node.add(code); + } else { + node.add(new SourceNode(mapping.originalLine, + mapping.originalColumn, + mapping.source, + code, + mapping.name)); + } + } + }; + + /** + * Add a chunk of generated JS to this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + SourceNode.prototype.add = function SourceNode_add(aChunk) { + if (Array.isArray(aChunk)) { + aChunk.forEach(function (chunk) { + this.add(chunk); + }, this); + } + else if (aChunk instanceof SourceNode || typeof aChunk === "string") { + if (aChunk) { + this.children.push(aChunk); + } + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; + }; + + /** + * Add a chunk of generated JS to the beginning of this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { + if (Array.isArray(aChunk)) { + for (var i = aChunk.length-1; i >= 0; i--) { + this.prepend(aChunk[i]); + } + } + else if (aChunk instanceof SourceNode || typeof aChunk === "string") { + this.children.unshift(aChunk); + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; + }; + + /** + * Walk over the tree of JS snippets in this node and its children. The + * walking function is called once for each snippet of JS and is passed that + * snippet and the its original associated source's line/column location. + * + * @param aFn The traversal function. + */ + SourceNode.prototype.walk = function SourceNode_walk(aFn) { + var chunk; + for (var i = 0, len = this.children.length; i < len; i++) { + chunk = this.children[i]; + if (chunk instanceof SourceNode) { + chunk.walk(aFn); + } + else { + if (chunk !== '') { + aFn(chunk, { source: this.source, + line: this.line, + column: this.column, + name: this.name }); + } + } + } + }; + + /** + * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between + * each of `this.children`. + * + * @param aSep The separator. + */ + SourceNode.prototype.join = function SourceNode_join(aSep) { + var newChildren; + var i; + var len = this.children.length; + if (len > 0) { + newChildren = []; + for (i = 0; i < len-1; i++) { + newChildren.push(this.children[i]); + newChildren.push(aSep); + } + newChildren.push(this.children[i]); + this.children = newChildren; + } + return this; + }; + + /** + * Call String.prototype.replace on the very right-most source snippet. Useful + * for trimming whitespace from the end of a source node, etc. + * + * @param aPattern The pattern to replace. + * @param aReplacement The thing to replace the pattern with. + */ + SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { + var lastChild = this.children[this.children.length - 1]; + if (lastChild instanceof SourceNode) { + lastChild.replaceRight(aPattern, aReplacement); + } + else if (typeof lastChild === 'string') { + this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); + } + else { + this.children.push(''.replace(aPattern, aReplacement)); + } + return this; + }; + + /** + * Set the source content for a source file. This will be added to the SourceMapGenerator + * in the sourcesContent field. + * + * @param aSourceFile The filename of the source file + * @param aSourceContent The content of the source file + */ + SourceNode.prototype.setSourceContent = + function SourceNode_setSourceContent(aSourceFile, aSourceContent) { + this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; + }; + + /** + * Walk over the tree of SourceNodes. The walking function is called for each + * source file content and is passed the filename and source content. + * + * @param aFn The traversal function. + */ + SourceNode.prototype.walkSourceContents = + function SourceNode_walkSourceContents(aFn) { + for (var i = 0, len = this.children.length; i < len; i++) { + if (this.children[i] instanceof SourceNode) { + this.children[i].walkSourceContents(aFn); + } + } + + var sources = Object.keys(this.sourceContents); + for (var i = 0, len = sources.length; i < len; i++) { + aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]); + } + }; + + /** + * Return the string representation of this source node. Walks over the tree + * and concatenates all the various snippets together to one string. + */ + SourceNode.prototype.toString = function SourceNode_toString() { + var str = ""; + this.walk(function (chunk) { + str += chunk; + }); + return str; + }; + + /** + * Returns the string representation of this source node along with a source + * map. + */ + SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { + var generated = { + code: "", + line: 1, + column: 0 + }; + var map = new SourceMapGenerator(aArgs); + var sourceMappingActive = false; + var lastOriginalSource = null; + var lastOriginalLine = null; + var lastOriginalColumn = null; + var lastOriginalName = null; + this.walk(function (chunk, original) { + generated.code += chunk; + if (original.source !== null + && original.line !== null + && original.column !== null) { + if(lastOriginalSource !== original.source + || lastOriginalLine !== original.line + || lastOriginalColumn !== original.column + || lastOriginalName !== original.name) { + map.addMapping({ + source: original.source, + original: { + line: original.line, + column: original.column + }, + generated: { + line: generated.line, + column: generated.column + }, + name: original.name + }); + } + lastOriginalSource = original.source; + lastOriginalLine = original.line; + lastOriginalColumn = original.column; + lastOriginalName = original.name; + sourceMappingActive = true; + } else if (sourceMappingActive) { + map.addMapping({ + generated: { + line: generated.line, + column: generated.column + } + }); + lastOriginalSource = null; + sourceMappingActive = false; + } + chunk.split('').forEach(function (ch) { + if (ch === '\n') { + generated.line++; + generated.column = 0; + } else { + generated.column++; + } + }); + }); + this.walkSourceContents(function (sourceFile, sourceContent) { + map.setSourceContent(sourceFile, sourceContent); + }); + + return { code: generated.code, map: map }; + }; + + exports.SourceNode = SourceNode; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/util.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/util.js new file mode 100644 index 0000000..87946d3 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/lib/source-map/util.js @@ -0,0 +1,205 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + /** + * This is a helper function for getting values from parameter/options + * objects. + * + * @param args The object we are extracting values from + * @param name The name of the property we are getting. + * @param defaultValue An optional value to return if the property is missing + * from the object. If this is not specified and the property is missing, an + * error will be thrown. + */ + function getArg(aArgs, aName, aDefaultValue) { + if (aName in aArgs) { + return aArgs[aName]; + } else if (arguments.length === 3) { + return aDefaultValue; + } else { + throw new Error('"' + aName + '" is a required argument.'); + } + } + exports.getArg = getArg; + + var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; + var dataUrlRegexp = /^data:.+\,.+/; + + function urlParse(aUrl) { + var match = aUrl.match(urlRegexp); + if (!match) { + return null; + } + return { + scheme: match[1], + auth: match[3], + host: match[4], + port: match[6], + path: match[7] + }; + } + exports.urlParse = urlParse; + + function urlGenerate(aParsedUrl) { + var url = aParsedUrl.scheme + "://"; + if (aParsedUrl.auth) { + url += aParsedUrl.auth + "@" + } + if (aParsedUrl.host) { + url += aParsedUrl.host; + } + if (aParsedUrl.port) { + url += ":" + aParsedUrl.port + } + if (aParsedUrl.path) { + url += aParsedUrl.path; + } + return url; + } + exports.urlGenerate = urlGenerate; + + function join(aRoot, aPath) { + var url; + + if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) { + return aPath; + } + + if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { + url.path = aPath; + return urlGenerate(url); + } + + return aRoot.replace(/\/$/, '') + '/' + aPath; + } + exports.join = join; + + /** + * Because behavior goes wacky when you set `__proto__` on objects, we + * have to prefix all the strings in our set with an arbitrary character. + * + * See https://github.com/mozilla/source-map/pull/31 and + * https://github.com/mozilla/source-map/issues/30 + * + * @param String aStr + */ + function toSetString(aStr) { + return '$' + aStr; + } + exports.toSetString = toSetString; + + function fromSetString(aStr) { + return aStr.substr(1); + } + exports.fromSetString = fromSetString; + + function relative(aRoot, aPath) { + aRoot = aRoot.replace(/\/$/, ''); + + var url = urlParse(aRoot); + if (aPath.charAt(0) == "/" && url && url.path == "/") { + return aPath.slice(1); + } + + return aPath.indexOf(aRoot + '/') === 0 + ? aPath.substr(aRoot.length + 1) + : aPath; + } + exports.relative = relative; + + function strcmp(aStr1, aStr2) { + var s1 = aStr1 || ""; + var s2 = aStr2 || ""; + return (s1 > s2) - (s1 < s2); + } + + /** + * Comparator between two mappings where the original positions are compared. + * + * Optionally pass in `true` as `onlyCompareGenerated` to consider two + * mappings with the same original source/line/column, but different generated + * line and column the same. Useful when searching for a mapping with a + * stubbed out mapping. + */ + function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) { + var cmp; + + cmp = strcmp(mappingA.source, mappingB.source); + if (cmp) { + return cmp; + } + + cmp = mappingA.originalLine - mappingB.originalLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.originalColumn - mappingB.originalColumn; + if (cmp || onlyCompareOriginal) { + return cmp; + } + + cmp = strcmp(mappingA.name, mappingB.name); + if (cmp) { + return cmp; + } + + cmp = mappingA.generatedLine - mappingB.generatedLine; + if (cmp) { + return cmp; + } + + return mappingA.generatedColumn - mappingB.generatedColumn; + }; + exports.compareByOriginalPositions = compareByOriginalPositions; + + /** + * Comparator between two mappings where the generated positions are + * compared. + * + * Optionally pass in `true` as `onlyCompareGenerated` to consider two + * mappings with the same generated line and column, but different + * source/name/original line and column the same. Useful when searching for a + * mapping with a stubbed out mapping. + */ + function compareByGeneratedPositions(mappingA, mappingB, onlyCompareGenerated) { + var cmp; + + cmp = mappingA.generatedLine - mappingB.generatedLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.generatedColumn - mappingB.generatedColumn; + if (cmp || onlyCompareGenerated) { + return cmp; + } + + cmp = strcmp(mappingA.source, mappingB.source); + if (cmp) { + return cmp; + } + + cmp = mappingA.originalLine - mappingB.originalLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.originalColumn - mappingB.originalColumn; + if (cmp) { + return cmp; + } + + return strcmp(mappingA.name, mappingB.name); + }; + exports.compareByGeneratedPositions = compareByGeneratedPositions; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/LICENSE b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/LICENSE new file mode 100644 index 0000000..f33d665 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/LICENSE @@ -0,0 +1,58 @@ +amdefine is released under two licenses: new BSD, and MIT. You may pick the +license that best suits your development needs. The text of both licenses are +provided below. + + +The "New" BSD License: +---------------------- + +Copyright (c) 2011, The Dojo Foundation +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 the Dojo Foundation 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 OWNER 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. + + + +MIT License +----------- + +Copyright (c) 2011, The Dojo Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/README.md b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/README.md new file mode 100644 index 0000000..c6995c0 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/README.md @@ -0,0 +1,171 @@ +# amdefine + +A module that can be used to implement AMD's define() in Node. This allows you +to code to the AMD API and have the module work in node programs without +requiring those other programs to use AMD. + +## Usage + +**1)** Update your package.json to indicate amdefine as a dependency: + +```javascript + "dependencies": { + "amdefine": ">=0.1.0" + } +``` + +Then run `npm install` to get amdefine into your project. + +**2)** At the top of each module that uses define(), place this code: + +```javascript +if (typeof define !== 'function') { var define = require('amdefine')(module) } +``` + +**Only use these snippets** when loading amdefine. If you preserve the basic structure, +with the braces, it will be stripped out when using the [RequireJS optimizer](#optimizer). + +You can add spaces, line breaks and even require amdefine with a local path, but +keep the rest of the structure to get the stripping behavior. + +As you may know, because `if` statements in JavaScript don't have their own scope, the var +declaration in the above snippet is made whether the `if` expression is truthy or not. If +RequireJS is loaded then the declaration is superfluous because `define` is already already +declared in the same scope in RequireJS. Fortunately JavaScript handles multiple `var` +declarations of the same variable in the same scope gracefully. + +If you want to deliver amdefine.js with your code rather than specifying it as a dependency +with npm, then just download the latest release and refer to it using a relative path: + +[Latest Version](https://github.com/jrburke/amdefine/raw/latest/amdefine.js) + +### amdefine/intercept + +Consider this very experimental. + +Instead of pasting the piece of text for the amdefine setup of a `define` +variable in each module you create or consume, you can use `amdefine/intercept` +instead. It will automatically insert the above snippet in each .js file loaded +by Node. + +**Warning**: you should only use this if you are creating an application that +is consuming AMD style defined()'d modules that are distributed via npm and want +to run that code in Node. + +For library code where you are not sure if it will be used by others in Node or +in the browser, then explicitly depending on amdefine and placing the code +snippet above is suggested path, instead of using `amdefine/intercept`. The +intercept module affects all .js files loaded in the Node app, and it is +inconsiderate to modify global state like that unless you are also controlling +the top level app. + +#### Why distribute AMD-style nodes via npm? + +npm has a lot of weaknesses for front-end use (installed layout is not great, +should have better support for the `baseUrl + moduleID + '.js' style of loading, +single file JS installs), but some people want a JS package manager and are +willing to live with those constraints. If that is you, but still want to author +in AMD style modules to get dynamic require([]), better direct source usage and +powerful loader plugin support in the browser, then this tool can help. + +#### amdefine/intercept usage + +Just require it in your top level app module (for example index.js, server.js): + +```javascript +require('amdefine/intercept'); +``` + +The module does not return a value, so no need to assign the result to a local +variable. + +Then just require() code as you normally would with Node's require(). Any .js +loaded after the intercept require will have the amdefine check injected in +the .js source as it is loaded. It does not modify the source on disk, just +prepends some content to the text of the module as it is loaded by Node. + +#### How amdefine/intercept works + +It overrides the `Module._extensions['.js']` in Node to automatically prepend +the amdefine snippet above. So, it will affect any .js file loaded by your +app. + +## define() usage + +It is best if you use the anonymous forms of define() in your module: + +```javascript +define(function (require) { + var dependency = require('dependency'); +}); +``` + +or + +```javascript +define(['dependency'], function (dependency) { + +}); +``` + +## RequireJS optimizer integration. + +Version 1.0.3 of the [RequireJS optimizer](http://requirejs.org/docs/optimization.html) +will have support for stripping the `if (typeof define !== 'function')` check +mentioned above, so you can include this snippet for code that runs in the +browser, but avoid taking the cost of the if() statement once the code is +optimized for deployment. + +## Node 0.4 Support + +If you want to support Node 0.4, then add `require` as the second parameter to amdefine: + +```javascript +//Only if you want Node 0.4. If using 0.5 or later, use the above snippet. +if (typeof define !== 'function') { var define = require('amdefine')(module, require) } +``` + +## Limitations + +### Synchronous vs Asynchronous + +amdefine creates a define() function that is callable by your code. It will +execute and trace dependencies and call the factory function *synchronously*, +to keep the behavior in line with Node's synchronous dependency tracing. + +The exception: calling AMD's callback-style require() from inside a factory +function. The require callback is called on process.nextTick(): + +```javascript +define(function (require) { + require(['a'], function(a) { + //'a' is loaded synchronously, but + //this callback is called on process.nextTick(). + }); +}); +``` + +### Loader Plugins + +Loader plugins are supported as long as they call their load() callbacks +synchronously. So ones that do network requests will not work. However plugins +like [text](http://requirejs.org/docs/api.html#text) can load text files locally. + +The plugin API's `load.fromText()` is **not supported** in amdefine, so this means +transpiler plugins like the [CoffeeScript loader plugin](https://github.com/jrburke/require-cs) +will not work. This may be fixable, but it is a bit complex, and I do not have +enough node-fu to figure it out yet. See the source for amdefine.js if you want +to get an idea of the issues involved. + +## Tests + +To run the tests, cd to **tests** and run: + +``` +node all.js +node all-intercept.js +``` + +## License + +New BSD and MIT. Check the LICENSE file for all the details. diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/amdefine.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/amdefine.js new file mode 100644 index 0000000..53bf5a6 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/amdefine.js @@ -0,0 +1,299 @@ +/** vim: et:ts=4:sw=4:sts=4 + * @license amdefine 0.1.0 Copyright (c) 2011, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/amdefine for details + */ + +/*jslint node: true */ +/*global module, process */ +'use strict'; + +/** + * Creates a define for node. + * @param {Object} module the "module" object that is defined by Node for the + * current module. + * @param {Function} [requireFn]. Node's require function for the current module. + * It only needs to be passed in Node versions before 0.5, when module.require + * did not exist. + * @returns {Function} a define function that is usable for the current node + * module. + */ +function amdefine(module, requireFn) { + 'use strict'; + var defineCache = {}, + loaderCache = {}, + alreadyCalled = false, + path = require('path'), + makeRequire, stringRequire; + + /** + * Trims the . and .. from an array of path segments. + * It will keep a leading path segment if a .. will become + * the first path segment, to help with module name lookups, + * which act like paths, but can be remapped. But the end result, + * all paths that use this function should look normalized. + * NOTE: this method MODIFIES the input array. + * @param {Array} ary the array of path segments. + */ + function trimDots(ary) { + var i, part; + for (i = 0; ary[i]; i+= 1) { + part = ary[i]; + if (part === '.') { + ary.splice(i, 1); + i -= 1; + } else if (part === '..') { + if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { + //End of the line. Keep at least one non-dot + //path segment at the front so it can be mapped + //correctly to disk. Otherwise, there is likely + //no path mapping for a path starting with '..'. + //This can still fail, but catches the most reasonable + //uses of .. + break; + } else if (i > 0) { + ary.splice(i - 1, 2); + i -= 2; + } + } + } + } + + function normalize(name, baseName) { + var baseParts; + + //Adjust any relative paths. + if (name && name.charAt(0) === '.') { + //If have a base name, try to normalize against it, + //otherwise, assume it is a top-level require that will + //be relative to baseUrl in the end. + if (baseName) { + baseParts = baseName.split('/'); + baseParts = baseParts.slice(0, baseParts.length - 1); + baseParts = baseParts.concat(name.split('/')); + trimDots(baseParts); + name = baseParts.join('/'); + } + } + + return name; + } + + /** + * Create the normalize() function passed to a loader plugin's + * normalize method. + */ + function makeNormalize(relName) { + return function (name) { + return normalize(name, relName); + }; + } + + function makeLoad(id) { + function load(value) { + loaderCache[id] = value; + } + + load.fromText = function (id, text) { + //This one is difficult because the text can/probably uses + //define, and any relative paths and requires should be relative + //to that id was it would be found on disk. But this would require + //bootstrapping a module/require fairly deeply from node core. + //Not sure how best to go about that yet. + throw new Error('amdefine does not implement load.fromText'); + }; + + return load; + } + + makeRequire = function (systemRequire, exports, module, relId) { + function amdRequire(deps, callback) { + if (typeof deps === 'string') { + //Synchronous, single module require('') + return stringRequire(systemRequire, exports, module, deps, relId); + } else { + //Array of dependencies with a callback. + + //Convert the dependencies to modules. + deps = deps.map(function (depName) { + return stringRequire(systemRequire, exports, module, depName, relId); + }); + + //Wait for next tick to call back the require call. + process.nextTick(function () { + callback.apply(null, deps); + }); + } + } + + amdRequire.toUrl = function (filePath) { + if (filePath.indexOf('.') === 0) { + return normalize(filePath, path.dirname(module.filename)); + } else { + return filePath; + } + }; + + return amdRequire; + }; + + //Favor explicit value, passed in if the module wants to support Node 0.4. + requireFn = requireFn || function req() { + return module.require.apply(module, arguments); + }; + + function runFactory(id, deps, factory) { + var r, e, m, result; + + if (id) { + e = loaderCache[id] = {}; + m = { + id: id, + uri: __filename, + exports: e + }; + r = makeRequire(requireFn, e, m, id); + } else { + //Only support one define call per file + if (alreadyCalled) { + throw new Error('amdefine with no module ID cannot be called more than once per file.'); + } + alreadyCalled = true; + + //Use the real variables from node + //Use module.exports for exports, since + //the exports in here is amdefine exports. + e = module.exports; + m = module; + r = makeRequire(requireFn, e, m, module.id); + } + + //If there are dependencies, they are strings, so need + //to convert them to dependency values. + if (deps) { + deps = deps.map(function (depName) { + return r(depName); + }); + } + + //Call the factory with the right dependencies. + if (typeof factory === 'function') { + result = factory.apply(m.exports, deps); + } else { + result = factory; + } + + if (result !== undefined) { + m.exports = result; + if (id) { + loaderCache[id] = m.exports; + } + } + } + + stringRequire = function (systemRequire, exports, module, id, relId) { + //Split the ID by a ! so that + var index = id.indexOf('!'), + originalId = id, + prefix, plugin; + + if (index === -1) { + id = normalize(id, relId); + + //Straight module lookup. If it is one of the special dependencies, + //deal with it, otherwise, delegate to node. + if (id === 'require') { + return makeRequire(systemRequire, exports, module, relId); + } else if (id === 'exports') { + return exports; + } else if (id === 'module') { + return module; + } else if (loaderCache.hasOwnProperty(id)) { + return loaderCache[id]; + } else if (defineCache[id]) { + runFactory.apply(null, defineCache[id]); + return loaderCache[id]; + } else { + if(systemRequire) { + return systemRequire(originalId); + } else { + throw new Error('No module with ID: ' + id); + } + } + } else { + //There is a plugin in play. + prefix = id.substring(0, index); + id = id.substring(index + 1, id.length); + + plugin = stringRequire(systemRequire, exports, module, prefix, relId); + + if (plugin.normalize) { + id = plugin.normalize(id, makeNormalize(relId)); + } else { + //Normalize the ID normally. + id = normalize(id, relId); + } + + if (loaderCache[id]) { + return loaderCache[id]; + } else { + plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {}); + + return loaderCache[id]; + } + } + }; + + //Create a define function specific to the module asking for amdefine. + function define(id, deps, factory) { + if (Array.isArray(id)) { + factory = deps; + deps = id; + id = undefined; + } else if (typeof id !== 'string') { + factory = id; + id = deps = undefined; + } + + if (deps && !Array.isArray(deps)) { + factory = deps; + deps = undefined; + } + + if (!deps) { + deps = ['require', 'exports', 'module']; + } + + //Set up properties for this module. If an ID, then use + //internal cache. If no ID, then use the external variables + //for this node module. + if (id) { + //Put the module in deep freeze until there is a + //require call for it. + defineCache[id] = [id, deps, factory]; + } else { + runFactory(id, deps, factory); + } + } + + //define.require, which has access to all the values in the + //cache. Useful for AMD modules that all have IDs in the file, + //but need to finally export a value to node based on one of those + //IDs. + define.require = function (id) { + if (loaderCache[id]) { + return loaderCache[id]; + } + + if (defineCache[id]) { + runFactory.apply(null, defineCache[id]); + return loaderCache[id]; + } + }; + + define.amd = {}; + + return define; +} + +module.exports = amdefine; diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/intercept.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/intercept.js new file mode 100644 index 0000000..771a983 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/intercept.js @@ -0,0 +1,36 @@ +/*jshint node: true */ +var inserted, + Module = require('module'), + fs = require('fs'), + existingExtFn = Module._extensions['.js'], + amdefineRegExp = /amdefine\.js/; + +inserted = "if (typeof define !== 'function') {var define = require('amdefine')(module)}"; + +//From the node/lib/module.js source: +function stripBOM(content) { + // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) + // because the buffer-to-string conversion in `fs.readFileSync()` + // translates it to FEFF, the UTF-16 BOM. + if (content.charCodeAt(0) === 0xFEFF) { + content = content.slice(1); + } + return content; +} + +//Also adapted from the node/lib/module.js source: +function intercept(module, filename) { + var content = stripBOM(fs.readFileSync(filename, 'utf8')); + + if (!amdefineRegExp.test(module.id)) { + content = inserted + content; + } + + module._compile(content, filename); +} + +intercept._id = 'amdefine/intercept'; + +if (!existingExtFn._id || existingExtFn._id !== intercept._id) { + Module._extensions['.js'] = intercept; +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/package.json b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/package.json new file mode 100644 index 0000000..7041776 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/node_modules/amdefine/package.json @@ -0,0 +1,40 @@ +{ + "name": "amdefine", + "description": "Provide AMD's define() API for declaring modules in the AMD format", + "version": "0.1.0", + "homepage": "http://github.com/jrburke/amdefine", + "author": { + "name": "James Burke", + "email": "jrburke@gmail.com", + "url": "http://github.com/jrburke" + }, + "licenses": [ + { + "type": "BSD", + "url": "https://github.com/jrburke/amdefine/blob/master/LICENSE" + }, + { + "type": "MIT", + "url": "https://github.com/jrburke/amdefine/blob/master/LICENSE" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/jrburke/amdefine.git" + }, + "main": "./amdefine.js", + "engines": { + "node": ">=0.4.2" + }, + "readme": "# amdefine\n\nA module that can be used to implement AMD's define() in Node. This allows you\nto code to the AMD API and have the module work in node programs without\nrequiring those other programs to use AMD.\n\n## Usage\n\n**1)** Update your package.json to indicate amdefine as a dependency:\n\n```javascript\n \"dependencies\": {\n \"amdefine\": \">=0.1.0\"\n }\n```\n\nThen run `npm install` to get amdefine into your project.\n\n**2)** At the top of each module that uses define(), place this code:\n\n```javascript\nif (typeof define !== 'function') { var define = require('amdefine')(module) }\n```\n\n**Only use these snippets** when loading amdefine. If you preserve the basic structure,\nwith the braces, it will be stripped out when using the [RequireJS optimizer](#optimizer).\n\nYou can add spaces, line breaks and even require amdefine with a local path, but\nkeep the rest of the structure to get the stripping behavior.\n\nAs you may know, because `if` statements in JavaScript don't have their own scope, the var\ndeclaration in the above snippet is made whether the `if` expression is truthy or not. If\nRequireJS is loaded then the declaration is superfluous because `define` is already already\ndeclared in the same scope in RequireJS. Fortunately JavaScript handles multiple `var`\ndeclarations of the same variable in the same scope gracefully.\n\nIf you want to deliver amdefine.js with your code rather than specifying it as a dependency\nwith npm, then just download the latest release and refer to it using a relative path:\n\n[Latest Version](https://github.com/jrburke/amdefine/raw/latest/amdefine.js)\n\n### amdefine/intercept\n\nConsider this very experimental.\n\nInstead of pasting the piece of text for the amdefine setup of a `define`\nvariable in each module you create or consume, you can use `amdefine/intercept`\ninstead. It will automatically insert the above snippet in each .js file loaded\nby Node.\n\n**Warning**: you should only use this if you are creating an application that\nis consuming AMD style defined()'d modules that are distributed via npm and want\nto run that code in Node.\n\nFor library code where you are not sure if it will be used by others in Node or\nin the browser, then explicitly depending on amdefine and placing the code\nsnippet above is suggested path, instead of using `amdefine/intercept`. The\nintercept module affects all .js files loaded in the Node app, and it is\ninconsiderate to modify global state like that unless you are also controlling\nthe top level app.\n\n#### Why distribute AMD-style nodes via npm?\n\nnpm has a lot of weaknesses for front-end use (installed layout is not great,\nshould have better support for the `baseUrl + moduleID + '.js' style of loading,\nsingle file JS installs), but some people want a JS package manager and are\nwilling to live with those constraints. If that is you, but still want to author\nin AMD style modules to get dynamic require([]), better direct source usage and\npowerful loader plugin support in the browser, then this tool can help.\n\n#### amdefine/intercept usage\n\nJust require it in your top level app module (for example index.js, server.js):\n\n```javascript\nrequire('amdefine/intercept');\n```\n\nThe module does not return a value, so no need to assign the result to a local\nvariable.\n\nThen just require() code as you normally would with Node's require(). Any .js\nloaded after the intercept require will have the amdefine check injected in\nthe .js source as it is loaded. It does not modify the source on disk, just\nprepends some content to the text of the module as it is loaded by Node.\n\n#### How amdefine/intercept works\n\nIt overrides the `Module._extensions['.js']` in Node to automatically prepend\nthe amdefine snippet above. So, it will affect any .js file loaded by your\napp.\n\n## define() usage\n\nIt is best if you use the anonymous forms of define() in your module:\n\n```javascript\ndefine(function (require) {\n var dependency = require('dependency');\n});\n```\n\nor\n\n```javascript\ndefine(['dependency'], function (dependency) {\n\n});\n```\n\n## RequireJS optimizer integration. \n\nVersion 1.0.3 of the [RequireJS optimizer](http://requirejs.org/docs/optimization.html)\nwill have support for stripping the `if (typeof define !== 'function')` check\nmentioned above, so you can include this snippet for code that runs in the\nbrowser, but avoid taking the cost of the if() statement once the code is\noptimized for deployment.\n\n## Node 0.4 Support\n\nIf you want to support Node 0.4, then add `require` as the second parameter to amdefine:\n\n```javascript\n//Only if you want Node 0.4. If using 0.5 or later, use the above snippet.\nif (typeof define !== 'function') { var define = require('amdefine')(module, require) }\n```\n\n## Limitations\n\n### Synchronous vs Asynchronous\n\namdefine creates a define() function that is callable by your code. It will\nexecute and trace dependencies and call the factory function *synchronously*,\nto keep the behavior in line with Node's synchronous dependency tracing.\n\nThe exception: calling AMD's callback-style require() from inside a factory\nfunction. The require callback is called on process.nextTick():\n\n```javascript\ndefine(function (require) {\n require(['a'], function(a) {\n //'a' is loaded synchronously, but\n //this callback is called on process.nextTick().\n });\n});\n```\n\n### Loader Plugins\n\nLoader plugins are supported as long as they call their load() callbacks\nsynchronously. So ones that do network requests will not work. However plugins\nlike [text](http://requirejs.org/docs/api.html#text) can load text files locally.\n\nThe plugin API's `load.fromText()` is **not supported** in amdefine, so this means\ntranspiler plugins like the [CoffeeScript loader plugin](https://github.com/jrburke/require-cs)\nwill not work. This may be fixable, but it is a bit complex, and I do not have\nenough node-fu to figure it out yet. See the source for amdefine.js if you want\nto get an idea of the issues involved.\n\n## Tests\n\nTo run the tests, cd to **tests** and run:\n\n```\nnode all.js\nnode all-intercept.js\n```\n\n## License\n\nNew BSD and MIT. Check the LICENSE file for all the details.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/jrburke/amdefine/issues" + }, + "_id": "amdefine@0.1.0", + "dist": { + "shasum": "273a820f5f58f0585e74bf1f5b8d7c03e2e56ba8" + }, + "_from": "amdefine@>=0.0.4", + "_resolved": "https://registry.npmjs.org/amdefine/-/amdefine-0.1.0.tgz" +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/package.json b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/package.json new file mode 100644 index 0000000..8ff0560 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/package.json @@ -0,0 +1,114 @@ +{ + "name": "source-map", + "description": "Generates and consumes source maps", + "version": "0.1.31", + "homepage": "https://github.com/mozilla/source-map", + "author": { + "name": "Nick Fitzgerald", + "email": "nfitzgerald@mozilla.com" + }, + "contributors": [ + { + "name": "Tobias Koppers", + "email": "tobias.koppers@googlemail.com" + }, + { + "name": "Duncan Beevers", + "email": "duncan@dweebd.com" + }, + { + "name": "Stephen Crane", + "email": "scrane@mozilla.com" + }, + { + "name": "Ryan Seddon", + "email": "seddon.ryan@gmail.com" + }, + { + "name": "Miles Elam", + "email": "miles.elam@deem.com" + }, + { + "name": "Mihai Bazon", + "email": "mihai.bazon@gmail.com" + }, + { + "name": "Michael Ficarra", + "email": "github.public.email@michael.ficarra.me" + }, + { + "name": "Todd Wolfson", + "email": "todd@twolfson.com" + }, + { + "name": "Alexander Solovyov", + "email": "alexander@solovyov.net" + }, + { + "name": "Felix Gnass", + "email": "fgnass@gmail.com" + }, + { + "name": "Conrad Irwin", + "email": "conrad.irwin@gmail.com" + }, + { + "name": "usrbincc", + "email": "usrbincc@yahoo.com" + }, + { + "name": "David Glasser", + "email": "glasser@davidglasser.net" + }, + { + "name": "Chase Douglas", + "email": "chase@newrelic.com" + }, + { + "name": "Evan Wallace", + "email": "evan.exe@gmail.com" + }, + { + "name": "Heather Arthur", + "email": "fayearthur@gmail.com" + } + ], + "repository": { + "type": "git", + "url": "http://github.com/mozilla/source-map.git" + }, + "directories": { + "lib": "./lib" + }, + "main": "./lib/source-map.js", + "engines": { + "node": ">=0.8.0" + }, + "licenses": [ + { + "type": "BSD", + "url": "http://opensource.org/licenses/BSD-3-Clause" + } + ], + "dependencies": { + "amdefine": ">=0.0.4" + }, + "devDependencies": { + "dryice": ">=0.4.8" + }, + "scripts": { + "test": "node test/run-tests.js", + "build": "node Makefile.dryice.js" + }, + "readme": "# Source Map\n\nThis is a library to generate and consume the source map format\n[described here][format].\n\nThis library is written in the Asynchronous Module Definition format, and works\nin the following environments:\n\n* Modern Browsers supporting ECMAScript 5 (either after the build, or with an\n AMD loader such as RequireJS)\n\n* Inside Firefox (as a JSM file, after the build)\n\n* With NodeJS versions 0.8.X and higher\n\n## Node\n\n $ npm install source-map\n\n## Building from Source (for everywhere else)\n\nInstall Node and then run\n\n $ git clone https://fitzgen@github.com/mozilla/source-map.git\n $ cd source-map\n $ npm link .\n\nNext, run\n\n $ node Makefile.dryice.js\n\nThis should spew a bunch of stuff to stdout, and create the following files:\n\n* `dist/source-map.js` - The unminified browser version.\n\n* `dist/source-map.min.js` - The minified browser version.\n\n* `dist/SourceMap.jsm` - The JavaScript Module for inclusion in Firefox source.\n\n## Examples\n\n### Consuming a source map\n\n var rawSourceMap = {\n version: 3,\n file: 'min.js',\n names: ['bar', 'baz', 'n'],\n sources: ['one.js', 'two.js'],\n sourceRoot: 'http://example.com/www/js/',\n mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA'\n };\n\n var smc = new SourceMapConsumer(rawSourceMap);\n\n console.log(smc.sources);\n // [ 'http://example.com/www/js/one.js',\n // 'http://example.com/www/js/two.js' ]\n\n console.log(smc.originalPositionFor({\n line: 2,\n column: 28\n }));\n // { source: 'http://example.com/www/js/two.js',\n // line: 2,\n // column: 10,\n // name: 'n' }\n\n console.log(smc.generatedPositionFor({\n source: 'http://example.com/www/js/two.js',\n line: 2,\n column: 10\n }));\n // { line: 2, column: 28 }\n\n smc.eachMapping(function (m) {\n // ...\n });\n\n### Generating a source map\n\nIn depth guide:\n[**Compiling to JavaScript, and Debugging with Source Maps**](https://hacks.mozilla.org/2013/05/compiling-to-javascript-and-debugging-with-source-maps/)\n\n#### With SourceNode (high level API)\n\n function compile(ast) {\n switch (ast.type) {\n case 'BinaryExpression':\n return new SourceNode(\n ast.location.line,\n ast.location.column,\n ast.location.source,\n [compile(ast.left), \" + \", compile(ast.right)]\n );\n case 'Literal':\n return new SourceNode(\n ast.location.line,\n ast.location.column,\n ast.location.source,\n String(ast.value)\n );\n // ...\n default:\n throw new Error(\"Bad AST\");\n }\n }\n\n var ast = parse(\"40 + 2\", \"add.js\");\n console.log(compile(ast).toStringWithSourceMap({\n file: 'add.js'\n }));\n // { code: '40 + 2',\n // map: [object SourceMapGenerator] }\n\n#### With SourceMapGenerator (low level API)\n\n var map = new SourceMapGenerator({\n file: \"source-mapped.js\"\n });\n\n map.addMapping({\n generated: {\n line: 10,\n column: 35\n },\n source: \"foo.js\",\n original: {\n line: 33,\n column: 2\n },\n name: \"christopher\"\n });\n\n console.log(map.toString());\n // '{\"version\":3,\"file\":\"source-mapped.js\",\"sources\":[\"foo.js\"],\"names\":[\"christopher\"],\"mappings\":\";;;;;;;;;mCAgCEA\"}'\n\n## API\n\nGet a reference to the module:\n\n // NodeJS\n var sourceMap = require('source-map');\n\n // Browser builds\n var sourceMap = window.sourceMap;\n\n // Inside Firefox\n let sourceMap = {};\n Components.utils.import('resource:///modules/devtools/SourceMap.jsm', sourceMap);\n\n### SourceMapConsumer\n\nA SourceMapConsumer instance represents a parsed source map which we can query\nfor information about the original file positions by giving it a file position\nin the generated source.\n\n#### new SourceMapConsumer(rawSourceMap)\n\nThe only parameter is the raw source map (either as a string which can be\n`JSON.parse`'d, or an object). According to the spec, source maps have the\nfollowing attributes:\n\n* `version`: Which version of the source map spec this map is following.\n\n* `sources`: An array of URLs to the original source files.\n\n* `names`: An array of identifiers which can be referrenced by individual\n mappings.\n\n* `sourceRoot`: Optional. The URL root from which all sources are relative.\n\n* `sourcesContent`: Optional. An array of contents of the original source files.\n\n* `mappings`: A string of base64 VLQs which contain the actual mappings.\n\n* `file`: The generated filename this source map is associated with.\n\n#### SourceMapConsumer.prototype.originalPositionFor(generatedPosition)\n\nReturns the original source, line, and column information for the generated\nsource's line and column positions provided. The only argument is an object with\nthe following properties:\n\n* `line`: The line number in the generated source.\n\n* `column`: The column number in the generated source.\n\nand an object is returned with the following properties:\n\n* `source`: The original source file, or null if this information is not\n available.\n\n* `line`: The line number in the original source, or null if this information is\n not available.\n\n* `column`: The column number in the original source, or null or null if this\n information is not available.\n\n* `name`: The original identifier, or null if this information is not available.\n\n#### SourceMapConsumer.prototype.generatedPositionFor(originalPosition)\n\nReturns the generated line and column information for the original source,\nline, and column positions provided. The only argument is an object with\nthe following properties:\n\n* `source`: The filename of the original source.\n\n* `line`: The line number in the original source.\n\n* `column`: The column number in the original source.\n\nand an object is returned with the following properties:\n\n* `line`: The line number in the generated source, or null.\n\n* `column`: The column number in the generated source, or null.\n\n#### SourceMapConsumer.prototype.sourceContentFor(source)\n\nReturns the original source content for the source provided. The only\nargument is the URL of the original source file.\n\n#### SourceMapConsumer.prototype.eachMapping(callback, context, order)\n\nIterate over each mapping between an original source/line/column and a\ngenerated line/column in this source map.\n\n* `callback`: The function that is called with each mapping. Mappings have the\n form `{ source, generatedLine, generatedColumn, originalLine, originalColumn,\n name }`\n\n* `context`: Optional. If specified, this object will be the value of `this`\n every time that `callback` is called.\n\n* `order`: Either `SourceMapConsumer.GENERATED_ORDER` or\n `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to iterate over\n the mappings sorted by the generated file's line/column order or the\n original's source/line/column order, respectively. Defaults to\n `SourceMapConsumer.GENERATED_ORDER`.\n\n### SourceMapGenerator\n\nAn instance of the SourceMapGenerator represents a source map which is being\nbuilt incrementally.\n\n#### new SourceMapGenerator(startOfSourceMap)\n\nTo create a new one, you must pass an object with the following properties:\n\n* `file`: The filename of the generated source that this source map is\n associated with.\n\n* `sourceRoot`: An optional root for all relative URLs in this source map.\n\n#### SourceMapGenerator.fromSourceMap(sourceMapConsumer)\n\nCreates a new SourceMapGenerator based on a SourceMapConsumer\n\n* `sourceMapConsumer` The SourceMap.\n\n#### SourceMapGenerator.prototype.addMapping(mapping)\n\nAdd a single mapping from original source line and column to the generated\nsource's line and column for this source map being created. The mapping object\nshould have the following properties:\n\n* `generated`: An object with the generated line and column positions.\n\n* `original`: An object with the original line and column positions.\n\n* `source`: The original source file (relative to the sourceRoot).\n\n* `name`: An optional original token name for this mapping.\n\n#### SourceMapGenerator.prototype.setSourceContent(sourceFile, sourceContent)\n\nSet the source content for an original source file.\n\n* `sourceFile` the URL of the original source file.\n\n* `sourceContent` the content of the source file.\n\n#### SourceMapGenerator.prototype.applySourceMap(sourceMapConsumer[, sourceFile])\n\nApplies a SourceMap for a source file to the SourceMap.\nEach mapping to the supplied source file is rewritten using the\nsupplied SourceMap. Note: The resolution for the resulting mappings\nis the minimium of this map and the supplied map.\n\n* `sourceMapConsumer`: The SourceMap to be applied.\n\n* `sourceFile`: Optional. The filename of the source file.\n If omitted, sourceMapConsumer.file will be used.\n\n#### SourceMapGenerator.prototype.toString()\n\nRenders the source map being generated to a string.\n\n### SourceNode\n\nSourceNodes provide a way to abstract over interpolating and/or concatenating\nsnippets of generated JavaScript source code, while maintaining the line and\ncolumn information associated between those snippets and the original source\ncode. This is useful as the final intermediate representation a compiler might\nuse before outputting the generated JS and source map.\n\n#### new SourceNode(line, column, source[, chunk[, name]])\n\n* `line`: The original line number associated with this source node, or null if\n it isn't associated with an original line.\n\n* `column`: The original column number associated with this source node, or null\n if it isn't associated with an original column.\n\n* `source`: The original source's filename.\n\n* `chunk`: Optional. Is immediately passed to `SourceNode.prototype.add`, see\n below.\n\n* `name`: Optional. The original identifier.\n\n#### SourceNode.fromStringWithSourceMap(code, sourceMapConsumer)\n\nCreates a SourceNode from generated code and a SourceMapConsumer.\n\n* `code`: The generated code\n\n* `sourceMapConsumer` The SourceMap for the generated code\n\n#### SourceNode.prototype.add(chunk)\n\nAdd a chunk of generated JS to this source node.\n\n* `chunk`: A string snippet of generated JS code, another instance of\n `SourceNode`, or an array where each member is one of those things.\n\n#### SourceNode.prototype.prepend(chunk)\n\nPrepend a chunk of generated JS to this source node.\n\n* `chunk`: A string snippet of generated JS code, another instance of\n `SourceNode`, or an array where each member is one of those things.\n\n#### SourceNode.prototype.setSourceContent(sourceFile, sourceContent)\n\nSet the source content for a source file. This will be added to the\n`SourceMap` in the `sourcesContent` field.\n\n* `sourceFile`: The filename of the source file\n\n* `sourceContent`: The content of the source file\n\n#### SourceNode.prototype.walk(fn)\n\nWalk over the tree of JS snippets in this node and its children. The walking\nfunction is called once for each snippet of JS and is passed that snippet and\nthe its original associated source's line/column location.\n\n* `fn`: The traversal function.\n\n#### SourceNode.prototype.walkSourceContents(fn)\n\nWalk over the tree of SourceNodes. The walking function is called for each\nsource file content and is passed the filename and source content.\n\n* `fn`: The traversal function.\n\n#### SourceNode.prototype.join(sep)\n\nLike `Array.prototype.join` except for SourceNodes. Inserts the separator\nbetween each of this source node's children.\n\n* `sep`: The separator.\n\n#### SourceNode.prototype.replaceRight(pattern, replacement)\n\nCall `String.prototype.replace` on the very right-most source snippet. Useful\nfor trimming whitespace from the end of a source node, etc.\n\n* `pattern`: The pattern to replace.\n\n* `replacement`: The thing to replace the pattern with.\n\n#### SourceNode.prototype.toString()\n\nReturn the string representation of this source node. Walks over the tree and\nconcatenates all the various snippets together to one string.\n\n### SourceNode.prototype.toStringWithSourceMap(startOfSourceMap)\n\nReturns the string representation of this tree of source nodes, plus a\nSourceMapGenerator which contains all the mappings between the generated and\noriginal sources.\n\nThe arguments are the same as those to `new SourceMapGenerator`.\n\n## Tests\n\n[![Build Status](https://travis-ci.org/mozilla/source-map.png?branch=master)](https://travis-ci.org/mozilla/source-map)\n\nInstall NodeJS version 0.8.0 or greater, then run `node test/run-tests.js`.\n\nTo add new tests, create a new file named `test/test-.js`\nand export your test functions with names that start with \"test\", for example\n\n exports[\"test doing the foo bar\"] = function (assert, util) {\n ...\n };\n\nThe new test will be located automatically when you run the suite.\n\nThe `util` argument is the test utility module located at `test/source-map/util`.\n\nThe `assert` argument is a cut down version of node's assert module. You have\naccess to the following assertion functions:\n\n* `doesNotThrow`\n\n* `equal`\n\n* `ok`\n\n* `strictEqual`\n\n* `throws`\n\n(The reason for the restricted set of test functions is because we need the\ntests to run inside Firefox's test suite as well and so the assert module is\nshimmed in that environment. See `build/assert-shim.js`.)\n\n[format]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit\n[feature]: https://wiki.mozilla.org/DevTools/Features/SourceMap\n[Dryice]: https://github.com/mozilla/dryice\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/mozilla/source-map/issues" + }, + "_id": "source-map@0.1.31", + "dist": { + "shasum": "11aa197fd21ff05341ed68496292befec6c1ef23" + }, + "_from": "source-map@~0.1.7", + "_resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.31.tgz" +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/run-tests.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/run-tests.js new file mode 100755 index 0000000..626c53f --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/run-tests.js @@ -0,0 +1,71 @@ +#!/usr/bin/env node +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +var assert = require('assert'); +var fs = require('fs'); +var path = require('path'); +var util = require('./source-map/util'); + +function run(tests) { + var failures = []; + var total = 0; + var passed = 0; + + for (var i = 0; i < tests.length; i++) { + for (var k in tests[i].testCase) { + if (/^test/.test(k)) { + total++; + try { + tests[i].testCase[k](assert, util); + passed++; + } + catch (e) { + console.log('FAILED ' + tests[i].name + ': ' + k + '!'); + console.log(e.stack); + } + } + } + } + + console.log(""); + console.log(passed + ' / ' + total + ' tests passed.'); + console.log(""); + + failures.forEach(function (f) { + }); + + return failures.length; +} + +var code; + +process.stdout.on('close', function () { + process.exit(code); +}); + +function isTestFile(f) { + var testToRun = process.argv[2]; + return testToRun + ? path.basename(testToRun) === f + : /^test\-.*?\.js/.test(f); +} + +function toModule(f) { + return './source-map/' + f.replace(/\.js$/, ''); +} + +var requires = fs.readdirSync(path.join(__dirname, 'source-map')) + .filter(isTestFile) + .map(toModule); + +code = run(requires.map(require).map(function (mod, i) { + return { + name: requires[i], + testCase: mod + }; +})); +process.exit(code); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-api.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-api.js new file mode 100644 index 0000000..3801233 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-api.js @@ -0,0 +1,26 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2012 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var sourceMap; + try { + sourceMap = require('../../lib/source-map'); + } catch (e) { + sourceMap = {}; + Components.utils.import('resource:///modules/devtools/SourceMap.jsm', sourceMap); + } + + exports['test that the api is properly exposed in the top level'] = function (assert, util) { + assert.equal(typeof sourceMap.SourceMapGenerator, "function"); + assert.equal(typeof sourceMap.SourceMapConsumer, "function"); + assert.equal(typeof sourceMap.SourceNode, "function"); + }; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-array-set.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-array-set.js new file mode 100644 index 0000000..b5797ed --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-array-set.js @@ -0,0 +1,104 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var ArraySet = require('../../lib/source-map/array-set').ArraySet; + + function makeTestSet() { + var set = new ArraySet(); + for (var i = 0; i < 100; i++) { + set.add(String(i)); + } + return set; + } + + exports['test .has() membership'] = function (assert, util) { + var set = makeTestSet(); + for (var i = 0; i < 100; i++) { + assert.ok(set.has(String(i))); + } + }; + + exports['test .indexOf() elements'] = function (assert, util) { + var set = makeTestSet(); + for (var i = 0; i < 100; i++) { + assert.strictEqual(set.indexOf(String(i)), i); + } + }; + + exports['test .at() indexing'] = function (assert, util) { + var set = makeTestSet(); + for (var i = 0; i < 100; i++) { + assert.strictEqual(set.at(i), String(i)); + } + }; + + exports['test creating from an array'] = function (assert, util) { + var set = ArraySet.fromArray(['foo', 'bar', 'baz', 'quux', 'hasOwnProperty']); + + assert.ok(set.has('foo')); + assert.ok(set.has('bar')); + assert.ok(set.has('baz')); + assert.ok(set.has('quux')); + assert.ok(set.has('hasOwnProperty')); + + assert.strictEqual(set.indexOf('foo'), 0); + assert.strictEqual(set.indexOf('bar'), 1); + assert.strictEqual(set.indexOf('baz'), 2); + assert.strictEqual(set.indexOf('quux'), 3); + + assert.strictEqual(set.at(0), 'foo'); + assert.strictEqual(set.at(1), 'bar'); + assert.strictEqual(set.at(2), 'baz'); + assert.strictEqual(set.at(3), 'quux'); + }; + + exports['test that you can add __proto__; see github issue #30'] = function (assert, util) { + var set = new ArraySet(); + set.add('__proto__'); + assert.ok(set.has('__proto__')); + assert.strictEqual(set.at(0), '__proto__'); + assert.strictEqual(set.indexOf('__proto__'), 0); + }; + + exports['test .fromArray() with duplicates'] = function (assert, util) { + var set = ArraySet.fromArray(['foo', 'foo']); + assert.ok(set.has('foo')); + assert.strictEqual(set.at(0), 'foo'); + assert.strictEqual(set.indexOf('foo'), 0); + assert.strictEqual(set.toArray().length, 1); + + set = ArraySet.fromArray(['foo', 'foo'], true); + assert.ok(set.has('foo')); + assert.strictEqual(set.at(0), 'foo'); + assert.strictEqual(set.at(1), 'foo'); + assert.strictEqual(set.indexOf('foo'), 0); + assert.strictEqual(set.toArray().length, 2); + }; + + exports['test .add() with duplicates'] = function (assert, util) { + var set = new ArraySet(); + set.add('foo'); + + set.add('foo'); + assert.ok(set.has('foo')); + assert.strictEqual(set.at(0), 'foo'); + assert.strictEqual(set.indexOf('foo'), 0); + assert.strictEqual(set.toArray().length, 1); + + set.add('foo', true); + assert.ok(set.has('foo')); + assert.strictEqual(set.at(0), 'foo'); + assert.strictEqual(set.at(1), 'foo'); + assert.strictEqual(set.indexOf('foo'), 0); + assert.strictEqual(set.toArray().length, 2); + }; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-base64-vlq.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-base64-vlq.js new file mode 100644 index 0000000..653a874 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-base64-vlq.js @@ -0,0 +1,24 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var base64VLQ = require('../../lib/source-map/base64-vlq'); + + exports['test normal encoding and decoding'] = function (assert, util) { + var result; + for (var i = -255; i < 256; i++) { + result = base64VLQ.decode(base64VLQ.encode(i)); + assert.ok(result); + assert.equal(result.value, i); + assert.equal(result.rest, ""); + } + }; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-base64.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-base64.js new file mode 100644 index 0000000..ff3a244 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-base64.js @@ -0,0 +1,35 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var base64 = require('../../lib/source-map/base64'); + + exports['test out of range encoding'] = function (assert, util) { + assert.throws(function () { + base64.encode(-1); + }); + assert.throws(function () { + base64.encode(64); + }); + }; + + exports['test out of range decoding'] = function (assert, util) { + assert.throws(function () { + base64.decode('='); + }); + }; + + exports['test normal encoding and decoding'] = function (assert, util) { + for (var i = 0; i < 64; i++) { + assert.equal(base64.decode(base64.encode(i)), i); + } + }; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-binary-search.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-binary-search.js new file mode 100644 index 0000000..ee30683 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-binary-search.js @@ -0,0 +1,54 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var binarySearch = require('../../lib/source-map/binary-search'); + + function numberCompare(a, b) { + return a - b; + } + + exports['test too high'] = function (assert, util) { + var needle = 30; + var haystack = [2,4,6,8,10,12,14,16,18,20]; + + assert.doesNotThrow(function () { + binarySearch.search(needle, haystack, numberCompare); + }); + + assert.equal(binarySearch.search(needle, haystack, numberCompare), 20); + }; + + exports['test too low'] = function (assert, util) { + var needle = 1; + var haystack = [2,4,6,8,10,12,14,16,18,20]; + + assert.doesNotThrow(function () { + binarySearch.search(needle, haystack, numberCompare); + }); + + assert.equal(binarySearch.search(needle, haystack, numberCompare), null); + }; + + exports['test exact search'] = function (assert, util) { + var needle = 4; + var haystack = [2,4,6,8,10,12,14,16,18,20]; + + assert.equal(binarySearch.search(needle, haystack, numberCompare), 4); + }; + + exports['test fuzzy search'] = function (assert, util) { + var needle = 19; + var haystack = [2,4,6,8,10,12,14,16,18,20]; + + assert.equal(binarySearch.search(needle, haystack, numberCompare), 18); + }; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-dog-fooding.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-dog-fooding.js new file mode 100644 index 0000000..d831b92 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-dog-fooding.js @@ -0,0 +1,72 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var SourceMapConsumer = require('../../lib/source-map/source-map-consumer').SourceMapConsumer; + var SourceMapGenerator = require('../../lib/source-map/source-map-generator').SourceMapGenerator; + + exports['test eating our own dog food'] = function (assert, util) { + var smg = new SourceMapGenerator({ + file: 'testing.js', + sourceRoot: '/wu/tang' + }); + + smg.addMapping({ + source: 'gza.coffee', + original: { line: 1, column: 0 }, + generated: { line: 2, column: 2 } + }); + + smg.addMapping({ + source: 'gza.coffee', + original: { line: 2, column: 0 }, + generated: { line: 3, column: 2 } + }); + + smg.addMapping({ + source: 'gza.coffee', + original: { line: 3, column: 0 }, + generated: { line: 4, column: 2 } + }); + + smg.addMapping({ + source: 'gza.coffee', + original: { line: 4, column: 0 }, + generated: { line: 5, column: 2 } + }); + + var smc = new SourceMapConsumer(smg.toString()); + + // Exact + util.assertMapping(2, 2, '/wu/tang/gza.coffee', 1, 0, null, smc, assert); + util.assertMapping(3, 2, '/wu/tang/gza.coffee', 2, 0, null, smc, assert); + util.assertMapping(4, 2, '/wu/tang/gza.coffee', 3, 0, null, smc, assert); + util.assertMapping(5, 2, '/wu/tang/gza.coffee', 4, 0, null, smc, assert); + + // Fuzzy + + // Original to generated + util.assertMapping(2, 0, null, null, null, null, smc, assert, true); + util.assertMapping(2, 9, '/wu/tang/gza.coffee', 1, 0, null, smc, assert, true); + util.assertMapping(3, 0, '/wu/tang/gza.coffee', 1, 0, null, smc, assert, true); + util.assertMapping(3, 9, '/wu/tang/gza.coffee', 2, 0, null, smc, assert, true); + util.assertMapping(4, 0, '/wu/tang/gza.coffee', 2, 0, null, smc, assert, true); + util.assertMapping(4, 9, '/wu/tang/gza.coffee', 3, 0, null, smc, assert, true); + util.assertMapping(5, 0, '/wu/tang/gza.coffee', 3, 0, null, smc, assert, true); + util.assertMapping(5, 9, '/wu/tang/gza.coffee', 4, 0, null, smc, assert, true); + + // Generated to original + util.assertMapping(2, 2, '/wu/tang/gza.coffee', 1, 1, null, smc, assert, null, true); + util.assertMapping(3, 2, '/wu/tang/gza.coffee', 2, 3, null, smc, assert, null, true); + util.assertMapping(4, 2, '/wu/tang/gza.coffee', 3, 6, null, smc, assert, null, true); + util.assertMapping(5, 2, '/wu/tang/gza.coffee', 4, 9, null, smc, assert, null, true); + }; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-map-consumer.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-map-consumer.js new file mode 100644 index 0000000..f2c65a7 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-map-consumer.js @@ -0,0 +1,451 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var SourceMapConsumer = require('../../lib/source-map/source-map-consumer').SourceMapConsumer; + var SourceMapGenerator = require('../../lib/source-map/source-map-generator').SourceMapGenerator; + + exports['test that we can instantiate with a string or an objects'] = function (assert, util) { + assert.doesNotThrow(function () { + var map = new SourceMapConsumer(util.testMap); + }); + assert.doesNotThrow(function () { + var map = new SourceMapConsumer(JSON.stringify(util.testMap)); + }); + }; + + exports['test that the `sources` field has the original sources'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMap); + var sources = map.sources; + + assert.equal(sources[0], '/the/root/one.js'); + assert.equal(sources[1], '/the/root/two.js'); + assert.equal(sources.length, 2); + }; + + exports['test that the source root is reflected in a mapping\'s source field'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMap); + var mapping; + + mapping = map.originalPositionFor({ + line: 2, + column: 1 + }); + assert.equal(mapping.source, '/the/root/two.js'); + + mapping = map.originalPositionFor({ + line: 1, + column: 1 + }); + assert.equal(mapping.source, '/the/root/one.js'); + }; + + exports['test mapping tokens back exactly'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMap); + + util.assertMapping(1, 1, '/the/root/one.js', 1, 1, null, map, assert); + util.assertMapping(1, 5, '/the/root/one.js', 1, 5, null, map, assert); + util.assertMapping(1, 9, '/the/root/one.js', 1, 11, null, map, assert); + util.assertMapping(1, 18, '/the/root/one.js', 1, 21, 'bar', map, assert); + util.assertMapping(1, 21, '/the/root/one.js', 2, 3, null, map, assert); + util.assertMapping(1, 28, '/the/root/one.js', 2, 10, 'baz', map, assert); + util.assertMapping(1, 32, '/the/root/one.js', 2, 14, 'bar', map, assert); + + util.assertMapping(2, 1, '/the/root/two.js', 1, 1, null, map, assert); + util.assertMapping(2, 5, '/the/root/two.js', 1, 5, null, map, assert); + util.assertMapping(2, 9, '/the/root/two.js', 1, 11, null, map, assert); + util.assertMapping(2, 18, '/the/root/two.js', 1, 21, 'n', map, assert); + util.assertMapping(2, 21, '/the/root/two.js', 2, 3, null, map, assert); + util.assertMapping(2, 28, '/the/root/two.js', 2, 10, 'n', map, assert); + }; + + exports['test mapping tokens fuzzy'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMap); + + // Finding original positions + util.assertMapping(1, 20, '/the/root/one.js', 1, 21, 'bar', map, assert, true); + util.assertMapping(1, 30, '/the/root/one.js', 2, 10, 'baz', map, assert, true); + util.assertMapping(2, 12, '/the/root/two.js', 1, 11, null, map, assert, true); + + // Finding generated positions + util.assertMapping(1, 18, '/the/root/one.js', 1, 22, 'bar', map, assert, null, true); + util.assertMapping(1, 28, '/the/root/one.js', 2, 13, 'baz', map, assert, null, true); + util.assertMapping(2, 9, '/the/root/two.js', 1, 16, null, map, assert, null, true); + }; + + exports['test creating source map consumers with )]}\' prefix'] = function (assert, util) { + assert.doesNotThrow(function () { + var map = new SourceMapConsumer(")]}'" + JSON.stringify(util.testMap)); + }); + }; + + exports['test eachMapping'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMap); + var previousLine = -Infinity; + var previousColumn = -Infinity; + map.eachMapping(function (mapping) { + assert.ok(mapping.generatedLine >= previousLine); + + if (mapping.source) { + assert.equal(mapping.source.indexOf(util.testMap.sourceRoot), 0); + } + + if (mapping.generatedLine === previousLine) { + assert.ok(mapping.generatedColumn >= previousColumn); + previousColumn = mapping.generatedColumn; + } + else { + previousLine = mapping.generatedLine; + previousColumn = -Infinity; + } + }); + }; + + exports['test iterating over mappings in a different order'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMap); + var previousLine = -Infinity; + var previousColumn = -Infinity; + var previousSource = ""; + map.eachMapping(function (mapping) { + assert.ok(mapping.source >= previousSource); + + if (mapping.source === previousSource) { + assert.ok(mapping.originalLine >= previousLine); + + if (mapping.originalLine === previousLine) { + assert.ok(mapping.originalColumn >= previousColumn); + previousColumn = mapping.originalColumn; + } + else { + previousLine = mapping.originalLine; + previousColumn = -Infinity; + } + } + else { + previousSource = mapping.source; + previousLine = -Infinity; + previousColumn = -Infinity; + } + }, null, SourceMapConsumer.ORIGINAL_ORDER); + }; + + exports['test that we can set the context for `this` in eachMapping'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMap); + var context = {}; + map.eachMapping(function () { + assert.equal(this, context); + }, context); + }; + + exports['test that the `sourcesContent` field has the original sources'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMapWithSourcesContent); + var sourcesContent = map.sourcesContent; + + assert.equal(sourcesContent[0], ' ONE.foo = function (bar) {\n return baz(bar);\n };'); + assert.equal(sourcesContent[1], ' TWO.inc = function (n) {\n return n + 1;\n };'); + assert.equal(sourcesContent.length, 2); + }; + + exports['test that we can get the original sources for the sources'] = function (assert, util) { + var map = new SourceMapConsumer(util.testMapWithSourcesContent); + var sources = map.sources; + + assert.equal(map.sourceContentFor(sources[0]), ' ONE.foo = function (bar) {\n return baz(bar);\n };'); + assert.equal(map.sourceContentFor(sources[1]), ' TWO.inc = function (n) {\n return n + 1;\n };'); + assert.equal(map.sourceContentFor("one.js"), ' ONE.foo = function (bar) {\n return baz(bar);\n };'); + assert.equal(map.sourceContentFor("two.js"), ' TWO.inc = function (n) {\n return n + 1;\n };'); + assert.throws(function () { + map.sourceContentFor(""); + }, Error); + assert.throws(function () { + map.sourceContentFor("/the/root/three.js"); + }, Error); + assert.throws(function () { + map.sourceContentFor("three.js"); + }, Error); + }; + + exports['test sourceRoot + generatedPositionFor'] = function (assert, util) { + var map = new SourceMapGenerator({ + sourceRoot: 'foo/bar', + file: 'baz.js' + }); + map.addMapping({ + original: { line: 1, column: 1 }, + generated: { line: 2, column: 2 }, + source: 'bang.coffee' + }); + map.addMapping({ + original: { line: 5, column: 5 }, + generated: { line: 6, column: 6 }, + source: 'bang.coffee' + }); + map = new SourceMapConsumer(map.toString()); + + // Should handle without sourceRoot. + var pos = map.generatedPositionFor({ + line: 1, + column: 1, + source: 'bang.coffee' + }); + + assert.equal(pos.line, 2); + assert.equal(pos.column, 2); + + // Should handle with sourceRoot. + var pos = map.generatedPositionFor({ + line: 1, + column: 1, + source: 'foo/bar/bang.coffee' + }); + + assert.equal(pos.line, 2); + assert.equal(pos.column, 2); + }; + + exports['test sourceRoot + originalPositionFor'] = function (assert, util) { + var map = new SourceMapGenerator({ + sourceRoot: 'foo/bar', + file: 'baz.js' + }); + map.addMapping({ + original: { line: 1, column: 1 }, + generated: { line: 2, column: 2 }, + source: 'bang.coffee' + }); + map = new SourceMapConsumer(map.toString()); + + var pos = map.originalPositionFor({ + line: 2, + column: 2, + }); + + // Should always have the prepended source root + assert.equal(pos.source, 'foo/bar/bang.coffee'); + assert.equal(pos.line, 1); + assert.equal(pos.column, 1); + }; + + exports['test github issue #56'] = function (assert, util) { + var map = new SourceMapGenerator({ + sourceRoot: 'http://', + file: 'www.example.com/foo.js' + }); + map.addMapping({ + original: { line: 1, column: 1 }, + generated: { line: 2, column: 2 }, + source: 'www.example.com/original.js' + }); + map = new SourceMapConsumer(map.toString()); + + var sources = map.sources; + assert.equal(sources.length, 1); + assert.equal(sources[0], 'http://www.example.com/original.js'); + }; + + exports['test github issue #43'] = function (assert, util) { + var map = new SourceMapGenerator({ + sourceRoot: 'http://example.com', + file: 'foo.js' + }); + map.addMapping({ + original: { line: 1, column: 1 }, + generated: { line: 2, column: 2 }, + source: 'http://cdn.example.com/original.js' + }); + map = new SourceMapConsumer(map.toString()); + + var sources = map.sources; + assert.equal(sources.length, 1, + 'Should only be one source.'); + assert.equal(sources[0], 'http://cdn.example.com/original.js', + 'Should not be joined with the sourceRoot.'); + }; + + exports['test absolute path, but same host sources'] = function (assert, util) { + var map = new SourceMapGenerator({ + sourceRoot: 'http://example.com/foo/bar', + file: 'foo.js' + }); + map.addMapping({ + original: { line: 1, column: 1 }, + generated: { line: 2, column: 2 }, + source: '/original.js' + }); + map = new SourceMapConsumer(map.toString()); + + var sources = map.sources; + assert.equal(sources.length, 1, + 'Should only be one source.'); + assert.equal(sources[0], 'http://example.com/original.js', + 'Source should be relative the host of the source root.'); + }; + + exports['test github issue #64'] = function (assert, util) { + var map = new SourceMapConsumer({ + "version": 3, + "file": "foo.js", + "sourceRoot": "http://example.com/", + "sources": ["/a"], + "names": [], + "mappings": "AACA", + "sourcesContent": ["foo"] + }); + + assert.equal(map.sourceContentFor("a"), "foo"); + assert.equal(map.sourceContentFor("/a"), "foo"); + }; + + exports['test bug 885597'] = function (assert, util) { + var map = new SourceMapConsumer({ + "version": 3, + "file": "foo.js", + "sourceRoot": "file:///Users/AlGore/Invented/The/Internet/", + "sources": ["/a"], + "names": [], + "mappings": "AACA", + "sourcesContent": ["foo"] + }); + + var s = map.sources[0]; + assert.equal(map.sourceContentFor(s), "foo"); + }; + + exports['test github issue #72, duplicate sources'] = function (assert, util) { + var map = new SourceMapConsumer({ + "version": 3, + "file": "foo.js", + "sources": ["source1.js", "source1.js", "source3.js"], + "names": [], + "mappings": ";EAAC;;IAEE;;MEEE", + "sourceRoot": "http://example.com" + }); + + var pos = map.originalPositionFor({ + line: 2, + column: 2 + }); + assert.equal(pos.source, 'http://example.com/source1.js'); + assert.equal(pos.line, 1); + assert.equal(pos.column, 1); + + var pos = map.originalPositionFor({ + line: 4, + column: 4 + }); + assert.equal(pos.source, 'http://example.com/source1.js'); + assert.equal(pos.line, 3); + assert.equal(pos.column, 3); + + var pos = map.originalPositionFor({ + line: 6, + column: 6 + }); + assert.equal(pos.source, 'http://example.com/source3.js'); + assert.equal(pos.line, 5); + assert.equal(pos.column, 5); + }; + + exports['test github issue #72, duplicate names'] = function (assert, util) { + var map = new SourceMapConsumer({ + "version": 3, + "file": "foo.js", + "sources": ["source.js"], + "names": ["name1", "name1", "name3"], + "mappings": ";EAACA;;IAEEA;;MAEEE", + "sourceRoot": "http://example.com" + }); + + var pos = map.originalPositionFor({ + line: 2, + column: 2 + }); + assert.equal(pos.name, 'name1'); + assert.equal(pos.line, 1); + assert.equal(pos.column, 1); + + var pos = map.originalPositionFor({ + line: 4, + column: 4 + }); + assert.equal(pos.name, 'name1'); + assert.equal(pos.line, 3); + assert.equal(pos.column, 3); + + var pos = map.originalPositionFor({ + line: 6, + column: 6 + }); + assert.equal(pos.name, 'name3'); + assert.equal(pos.line, 5); + assert.equal(pos.column, 5); + }; + + exports['test SourceMapConsumer.fromSourceMap'] = function (assert, util) { + var smg = new SourceMapGenerator({ + sourceRoot: 'http://example.com/', + file: 'foo.js' + }); + smg.addMapping({ + original: { line: 1, column: 1 }, + generated: { line: 2, column: 2 }, + source: 'bar.js' + }); + smg.addMapping({ + original: { line: 2, column: 2 }, + generated: { line: 4, column: 4 }, + source: 'baz.js', + name: 'dirtMcGirt' + }); + smg.setSourceContent('baz.js', 'baz.js content'); + + var smc = SourceMapConsumer.fromSourceMap(smg); + assert.equal(smc.file, 'foo.js'); + assert.equal(smc.sourceRoot, 'http://example.com/'); + assert.equal(smc.sources.length, 2); + assert.equal(smc.sources[0], 'http://example.com/bar.js'); + assert.equal(smc.sources[1], 'http://example.com/baz.js'); + assert.equal(smc.sourceContentFor('baz.js'), 'baz.js content'); + + var pos = smc.originalPositionFor({ + line: 2, + column: 2 + }); + assert.equal(pos.line, 1); + assert.equal(pos.column, 1); + assert.equal(pos.source, 'http://example.com/bar.js'); + assert.equal(pos.name, null); + + pos = smc.generatedPositionFor({ + line: 1, + column: 1, + source: 'http://example.com/bar.js' + }); + assert.equal(pos.line, 2); + assert.equal(pos.column, 2); + + pos = smc.originalPositionFor({ + line: 4, + column: 4 + }); + assert.equal(pos.line, 2); + assert.equal(pos.column, 2); + assert.equal(pos.source, 'http://example.com/baz.js'); + assert.equal(pos.name, 'dirtMcGirt'); + + pos = smc.generatedPositionFor({ + line: 2, + column: 2, + source: 'http://example.com/baz.js' + }); + assert.equal(pos.line, 4); + assert.equal(pos.column, 4); + }; +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-map-generator.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-map-generator.js new file mode 100644 index 0000000..ba292f5 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-map-generator.js @@ -0,0 +1,417 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var SourceMapGenerator = require('../../lib/source-map/source-map-generator').SourceMapGenerator; + var SourceMapConsumer = require('../../lib/source-map/source-map-consumer').SourceMapConsumer; + var SourceNode = require('../../lib/source-map/source-node').SourceNode; + var util = require('./util'); + + exports['test some simple stuff'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'foo.js', + sourceRoot: '.' + }); + assert.ok(true); + }; + + exports['test JSON serialization'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'foo.js', + sourceRoot: '.' + }); + assert.equal(map.toString(), JSON.stringify(map)); + }; + + exports['test adding mappings (case 1)'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'generated-foo.js', + sourceRoot: '.' + }); + + assert.doesNotThrow(function () { + map.addMapping({ + generated: { line: 1, column: 1 } + }); + }); + }; + + exports['test adding mappings (case 2)'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'generated-foo.js', + sourceRoot: '.' + }); + + assert.doesNotThrow(function () { + map.addMapping({ + generated: { line: 1, column: 1 }, + source: 'bar.js', + original: { line: 1, column: 1 } + }); + }); + }; + + exports['test adding mappings (case 3)'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'generated-foo.js', + sourceRoot: '.' + }); + + assert.doesNotThrow(function () { + map.addMapping({ + generated: { line: 1, column: 1 }, + source: 'bar.js', + original: { line: 1, column: 1 }, + name: 'someToken' + }); + }); + }; + + exports['test adding mappings (invalid)'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'generated-foo.js', + sourceRoot: '.' + }); + + // Not enough info. + assert.throws(function () { + map.addMapping({}); + }); + + // Original file position, but no source. + assert.throws(function () { + map.addMapping({ + generated: { line: 1, column: 1 }, + original: { line: 1, column: 1 } + }); + }); + }; + + exports['test that the correct mappings are being generated'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'min.js', + sourceRoot: '/the/root' + }); + + map.addMapping({ + generated: { line: 1, column: 1 }, + original: { line: 1, column: 1 }, + source: 'one.js' + }); + map.addMapping({ + generated: { line: 1, column: 5 }, + original: { line: 1, column: 5 }, + source: 'one.js' + }); + map.addMapping({ + generated: { line: 1, column: 9 }, + original: { line: 1, column: 11 }, + source: 'one.js' + }); + map.addMapping({ + generated: { line: 1, column: 18 }, + original: { line: 1, column: 21 }, + source: 'one.js', + name: 'bar' + }); + map.addMapping({ + generated: { line: 1, column: 21 }, + original: { line: 2, column: 3 }, + source: 'one.js' + }); + map.addMapping({ + generated: { line: 1, column: 28 }, + original: { line: 2, column: 10 }, + source: 'one.js', + name: 'baz' + }); + map.addMapping({ + generated: { line: 1, column: 32 }, + original: { line: 2, column: 14 }, + source: 'one.js', + name: 'bar' + }); + + map.addMapping({ + generated: { line: 2, column: 1 }, + original: { line: 1, column: 1 }, + source: 'two.js' + }); + map.addMapping({ + generated: { line: 2, column: 5 }, + original: { line: 1, column: 5 }, + source: 'two.js' + }); + map.addMapping({ + generated: { line: 2, column: 9 }, + original: { line: 1, column: 11 }, + source: 'two.js' + }); + map.addMapping({ + generated: { line: 2, column: 18 }, + original: { line: 1, column: 21 }, + source: 'two.js', + name: 'n' + }); + map.addMapping({ + generated: { line: 2, column: 21 }, + original: { line: 2, column: 3 }, + source: 'two.js' + }); + map.addMapping({ + generated: { line: 2, column: 28 }, + original: { line: 2, column: 10 }, + source: 'two.js', + name: 'n' + }); + + map = JSON.parse(map.toString()); + + util.assertEqualMaps(assert, map, util.testMap); + }; + + exports['test that source content can be set'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'min.js', + sourceRoot: '/the/root' + }); + map.addMapping({ + generated: { line: 1, column: 1 }, + original: { line: 1, column: 1 }, + source: 'one.js' + }); + map.addMapping({ + generated: { line: 2, column: 1 }, + original: { line: 1, column: 1 }, + source: 'two.js' + }); + map.setSourceContent('one.js', 'one file content'); + + map = JSON.parse(map.toString()); + assert.equal(map.sources[0], 'one.js'); + assert.equal(map.sources[1], 'two.js'); + assert.equal(map.sourcesContent[0], 'one file content'); + assert.equal(map.sourcesContent[1], null); + }; + + exports['test .fromSourceMap'] = function (assert, util) { + var map = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(util.testMap)); + util.assertEqualMaps(assert, map.toJSON(), util.testMap); + }; + + exports['test .fromSourceMap with sourcesContent'] = function (assert, util) { + var map = SourceMapGenerator.fromSourceMap( + new SourceMapConsumer(util.testMapWithSourcesContent)); + util.assertEqualMaps(assert, map.toJSON(), util.testMapWithSourcesContent); + }; + + exports['test applySourceMap'] = function (assert, util) { + var node = new SourceNode(null, null, null, [ + new SourceNode(2, 0, 'fileX', 'lineX2\n'), + 'genA1\n', + new SourceNode(2, 0, 'fileY', 'lineY2\n'), + 'genA2\n', + new SourceNode(1, 0, 'fileX', 'lineX1\n'), + 'genA3\n', + new SourceNode(1, 0, 'fileY', 'lineY1\n') + ]); + var mapStep1 = node.toStringWithSourceMap({ + file: 'fileA' + }).map; + mapStep1.setSourceContent('fileX', 'lineX1\nlineX2\n'); + mapStep1 = mapStep1.toJSON(); + + node = new SourceNode(null, null, null, [ + 'gen1\n', + new SourceNode(1, 0, 'fileA', 'lineA1\n'), + new SourceNode(2, 0, 'fileA', 'lineA2\n'), + new SourceNode(3, 0, 'fileA', 'lineA3\n'), + new SourceNode(4, 0, 'fileA', 'lineA4\n'), + new SourceNode(1, 0, 'fileB', 'lineB1\n'), + new SourceNode(2, 0, 'fileB', 'lineB2\n'), + 'gen2\n' + ]); + var mapStep2 = node.toStringWithSourceMap({ + file: 'fileGen' + }).map; + mapStep2.setSourceContent('fileB', 'lineB1\nlineB2\n'); + mapStep2 = mapStep2.toJSON(); + + node = new SourceNode(null, null, null, [ + 'gen1\n', + new SourceNode(2, 0, 'fileX', 'lineA1\n'), + new SourceNode(2, 0, 'fileA', 'lineA2\n'), + new SourceNode(2, 0, 'fileY', 'lineA3\n'), + new SourceNode(4, 0, 'fileA', 'lineA4\n'), + new SourceNode(1, 0, 'fileB', 'lineB1\n'), + new SourceNode(2, 0, 'fileB', 'lineB2\n'), + 'gen2\n' + ]); + var expectedMap = node.toStringWithSourceMap({ + file: 'fileGen' + }).map; + expectedMap.setSourceContent('fileX', 'lineX1\nlineX2\n'); + expectedMap.setSourceContent('fileB', 'lineB1\nlineB2\n'); + expectedMap = expectedMap.toJSON(); + + // apply source map "mapStep1" to "mapStep2" + var generator = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(mapStep2)); + generator.applySourceMap(new SourceMapConsumer(mapStep1)); + var actualMap = generator.toJSON(); + + util.assertEqualMaps(assert, actualMap, expectedMap); + }; + + exports['test sorting with duplicate generated mappings'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'test.js' + }); + map.addMapping({ + generated: { line: 3, column: 0 }, + original: { line: 2, column: 0 }, + source: 'a.js' + }); + map.addMapping({ + generated: { line: 2, column: 0 } + }); + map.addMapping({ + generated: { line: 2, column: 0 } + }); + map.addMapping({ + generated: { line: 1, column: 0 }, + original: { line: 1, column: 0 }, + source: 'a.js' + }); + + util.assertEqualMaps(assert, map.toJSON(), { + version: 3, + file: 'test.js', + sources: ['a.js'], + names: [], + mappings: 'AAAA;A;AACA' + }); + }; + + exports['test ignore duplicate mappings.'] = function (assert, util) { + var init = { file: 'min.js', sourceRoot: '/the/root' }; + var map1, map2; + + // null original source location + var nullMapping1 = { + generated: { line: 1, column: 0 } + }; + var nullMapping2 = { + generated: { line: 2, column: 2 } + }; + + map1 = new SourceMapGenerator(init); + map2 = new SourceMapGenerator(init); + + map1.addMapping(nullMapping1); + map1.addMapping(nullMapping1); + + map2.addMapping(nullMapping1); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + + map1.addMapping(nullMapping2); + map1.addMapping(nullMapping1); + + map2.addMapping(nullMapping2); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + + // original source location + var srcMapping1 = { + generated: { line: 1, column: 0 }, + original: { line: 11, column: 0 }, + source: 'srcMapping1.js' + }; + var srcMapping2 = { + generated: { line: 2, column: 2 }, + original: { line: 11, column: 0 }, + source: 'srcMapping2.js' + }; + + map1 = new SourceMapGenerator(init); + map2 = new SourceMapGenerator(init); + + map1.addMapping(srcMapping1); + map1.addMapping(srcMapping1); + + map2.addMapping(srcMapping1); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + + map1.addMapping(srcMapping2); + map1.addMapping(srcMapping1); + + map2.addMapping(srcMapping2); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + + // full original source and name information + var fullMapping1 = { + generated: { line: 1, column: 0 }, + original: { line: 11, column: 0 }, + source: 'fullMapping1.js', + name: 'fullMapping1' + }; + var fullMapping2 = { + generated: { line: 2, column: 2 }, + original: { line: 11, column: 0 }, + source: 'fullMapping2.js', + name: 'fullMapping2' + }; + + map1 = new SourceMapGenerator(init); + map2 = new SourceMapGenerator(init); + + map1.addMapping(fullMapping1); + map1.addMapping(fullMapping1); + + map2.addMapping(fullMapping1); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + + map1.addMapping(fullMapping2); + map1.addMapping(fullMapping1); + + map2.addMapping(fullMapping2); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + }; + + exports['test github issue #72, check for duplicate names or sources'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'test.js' + }); + map.addMapping({ + generated: { line: 1, column: 1 }, + original: { line: 2, column: 2 }, + source: 'a.js', + name: 'foo' + }); + map.addMapping({ + generated: { line: 3, column: 3 }, + original: { line: 4, column: 4 }, + source: 'a.js', + name: 'foo' + }); + util.assertEqualMaps(assert, map.toJSON(), { + version: 3, + file: 'test.js', + sources: ['a.js'], + names: ['foo'], + mappings: 'CACEA;;GAEEA' + }); + }; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-node.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-node.js new file mode 100644 index 0000000..6e0eca8 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/test-source-node.js @@ -0,0 +1,365 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var SourceMapGenerator = require('../../lib/source-map/source-map-generator').SourceMapGenerator; + var SourceMapConsumer = require('../../lib/source-map/source-map-consumer').SourceMapConsumer; + var SourceNode = require('../../lib/source-map/source-node').SourceNode; + + exports['test .add()'] = function (assert, util) { + var node = new SourceNode(null, null, null); + + // Adding a string works. + node.add('function noop() {}'); + + // Adding another source node works. + node.add(new SourceNode(null, null, null)); + + // Adding an array works. + node.add(['function foo() {', + new SourceNode(null, null, null, + 'return 10;'), + '}']); + + // Adding other stuff doesn't. + assert.throws(function () { + node.add({}); + }); + assert.throws(function () { + node.add(function () {}); + }); + }; + + exports['test .prepend()'] = function (assert, util) { + var node = new SourceNode(null, null, null); + + // Prepending a string works. + node.prepend('function noop() {}'); + assert.equal(node.children[0], 'function noop() {}'); + assert.equal(node.children.length, 1); + + // Prepending another source node works. + node.prepend(new SourceNode(null, null, null)); + assert.equal(node.children[0], ''); + assert.equal(node.children[1], 'function noop() {}'); + assert.equal(node.children.length, 2); + + // Prepending an array works. + node.prepend(['function foo() {', + new SourceNode(null, null, null, + 'return 10;'), + '}']); + assert.equal(node.children[0], 'function foo() {'); + assert.equal(node.children[1], 'return 10;'); + assert.equal(node.children[2], '}'); + assert.equal(node.children[3], ''); + assert.equal(node.children[4], 'function noop() {}'); + assert.equal(node.children.length, 5); + + // Prepending other stuff doesn't. + assert.throws(function () { + node.prepend({}); + }); + assert.throws(function () { + node.prepend(function () {}); + }); + }; + + exports['test .toString()'] = function (assert, util) { + assert.equal((new SourceNode(null, null, null, + ['function foo() {', + new SourceNode(null, null, null, 'return 10;'), + '}'])).toString(), + 'function foo() {return 10;}'); + }; + + exports['test .join()'] = function (assert, util) { + assert.equal((new SourceNode(null, null, null, + ['a', 'b', 'c', 'd'])).join(', ').toString(), + 'a, b, c, d'); + }; + + exports['test .walk()'] = function (assert, util) { + var node = new SourceNode(null, null, null, + ['(function () {\n', + ' ', new SourceNode(1, 0, 'a.js', ['someCall()']), ';\n', + ' ', new SourceNode(2, 0, 'b.js', ['if (foo) bar()']), ';\n', + '}());']); + var expected = [ + { str: '(function () {\n', source: null, line: null, column: null }, + { str: ' ', source: null, line: null, column: null }, + { str: 'someCall()', source: 'a.js', line: 1, column: 0 }, + { str: ';\n', source: null, line: null, column: null }, + { str: ' ', source: null, line: null, column: null }, + { str: 'if (foo) bar()', source: 'b.js', line: 2, column: 0 }, + { str: ';\n', source: null, line: null, column: null }, + { str: '}());', source: null, line: null, column: null }, + ]; + var i = 0; + node.walk(function (chunk, loc) { + assert.equal(expected[i].str, chunk); + assert.equal(expected[i].source, loc.source); + assert.equal(expected[i].line, loc.line); + assert.equal(expected[i].column, loc.column); + i++; + }); + }; + + exports['test .replaceRight'] = function (assert, util) { + var node; + + // Not nested + node = new SourceNode(null, null, null, 'hello world'); + node.replaceRight(/world/, 'universe'); + assert.equal(node.toString(), 'hello universe'); + + // Nested + node = new SourceNode(null, null, null, + [new SourceNode(null, null, null, 'hey sexy mama, '), + new SourceNode(null, null, null, 'want to kill all humans?')]); + node.replaceRight(/kill all humans/, 'watch Futurama'); + assert.equal(node.toString(), 'hey sexy mama, want to watch Futurama?'); + }; + + exports['test .toStringWithSourceMap()'] = function (assert, util) { + var node = new SourceNode(null, null, null, + ['(function () {\n', + ' ', + new SourceNode(1, 0, 'a.js', 'someCall', 'originalCall'), + new SourceNode(1, 8, 'a.js', '()'), + ';\n', + ' ', new SourceNode(2, 0, 'b.js', ['if (foo) bar()']), ';\n', + '}());']); + var map = node.toStringWithSourceMap({ + file: 'foo.js' + }).map; + + assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator'); + map = new SourceMapConsumer(map.toString()); + + var actual; + + actual = map.originalPositionFor({ + line: 1, + column: 4 + }); + assert.equal(actual.source, null); + assert.equal(actual.line, null); + assert.equal(actual.column, null); + + actual = map.originalPositionFor({ + line: 2, + column: 2 + }); + assert.equal(actual.source, 'a.js'); + assert.equal(actual.line, 1); + assert.equal(actual.column, 0); + assert.equal(actual.name, 'originalCall'); + + actual = map.originalPositionFor({ + line: 3, + column: 2 + }); + assert.equal(actual.source, 'b.js'); + assert.equal(actual.line, 2); + assert.equal(actual.column, 0); + + actual = map.originalPositionFor({ + line: 3, + column: 16 + }); + assert.equal(actual.source, null); + assert.equal(actual.line, null); + assert.equal(actual.column, null); + + actual = map.originalPositionFor({ + line: 4, + column: 2 + }); + assert.equal(actual.source, null); + assert.equal(actual.line, null); + assert.equal(actual.column, null); + }; + + exports['test .fromStringWithSourceMap()'] = function (assert, util) { + var node = SourceNode.fromStringWithSourceMap( + util.testGeneratedCode, + new SourceMapConsumer(util.testMap)); + + var result = node.toStringWithSourceMap({ + file: 'min.js' + }); + var map = result.map; + var code = result.code; + + assert.equal(code, util.testGeneratedCode); + assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator'); + map = map.toJSON(); + assert.equal(map.version, util.testMap.version); + assert.equal(map.file, util.testMap.file); + assert.equal(map.mappings, util.testMap.mappings); + }; + + exports['test .fromStringWithSourceMap() empty map'] = function (assert, util) { + var node = SourceNode.fromStringWithSourceMap( + util.testGeneratedCode, + new SourceMapConsumer(util.emptyMap)); + var result = node.toStringWithSourceMap({ + file: 'min.js' + }); + var map = result.map; + var code = result.code; + + assert.equal(code, util.testGeneratedCode); + assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator'); + map = map.toJSON(); + assert.equal(map.version, util.emptyMap.version); + assert.equal(map.file, util.emptyMap.file); + assert.equal(map.mappings.length, util.emptyMap.mappings.length); + assert.equal(map.mappings, util.emptyMap.mappings); + }; + + exports['test .fromStringWithSourceMap() complex version'] = function (assert, util) { + var input = new SourceNode(null, null, null, [ + "(function() {\n", + " var Test = {};\n", + " ", new SourceNode(1, 0, "a.js", "Test.A = { value: 1234 };\n"), + " ", new SourceNode(2, 0, "a.js", "Test.A.x = 'xyz';"), "\n", + "}());\n", + "/* Generated Source */"]); + input = input.toStringWithSourceMap({ + file: 'foo.js' + }); + + var node = SourceNode.fromStringWithSourceMap( + input.code, + new SourceMapConsumer(input.map.toString())); + + var result = node.toStringWithSourceMap({ + file: 'foo.js' + }); + var map = result.map; + var code = result.code; + + assert.equal(code, input.code); + assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator'); + map = map.toJSON(); + var inputMap = input.map.toJSON(); + util.assertEqualMaps(assert, map, inputMap); + }; + + exports['test .fromStringWithSourceMap() merging duplicate mappings'] = function (assert, util) { + var input = new SourceNode(null, null, null, [ + new SourceNode(1, 0, "a.js", "(function"), + new SourceNode(1, 0, "a.js", "() {\n"), + " ", + new SourceNode(1, 0, "a.js", "var Test = "), + new SourceNode(1, 0, "b.js", "{};\n"), + new SourceNode(2, 0, "b.js", "Test"), + new SourceNode(2, 0, "b.js", ".A", "A"), + new SourceNode(2, 20, "b.js", " = { value: 1234 };\n", "A"), + "}());\n", + "/* Generated Source */" + ]); + input = input.toStringWithSourceMap({ + file: 'foo.js' + }); + + var correctMap = new SourceMapGenerator({ + file: 'foo.js' + }); + correctMap.addMapping({ + generated: { line: 1, column: 0 }, + source: 'a.js', + original: { line: 1, column: 0 } + }); + correctMap.addMapping({ + generated: { line: 2, column: 0 } + }); + correctMap.addMapping({ + generated: { line: 2, column: 2 }, + source: 'a.js', + original: { line: 1, column: 0 } + }); + correctMap.addMapping({ + generated: { line: 2, column: 13 }, + source: 'b.js', + original: { line: 1, column: 0 } + }); + correctMap.addMapping({ + generated: { line: 3, column: 0 }, + source: 'b.js', + original: { line: 2, column: 0 } + }); + correctMap.addMapping({ + generated: { line: 3, column: 4 }, + source: 'b.js', + name: 'A', + original: { line: 2, column: 0 } + }); + correctMap.addMapping({ + generated: { line: 3, column: 6 }, + source: 'b.js', + name: 'A', + original: { line: 2, column: 20 } + }); + correctMap.addMapping({ + generated: { line: 4, column: 0 } + }); + + var inputMap = input.map.toJSON(); + correctMap = correctMap.toJSON(); + util.assertEqualMaps(assert, correctMap, inputMap); + }; + + exports['test setSourceContent with toStringWithSourceMap'] = function (assert, util) { + var aNode = new SourceNode(1, 1, 'a.js', 'a'); + aNode.setSourceContent('a.js', 'someContent'); + var node = new SourceNode(null, null, null, + ['(function () {\n', + ' ', aNode, + ' ', new SourceNode(1, 1, 'b.js', 'b'), + '}());']); + node.setSourceContent('b.js', 'otherContent'); + var map = node.toStringWithSourceMap({ + file: 'foo.js' + }).map; + + assert.ok(map instanceof SourceMapGenerator, 'map instanceof SourceMapGenerator'); + map = new SourceMapConsumer(map.toString()); + + assert.equal(map.sources.length, 2); + assert.equal(map.sources[0], 'a.js'); + assert.equal(map.sources[1], 'b.js'); + assert.equal(map.sourcesContent.length, 2); + assert.equal(map.sourcesContent[0], 'someContent'); + assert.equal(map.sourcesContent[1], 'otherContent'); + }; + + exports['test walkSourceContents'] = function (assert, util) { + var aNode = new SourceNode(1, 1, 'a.js', 'a'); + aNode.setSourceContent('a.js', 'someContent'); + var node = new SourceNode(null, null, null, + ['(function () {\n', + ' ', aNode, + ' ', new SourceNode(1, 1, 'b.js', 'b'), + '}());']); + node.setSourceContent('b.js', 'otherContent'); + var results = []; + node.walkSourceContents(function (sourceFile, sourceContent) { + results.push([sourceFile, sourceContent]); + }); + assert.equal(results.length, 2); + assert.equal(results[0][0], 'a.js'); + assert.equal(results[0][1], 'someContent'); + assert.equal(results[1][0], 'b.js'); + assert.equal(results[1][1], 'otherContent'); + }; +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/util.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/util.js new file mode 100644 index 0000000..288046b --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/source-map/test/source-map/util.js @@ -0,0 +1,161 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +if (typeof define !== 'function') { + var define = require('amdefine')(module, require); +} +define(function (require, exports, module) { + + var util = require('../../lib/source-map/util'); + + // This is a test mapping which maps functions from two different files + // (one.js and two.js) to a minified generated source. + // + // Here is one.js: + // + // ONE.foo = function (bar) { + // return baz(bar); + // }; + // + // Here is two.js: + // + // TWO.inc = function (n) { + // return n + 1; + // }; + // + // And here is the generated code (min.js): + // + // ONE.foo=function(a){return baz(a);}; + // TWO.inc=function(a){return a+1;}; + exports.testGeneratedCode = " ONE.foo=function(a){return baz(a);};\n"+ + " TWO.inc=function(a){return a+1;};"; + exports.testMap = { + version: 3, + file: 'min.js', + names: ['bar', 'baz', 'n'], + sources: ['one.js', 'two.js'], + sourceRoot: '/the/root', + mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA' + }; + exports.testMapWithSourcesContent = { + version: 3, + file: 'min.js', + names: ['bar', 'baz', 'n'], + sources: ['one.js', 'two.js'], + sourcesContent: [ + ' ONE.foo = function (bar) {\n' + + ' return baz(bar);\n' + + ' };', + ' TWO.inc = function (n) {\n' + + ' return n + 1;\n' + + ' };' + ], + sourceRoot: '/the/root', + mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA' + }; + exports.emptyMap = { + version: 3, + file: 'min.js', + names: [], + sources: [], + mappings: '' + }; + + + function assertMapping(generatedLine, generatedColumn, originalSource, + originalLine, originalColumn, name, map, assert, + dontTestGenerated, dontTestOriginal) { + if (!dontTestOriginal) { + var origMapping = map.originalPositionFor({ + line: generatedLine, + column: generatedColumn + }); + assert.equal(origMapping.name, name, + 'Incorrect name, expected ' + JSON.stringify(name) + + ', got ' + JSON.stringify(origMapping.name)); + assert.equal(origMapping.line, originalLine, + 'Incorrect line, expected ' + JSON.stringify(originalLine) + + ', got ' + JSON.stringify(origMapping.line)); + assert.equal(origMapping.column, originalColumn, + 'Incorrect column, expected ' + JSON.stringify(originalColumn) + + ', got ' + JSON.stringify(origMapping.column)); + + var expectedSource; + + if (originalSource && map.sourceRoot && originalSource.indexOf(map.sourceRoot) === 0) { + expectedSource = originalSource; + } else if (originalSource) { + expectedSource = map.sourceRoot + ? util.join(map.sourceRoot, originalSource) + : originalSource; + } else { + expectedSource = null; + } + + assert.equal(origMapping.source, expectedSource, + 'Incorrect source, expected ' + JSON.stringify(expectedSource) + + ', got ' + JSON.stringify(origMapping.source)); + } + + if (!dontTestGenerated) { + var genMapping = map.generatedPositionFor({ + source: originalSource, + line: originalLine, + column: originalColumn + }); + assert.equal(genMapping.line, generatedLine, + 'Incorrect line, expected ' + JSON.stringify(generatedLine) + + ', got ' + JSON.stringify(genMapping.line)); + assert.equal(genMapping.column, generatedColumn, + 'Incorrect column, expected ' + JSON.stringify(generatedColumn) + + ', got ' + JSON.stringify(genMapping.column)); + } + } + exports.assertMapping = assertMapping; + + function assertEqualMaps(assert, actualMap, expectedMap) { + assert.equal(actualMap.version, expectedMap.version, "version mismatch"); + assert.equal(actualMap.file, expectedMap.file, "file mismatch"); + assert.equal(actualMap.names.length, + expectedMap.names.length, + "names length mismatch: " + + actualMap.names.join(", ") + " != " + expectedMap.names.join(", ")); + for (var i = 0; i < actualMap.names.length; i++) { + assert.equal(actualMap.names[i], + expectedMap.names[i], + "names[" + i + "] mismatch: " + + actualMap.names.join(", ") + " != " + expectedMap.names.join(", ")); + } + assert.equal(actualMap.sources.length, + expectedMap.sources.length, + "sources length mismatch: " + + actualMap.sources.join(", ") + " != " + expectedMap.sources.join(", ")); + for (var i = 0; i < actualMap.sources.length; i++) { + assert.equal(actualMap.sources[i], + expectedMap.sources[i], + "sources[" + i + "] length mismatch: " + + actualMap.sources.join(", ") + " != " + expectedMap.sources.join(", ")); + } + assert.equal(actualMap.sourceRoot, + expectedMap.sourceRoot, + "sourceRoot mismatch: " + + actualMap.sourceRoot + " != " + expectedMap.sourceRoot); + assert.equal(actualMap.mappings, expectedMap.mappings, + "mappings mismatch:\nActual: " + actualMap.mappings + "\nExpected: " + expectedMap.mappings); + if (actualMap.sourcesContent) { + assert.equal(actualMap.sourcesContent.length, + expectedMap.sourcesContent.length, + "sourcesContent length mismatch"); + for (var i = 0; i < actualMap.sourcesContent.length; i++) { + assert.equal(actualMap.sourcesContent[i], + expectedMap.sourcesContent[i], + "sourcesContent[" + i + "] mismatch"); + } + } + } + exports.assertEqualMaps = assertEqualMaps; + +}); diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/.npmignore b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/.npmignore new file mode 100644 index 0000000..3e56974 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/.npmignore @@ -0,0 +1,14 @@ +lib-cov +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.gz +pids +logs +results +npm-debug.log +node_modules +/test/output.js diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/.travis.yml b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/.travis.yml new file mode 100644 index 0000000..9a61f6b --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/.travis.yml @@ -0,0 +1,3 @@ +language: node_js +node_js: + - "0.10" \ No newline at end of file diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/LICENSE b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/LICENSE new file mode 100644 index 0000000..dfb0b19 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013 Forbes Lindesay + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/README.md b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/README.md new file mode 100644 index 0000000..99685da --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/README.md @@ -0,0 +1,15 @@ +# uglify-to-browserify + +A transform to make UglifyJS work in browserify. + +[![Build Status](https://travis-ci.org/ForbesLindesay/uglify-to-browserify.png?branch=master)](https://travis-ci.org/ForbesLindesay/uglify-to-browserify) +[![Dependency Status](https://gemnasium.com/ForbesLindesay/uglify-to-browserify.png)](https://gemnasium.com/ForbesLindesay/uglify-to-browserify) +[![NPM version](https://badge.fury.io/js/uglify-to-browserify.png)](http://badge.fury.io/js/uglify-to-browserify) + +## Installation + + npm install uglify-to-browserify + +## License + + MIT \ No newline at end of file diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/index.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/index.js new file mode 100644 index 0000000..11cb627 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/index.js @@ -0,0 +1,46 @@ +'use strict' + +var fs = require('fs') +var PassThrough = require('stream').PassThrough +var Transform = require('stream').Transform + +if (typeof Transform === 'undefined') { + throw new Error('UglifyJS only supports browserify when using node >= 0.10.x') +} + +var cache = {} +module.exports = transform +function transform(file) { + if (!/tools\/node\.js$/.test(file.replace(/\\/g,'/'))) return new PassThrough(); + if (cache[file]) return makeStream(cache[file]) + var uglify = require(file) + var src = 'var sys = require("util");\nvar MOZ_SourceMap = require("source-map");\nvar UglifyJS = exports;\n' + uglify.FILES.map(function (path) { return fs.readFileSync(path, 'utf8') }).join('\n') + + var ast = uglify.parse(src) + ast.figure_out_scope() + + var variables = ast.variables + .map(function (node, name) { + return name + }) + + src += '\n\n' + variables.map(function (v) { return 'exports.' + v + ' = ' + v + ';' }).join('\n') + '\n\n' + + src += 'exports.AST_Node.warn_function = function (txt) { if (typeof console != "undefined" && typeof console.warn === "function") console.warn(txt) }\n\n' + + src += 'exports.minify = ' + uglify.minify.toString() + ';\n\n' + src += 'exports.describe_ast = ' + uglify.describe_ast.toString() + ';' + + cache[file] = src + return makeStream(src); +} + +function makeStream(src) { + var res = new Transform(); + res._transform = function (chunk, encoding, callback) { callback() } + res._flush = function (callback) { + res.push(src) + callback() + } + return res; +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/package.json b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/package.json new file mode 100644 index 0000000..803cec8 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/package.json @@ -0,0 +1,33 @@ +{ + "name": "uglify-to-browserify", + "version": "1.0.1", + "description": "A transform to make UglifyJS work in browserify.", + "keywords": [], + "dependencies": {}, + "devDependencies": { + "uglify-js": "~2.4.0", + "source-map": "~0.1.27" + }, + "scripts": { + "test": "node test/index.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/ForbesLindesay/uglify-to-browserify.git" + }, + "author": { + "name": "ForbesLindesay" + }, + "license": "MIT", + "readme": "# uglify-to-browserify\r\n\r\nA transform to make UglifyJS work in browserify.\r\n\r\n[![Build Status](https://travis-ci.org/ForbesLindesay/uglify-to-browserify.png?branch=master)](https://travis-ci.org/ForbesLindesay/uglify-to-browserify)\r\n[![Dependency Status](https://gemnasium.com/ForbesLindesay/uglify-to-browserify.png)](https://gemnasium.com/ForbesLindesay/uglify-to-browserify)\r\n[![NPM version](https://badge.fury.io/js/uglify-to-browserify.png)](http://badge.fury.io/js/uglify-to-browserify)\r\n\r\n## Installation\r\n\r\n npm install uglify-to-browserify\r\n\r\n## License\r\n\r\n MIT", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/ForbesLindesay/uglify-to-browserify/issues" + }, + "_id": "uglify-to-browserify@1.0.1", + "dist": { + "shasum": "7e977b388edca6d77e667939b1956d180bcdfc8e" + }, + "_from": "uglify-to-browserify@~1.0.0", + "_resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.1.tgz" +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/test/index.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/test/index.js new file mode 100644 index 0000000..4117894 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/node_modules/uglify-to-browserify/test/index.js @@ -0,0 +1,22 @@ +var fs = require('fs') +var br = require('../') +var test = fs.readFileSync(require.resolve('uglify-js/test/run-tests.js'), 'utf8') + .replace(/^#.*\n/, '') + +var transform = br(require.resolve('uglify-js')) +transform.pipe(fs.createWriteStream(__dirname + '/output.js')) + .on('close', function () { + Function('module,require', test)({ + filename: require.resolve('uglify-js/test/run-tests.js') + }, + function (name) { + if (name === '../tools/node') { + return require('./output.js') + } else if (/^[a-z]+$/.test(name)) { + return require(name) + } else { + throw new Error('I didn\'t expect you to require ' + name) + } + }) + }) +transform.end(fs.readFileSync(require.resolve('uglify-js'), 'utf8')) \ No newline at end of file diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/package.json b/node_modules/jade/node_modules/with/node_modules/uglify-js/package.json new file mode 100644 index 0000000..80a97c1 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/package.json @@ -0,0 +1,49 @@ +{ + "name": "uglify-js", + "description": "JavaScript parser, mangler/compressor and beautifier toolkit", + "homepage": "http://lisperator.net/uglifyjs", + "main": "tools/node.js", + "version": "2.4.0", + "engines": { + "node": ">=0.4.0" + }, + "maintainers": [ + { + "name": "Mihai Bazon", + "email": "mihai.bazon@gmail.com", + "url": "http://lisperator.net/" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/mishoo/UglifyJS2.git" + }, + "dependencies": { + "async": "~0.2.6", + "source-map": "~0.1.7", + "optimist": "~0.3.5", + "uglify-to-browserify": "~1.0.0" + }, + "browserify": { + "transform": [ + "uglify-to-browserify" + ] + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "scripts": { + "test": "node test/run-tests.js" + }, + "readme": "UglifyJS 2\n==========\n[![Build Status](https://travis-ci.org/mishoo/UglifyJS2.png)](https://travis-ci.org/mishoo/UglifyJS2)\n\nUglifyJS is a JavaScript parser, minifier, compressor or beautifier toolkit.\n\nThis page documents the command line utility. For\n[API and internals documentation see my website](http://lisperator.net/uglifyjs/).\nThere's also an\n[in-browser online demo](http://lisperator.net/uglifyjs/#demo) (for Firefox,\nChrome and probably Safari).\n\nInstall\n-------\n\nFirst make sure you have installed the latest version of [node.js](http://nodejs.org/)\n(You may need to restart your computer after this step).\n\nFrom NPM for use as a command line app:\n\n npm install uglify-js -g\n\nFrom NPM for programmatic use:\n\n npm install uglify-js\n\nFrom Git:\n\n git clone git://github.com/mishoo/UglifyJS2.git\n cd UglifyJS2\n npm link .\n\nUsage\n-----\n\n uglifyjs [input files] [options]\n\nUglifyJS2 can take multiple input files. It's recommended that you pass the\ninput files first, then pass the options. UglifyJS will parse input files\nin sequence and apply any compression options. The files are parsed in the\nsame global scope, that is, a reference from a file to some\nvariable/function declared in another file will be matched properly.\n\nIf you want to read from STDIN instead, pass a single dash instead of input\nfiles.\n\nThe available options are:\n\n```\n --source-map Specify an output file where to generate source map.\n [string]\n --source-map-root The path to the original source to be included in the\n source map. [string]\n --source-map-url The path to the source map to be added in //#\n sourceMappingURL. Defaults to the value passed with\n --source-map. [string]\n --in-source-map Input source map, useful if you're compressing JS that was\n generated from some other original code.\n --screw-ie8 Pass this flag if you don't care about full compliance\n with Internet Explorer 6-8 quirks (by default UglifyJS\n will try to be IE-proof). [boolean]\n --expr Parse a single expression, rather than a program (for\n parsing JSON) [boolean]\n -p, --prefix Skip prefix for original filenames that appear in source\n maps. For example -p 3 will drop 3 directories from file\n names and ensure they are relative paths. You can also\n specify -p relative, which will make UglifyJS figure out\n itself the relative paths between original sources, the\n source map and the output file. [string]\n -o, --output Output file (default STDOUT).\n -b, --beautify Beautify output/specify output options. [string]\n -m, --mangle Mangle names/pass mangler options. [string]\n -r, --reserved Reserved names to exclude from mangling.\n -c, --compress Enable compressor/pass compressor options. Pass options\n like -c hoist_vars=false,if_return=false. Use -c with no\n argument to use the default compression options. [string]\n -d, --define Global definitions [string]\n -e, --enclose Embed everything in a big function, with a configurable\n parameter/argument list. [string]\n --comments Preserve copyright comments in the output. By default this\n works like Google Closure, keeping JSDoc-style comments\n that contain \"@license\" or \"@preserve\". You can optionally\n pass one of the following arguments to this flag:\n - \"all\" to keep all comments\n - a valid JS regexp (needs to start with a slash) to keep\n only comments that match.\n Note that currently not *all* comments can be kept when\n compression is on, because of dead code removal or\n cascading statements into sequences. [string]\n --stats Display operations run time on STDERR. [boolean]\n --acorn Use Acorn for parsing. [boolean]\n --spidermonkey Assume input files are SpiderMonkey AST format (as JSON).\n [boolean]\n --self Build itself (UglifyJS2) as a library (implies\n --wrap=UglifyJS --export-all) [boolean]\n --wrap Embed everything in a big function, making the “exports”\n and “global” variables available. You need to pass an\n argument to this option to specify the name that your\n module will take when included in, say, a browser.\n [string]\n --export-all Only used when --wrap, this tells UglifyJS to add code to\n automatically export all globals. [boolean]\n --lint Display some scope warnings [boolean]\n -v, --verbose Verbose [boolean]\n -V, --version Print version number and exit. [boolean]\n```\n\nSpecify `--output` (`-o`) to declare the output file. Otherwise the output\ngoes to STDOUT.\n\n## Source map options\n\nUglifyJS2 can generate a source map file, which is highly useful for\ndebugging your compressed JavaScript. To get a source map, pass\n`--source-map output.js.map` (full path to the file where you want the\nsource map dumped).\n\nAdditionally you might need `--source-map-root` to pass the URL where the\noriginal files can be found. In case you are passing full paths to input\nfiles to UglifyJS, you can use `--prefix` (`-p`) to specify the number of\ndirectories to drop from the path prefix when declaring files in the source\nmap.\n\nFor example:\n\n uglifyjs /home/doe/work/foo/src/js/file1.js \\\n /home/doe/work/foo/src/js/file2.js \\\n -o foo.min.js \\\n --source-map foo.min.js.map \\\n --source-map-root http://foo.com/src \\\n -p 5 -c -m\n\nThe above will compress and mangle `file1.js` and `file2.js`, will drop the\noutput in `foo.min.js` and the source map in `foo.min.js.map`. The source\nmapping will refer to `http://foo.com/src/js/file1.js` and\n`http://foo.com/src/js/file2.js` (in fact it will list `http://foo.com/src`\nas the source map root, and the original files as `js/file1.js` and\n`js/file2.js`).\n\n### Composed source map\n\nWhen you're compressing JS code that was output by a compiler such as\nCoffeeScript, mapping to the JS code won't be too helpful. Instead, you'd\nlike to map back to the original code (i.e. CoffeeScript). UglifyJS has an\noption to take an input source map. Assuming you have a mapping from\nCoffeeScript → compiled JS, UglifyJS can generate a map from CoffeeScript →\ncompressed JS by mapping every token in the compiled JS to its original\nlocation.\n\nTo use this feature you need to pass `--in-source-map\n/path/to/input/source.map`. Normally the input source map should also point\nto the file containing the generated JS, so if that's correct you can omit\ninput files from the command line.\n\n## Mangler options\n\nTo enable the mangler you need to pass `--mangle` (`-m`). The following\n(comma-separated) options are supported:\n\n- `sort` — to assign shorter names to most frequently used variables. This\n saves a few hundred bytes on jQuery before gzip, but the output is\n _bigger_ after gzip (and seems to happen for other libraries I tried it\n on) therefore it's not enabled by default.\n\n- `toplevel` — mangle names declared in the toplevel scope (disabled by\n default).\n\n- `eval` — mangle names visible in scopes where `eval` or `when` are used\n (disabled by default).\n\nWhen mangling is enabled but you want to prevent certain names from being\nmangled, you can declare those names with `--reserved` (`-r`) — pass a\ncomma-separated list of names. For example:\n\n uglifyjs ... -m -r '$,require,exports'\n\nto prevent the `require`, `exports` and `$` names from being changed.\n\n## Compressor options\n\nYou need to pass `--compress` (`-c`) to enable the compressor. Optionally\nyou can pass a comma-separated list of options. Options are in the form\n`foo=bar`, or just `foo` (the latter implies a boolean option that you want\nto set `true`; it's effectively a shortcut for `foo=true`).\n\n- `sequences` -- join consecutive simple statements using the comma operator\n- `properties` -- rewrite property access using the dot notation, for\n example `foo[\"bar\"] → foo.bar`\n- `dead_code` -- remove unreachable code\n- `drop_debugger` -- remove `debugger;` statements\n- `unsafe` (default: false) -- apply \"unsafe\" transformations (discussion below)\n- `conditionals` -- apply optimizations for `if`-s and conditional\n expressions\n- `comparisons` -- apply certain optimizations to binary nodes, for example:\n `!(a <= b) → a > b` (only when `unsafe`), attempts to negate binary nodes,\n e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.\n- `evaluate` -- attempt to evaluate constant expressions\n- `booleans` -- various optimizations for boolean context, for example `!!a\n ? b : c → a ? b : c`\n- `loops` -- optimizations for `do`, `while` and `for` loops when we can\n statically determine the condition\n- `unused` -- drop unreferenced functions and variables\n- `hoist_funs` -- hoist function declarations\n- `hoist_vars` (default: false) -- hoist `var` declarations (this is `false`\n by default because it seems to increase the size of the output in general)\n- `if_return` -- optimizations for if/return and if/continue\n- `join_vars` -- join consecutive `var` statements\n- `cascade` -- small optimization for sequences, transform `x, x` into `x`\n and `x = something(), x` into `x = something()`\n- `warnings` -- display warnings when dropping unreachable code or unused\n declarations etc.\n- `negate_iife` -- negate \"Immediately-Called Function Expressions\"\n where the return value is discarded, to avoid the parens that the\n code generator would insert.\n\n### The `unsafe` option\n\nIt enables some transformations that *might* break code logic in certain\ncontrived cases, but should be fine for most code. You might want to try it\non your own code, it should reduce the minified size. Here's what happens\nwhen this flag is on:\n\n- `new Array(1, 2, 3)` or `Array(1, 2, 3)` → `[1, 2, 3 ]`\n- `new Object()` → `{}`\n- `String(exp)` or `exp.toString()` → `\"\" + exp`\n- `new Object/RegExp/Function/Error/Array (...)` → we discard the `new`\n- `typeof foo == \"undefined\"` → `foo === void 0`\n- `void 0` → `\"undefined\"` (if there is a variable named \"undefined\" in\n scope; we do it because the variable name will be mangled, typically\n reduced to a single character).\n\n### Conditional compilation\n\nYou can use the `--define` (`-d`) switch in order to declare global\nvariables that UglifyJS will assume to be constants (unless defined in\nscope). For example if you pass `--define DEBUG=false` then, coupled with\ndead code removal UglifyJS will discard the following from the output:\n```javascript\nif (DEBUG) {\n\tconsole.log(\"debug stuff\");\n}\n```\n\nUglifyJS will warn about the condition being always false and about dropping\nunreachable code; for now there is no option to turn off only this specific\nwarning, you can pass `warnings=false` to turn off *all* warnings.\n\nAnother way of doing that is to declare your globals as constants in a\nseparate file and include it into the build. For example you can have a\n`build/defines.js` file with the following:\n```javascript\nconst DEBUG = false;\nconst PRODUCTION = true;\n// etc.\n```\n\nand build your code like this:\n\n uglifyjs build/defines.js js/foo.js js/bar.js... -c\n\nUglifyJS will notice the constants and, since they cannot be altered, it\nwill evaluate references to them to the value itself and drop unreachable\ncode as usual. The possible downside of this approach is that the build\nwill contain the `const` declarations.\n\n\n## Beautifier options\n\nThe code generator tries to output shortest code possible by default. In\ncase you want beautified output, pass `--beautify` (`-b`). Optionally you\ncan pass additional arguments that control the code output:\n\n- `beautify` (default `true`) -- whether to actually beautify the output.\n Passing `-b` will set this to true, but you might need to pass `-b` even\n when you want to generate minified code, in order to specify additional\n arguments, so you can use `-b beautify=false` to override it.\n- `indent-level` (default 4)\n- `indent-start` (default 0) -- prefix all lines by that many spaces\n- `quote-keys` (default `false`) -- pass `true` to quote all keys in literal\n objects\n- `space-colon` (default `true`) -- insert a space after the colon signs\n- `ascii-only` (default `false`) -- escape Unicode characters in strings and\n regexps\n- `inline-script` (default `false`) -- escape the slash in occurrences of\n `= (x = f(…)) + * + * For example, let the equation be: + * (a = parseInt('100')) <= a + * + * If a was an integer and has the value of 99, + * (a = parseInt('100')) <= a → 100 <= 100 → true + * + * When transformed incorrectly: + * a >= (a = parseInt('100')) → 99 >= 100 → false + */ + +tranformation_sort_order_equal: { + options = { + comparisons: true, + }; + + input: { (a = parseInt('100')) == a } + expect: { (a = parseInt('100')) == a } +} + +tranformation_sort_order_unequal: { + options = { + comparisons: true, + }; + + input: { (a = parseInt('100')) != a } + expect: { (a = parseInt('100')) != a } +} + +tranformation_sort_order_lesser_or_equal: { + options = { + comparisons: true, + }; + + input: { (a = parseInt('100')) <= a } + expect: { (a = parseInt('100')) <= a } +} +tranformation_sort_order_greater_or_equal: { + options = { + comparisons: true, + }; + + input: { (a = parseInt('100')) >= a } + expect: { (a = parseInt('100')) >= a } +} \ No newline at end of file diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/issue-22.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/issue-22.js new file mode 100644 index 0000000..a8b7bc6 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/issue-22.js @@ -0,0 +1,17 @@ +return_with_no_value_in_if_body: { + options = { conditionals: true }; + input: { + function foo(bar) { + if (bar) { + return; + } else { + return 1; + } + } + } + expect: { + function foo (bar) { + return bar ? void 0 : 1; + } + } +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/issue-44.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/issue-44.js new file mode 100644 index 0000000..7a972f9 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/issue-44.js @@ -0,0 +1,31 @@ +issue_44_valid_ast_1: { + options = { unused: true }; + input: { + function a(b) { + for (var i = 0, e = b.qoo(); ; i++) {} + } + } + expect: { + function a(b) { + var i = 0; + for (b.qoo(); ; i++); + } + } +} + +issue_44_valid_ast_2: { + options = { unused: true }; + input: { + function a(b) { + if (foo) for (var i = 0, e = b.qoo(); ; i++) {} + } + } + expect: { + function a(b) { + if (foo) { + var i = 0; + for (b.qoo(); ; i++); + } + } + } +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/issue-59.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/issue-59.js new file mode 100644 index 0000000..82b3880 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/issue-59.js @@ -0,0 +1,30 @@ +keep_continue: { + options = { + dead_code: true, + evaluate: true + }; + input: { + while (a) { + if (b) { + switch (true) { + case c(): + d(); + } + continue; + } + f(); + } + } + expect: { + while (a) { + if (b) { + switch (true) { + case c(): + d(); + } + continue; + } + f(); + } + } +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/labels.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/labels.js new file mode 100644 index 0000000..044b7a7 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/labels.js @@ -0,0 +1,163 @@ +labels_1: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + out: { + if (foo) break out; + console.log("bar"); + } + }; + expect: { + foo || console.log("bar"); + } +} + +labels_2: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + out: { + if (foo) print("stuff"); + else break out; + console.log("here"); + } + }; + expect: { + if (foo) { + print("stuff"); + console.log("here"); + } + } +} + +labels_3: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + for (var i = 0; i < 5; ++i) { + if (i < 3) continue; + console.log(i); + } + }; + expect: { + for (var i = 0; i < 5; ++i) + i < 3 || console.log(i); + } +} + +labels_4: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + out: for (var i = 0; i < 5; ++i) { + if (i < 3) continue out; + console.log(i); + } + }; + expect: { + for (var i = 0; i < 5; ++i) + i < 3 || console.log(i); + } +} + +labels_5: { + options = { if_return: true, conditionals: true, dead_code: true }; + // should keep the break-s in the following + input: { + while (foo) { + if (bar) break; + console.log("foo"); + } + out: while (foo) { + if (bar) break out; + console.log("foo"); + } + }; + expect: { + while (foo) { + if (bar) break; + console.log("foo"); + } + out: while (foo) { + if (bar) break out; + console.log("foo"); + } + } +} + +labels_6: { + input: { + out: break out; + }; + expect: {} +} + +labels_7: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + while (foo) { + x(); + y(); + continue; + } + }; + expect: { + while (foo) { + x(); + y(); + } + } +} + +labels_8: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + while (foo) { + x(); + y(); + break; + } + }; + expect: { + while (foo) { + x(); + y(); + break; + } + } +} + +labels_9: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + out: while (foo) { + x(); + y(); + continue out; + z(); + k(); + } + }; + expect: { + while (foo) { + x(); + y(); + } + } +} + +labels_10: { + options = { if_return: true, conditionals: true, dead_code: true }; + input: { + out: while (foo) { + x(); + y(); + break out; + z(); + k(); + } + }; + expect: { + out: while (foo) { + x(); + y(); + break out; + } + } +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/loops.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/loops.js new file mode 100644 index 0000000..cdf1f04 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/loops.js @@ -0,0 +1,123 @@ +while_becomes_for: { + options = { loops: true }; + input: { + while (foo()) bar(); + } + expect: { + for (; foo(); ) bar(); + } +} + +drop_if_break_1: { + options = { loops: true }; + input: { + for (;;) + if (foo()) break; + } + expect: { + for (; !foo();); + } +} + +drop_if_break_2: { + options = { loops: true }; + input: { + for (;bar();) + if (foo()) break; + } + expect: { + for (; bar() && !foo();); + } +} + +drop_if_break_3: { + options = { loops: true }; + input: { + for (;bar();) { + if (foo()) break; + stuff1(); + stuff2(); + } + } + expect: { + for (; bar() && !foo();) { + stuff1(); + stuff2(); + } + } +} + +drop_if_break_4: { + options = { loops: true, sequences: true }; + input: { + for (;bar();) { + x(); + y(); + if (foo()) break; + z(); + k(); + } + } + expect: { + for (; bar() && (x(), y(), !foo());) z(), k(); + } +} + +drop_if_else_break_1: { + options = { loops: true }; + input: { + for (;;) if (foo()) bar(); else break; + } + expect: { + for (; foo(); ) bar(); + } +} + +drop_if_else_break_2: { + options = { loops: true }; + input: { + for (;bar();) { + if (foo()) baz(); + else break; + } + } + expect: { + for (; bar() && foo();) baz(); + } +} + +drop_if_else_break_3: { + options = { loops: true }; + input: { + for (;bar();) { + if (foo()) baz(); + else break; + stuff1(); + stuff2(); + } + } + expect: { + for (; bar() && foo();) { + baz(); + stuff1(); + stuff2(); + } + } +} + +drop_if_else_break_4: { + options = { loops: true, sequences: true }; + input: { + for (;bar();) { + x(); + y(); + if (foo()) baz(); + else break; + z(); + k(); + } + } + expect: { + for (; bar() && (x(), y(), foo());) baz(), z(), k(); + } +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/negate-iife.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/negate-iife.js new file mode 100644 index 0000000..0362ffc --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/negate-iife.js @@ -0,0 +1,76 @@ +negate_iife_1: { + options = { + negate_iife: true + }; + input: { + (function(){ stuff() })(); + } + expect: { + !function(){ stuff() }(); + } +} + +negate_iife_2: { + options = { + negate_iife: true + }; + input: { + (function(){ return {} })().x = 10; // should not transform this one + } + expect: { + (function(){ return {} })().x = 10; + } +} + +negate_iife_3: { + options = { + negate_iife: true, + }; + input: { + (function(){ return true })() ? console.log(true) : console.log(false); + } + expect: { + !function(){ return true }() ? console.log(false) : console.log(true); + } +} + +negate_iife_3: { + options = { + negate_iife: true, + sequences: true + }; + input: { + (function(){ return true })() ? console.log(true) : console.log(false); + (function(){ + console.log("something"); + })(); + } + expect: { + !function(){ return true }() ? console.log(false) : console.log(true), function(){ + console.log("something"); + }(); + } +} + +negate_iife_4: { + options = { + negate_iife: true, + sequences: true, + conditionals: true, + }; + input: { + if ((function(){ return true })()) { + console.log(true); + } else { + console.log(false); + } + (function(){ + console.log("something"); + })(); + } + expect: { + !function(){ return true }() ? console.log(false) : console.log(true), function(){ + console.log("something"); + }(); + } +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/properties.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/properties.js new file mode 100644 index 0000000..8504596 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/properties.js @@ -0,0 +1,54 @@ +keep_properties: { + options = { + properties: false + }; + input: { + a["foo"] = "bar"; + } + expect: { + a["foo"] = "bar"; + } +} + +dot_properties: { + options = { + properties: true + }; + input: { + a["foo"] = "bar"; + a["if"] = "if"; + a["*"] = "asterisk"; + a["\u0EB3"] = "unicode"; + a[""] = "whitespace"; + a["1_1"] = "foo"; + } + expect: { + a.foo = "bar"; + a["if"] = "if"; + a["*"] = "asterisk"; + a.\u0EB3 = "unicode"; + a[""] = "whitespace"; + a["1_1"] = "foo"; + } +} + +dot_properties_es5: { + options = { + properties: true, + screw_ie8: true + }; + input: { + a["foo"] = "bar"; + a["if"] = "if"; + a["*"] = "asterisk"; + a["\u0EB3"] = "unicode"; + a[""] = "whitespace"; + } + expect: { + a.foo = "bar"; + a.if = "if"; + a["*"] = "asterisk"; + a.\u0EB3 = "unicode"; + a[""] = "whitespace"; + } +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/sequences.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/sequences.js new file mode 100644 index 0000000..6f63ace --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/sequences.js @@ -0,0 +1,161 @@ +make_sequences_1: { + options = { + sequences: true + }; + input: { + foo(); + bar(); + baz(); + } + expect: { + foo(),bar(),baz(); + } +} + +make_sequences_2: { + options = { + sequences: true + }; + input: { + if (boo) { + foo(); + bar(); + baz(); + } else { + x(); + y(); + z(); + } + } + expect: { + if (boo) foo(),bar(),baz(); + else x(),y(),z(); + } +} + +make_sequences_3: { + options = { + sequences: true + }; + input: { + function f() { + foo(); + bar(); + return baz(); + } + function g() { + foo(); + bar(); + throw new Error(); + } + } + expect: { + function f() { + return foo(), bar(), baz(); + } + function g() { + throw foo(), bar(), new Error(); + } + } +} + +make_sequences_4: { + options = { + sequences: true + }; + input: { + x = 5; + if (y) z(); + + x = 5; + for (i = 0; i < 5; i++) console.log(i); + + x = 5; + for (; i < 5; i++) console.log(i); + + x = 5; + switch (y) {} + + x = 5; + with (obj) {} + } + expect: { + if (x = 5, y) z(); + for (x = 5, i = 0; i < 5; i++) console.log(i); + for (x = 5; i < 5; i++) console.log(i); + switch (x = 5, y) {} + with (x = 5, obj); + } +} + +lift_sequences_1: { + options = { sequences: true }; + input: { + foo = !(x(), y(), bar()); + } + expect: { + x(), y(), foo = !bar(); + } +} + +lift_sequences_2: { + options = { sequences: true, evaluate: true }; + input: { + q = 1 + (foo(), bar(), 5) + 7 * (5 / (3 - (a(), (QW=ER), c(), 2))) - (x(), y(), 5); + } + expect: { + foo(), bar(), a(), QW = ER, c(), x(), y(), q = 36 + } +} + +lift_sequences_3: { + options = { sequences: true, conditionals: true }; + input: { + x = (foo(), bar(), baz()) ? 10 : 20; + } + expect: { + foo(), bar(), x = baz() ? 10 : 20; + } +} + +lift_sequences_4: { + options = { side_effects: true }; + input: { + x = (foo, bar, baz); + } + expect: { + x = baz; + } +} + +for_sequences: { + options = { sequences: true }; + input: { + // 1 + foo(); + bar(); + for (; false;); + // 2 + foo(); + bar(); + for (x = 5; false;); + // 3 + x = (foo in bar); + for (; false;); + // 4 + x = (foo in bar); + for (y = 5; false;); + } + expect: { + // 1 + for (foo(), bar(); false;); + // 2 + for (foo(), bar(), x = 5; false;); + // 3 + x = (foo in bar); + for (; false;); + // 4 + x = (foo in bar); + for (y = 5; false;); + } +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/switch.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/switch.js new file mode 100644 index 0000000..62e39cf --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/switch.js @@ -0,0 +1,260 @@ +constant_switch_1: { + options = { dead_code: true, evaluate: true }; + input: { + switch (1+1) { + case 1: foo(); break; + case 1+1: bar(); break; + case 1+1+1: baz(); break; + } + } + expect: { + bar(); + } +} + +constant_switch_2: { + options = { dead_code: true, evaluate: true }; + input: { + switch (1) { + case 1: foo(); + case 1+1: bar(); break; + case 1+1+1: baz(); + } + } + expect: { + foo(); + bar(); + } +} + +constant_switch_3: { + options = { dead_code: true, evaluate: true }; + input: { + switch (10) { + case 1: foo(); + case 1+1: bar(); break; + case 1+1+1: baz(); + default: + def(); + } + } + expect: { + def(); + } +} + +constant_switch_4: { + options = { dead_code: true, evaluate: true }; + input: { + switch (2) { + case 1: + x(); + if (foo) break; + y(); + break; + case 1+1: + bar(); + default: + def(); + } + } + expect: { + bar(); + def(); + } +} + +constant_switch_5: { + options = { dead_code: true, evaluate: true }; + input: { + switch (1) { + case 1: + x(); + if (foo) break; + y(); + break; + case 1+1: + bar(); + default: + def(); + } + } + expect: { + // the break inside the if ruins our job + // we can still get rid of irrelevant cases. + switch (1) { + case 1: + x(); + if (foo) break; + y(); + } + // XXX: we could optimize this better by inventing an outer + // labeled block, but that's kinda tricky. + } +} + +constant_switch_6: { + options = { dead_code: true, evaluate: true }; + input: { + OUT: { + foo(); + switch (1) { + case 1: + x(); + if (foo) break OUT; + y(); + case 1+1: + bar(); + break; + default: + def(); + } + } + } + expect: { + OUT: { + foo(); + x(); + if (foo) break OUT; + y(); + bar(); + } + } +} + +constant_switch_7: { + options = { dead_code: true, evaluate: true }; + input: { + OUT: { + foo(); + switch (1) { + case 1: + x(); + if (foo) break OUT; + for (var x = 0; x < 10; x++) { + if (x > 5) break; // this break refers to the for, not to the switch; thus it + // shouldn't ruin our optimization + console.log(x); + } + y(); + case 1+1: + bar(); + break; + default: + def(); + } + } + } + expect: { + OUT: { + foo(); + x(); + if (foo) break OUT; + for (var x = 0; x < 10; x++) { + if (x > 5) break; + console.log(x); + } + y(); + bar(); + } + } +} + +constant_switch_8: { + options = { dead_code: true, evaluate: true }; + input: { + OUT: switch (1) { + case 1: + x(); + for (;;) break OUT; + y(); + break; + case 1+1: + bar(); + default: + def(); + } + } + expect: { + OUT: { + x(); + for (;;) break OUT; + y(); + } + } +} + +constant_switch_9: { + options = { dead_code: true, evaluate: true }; + input: { + OUT: switch (1) { + case 1: + x(); + for (;;) if (foo) break OUT; + y(); + case 1+1: + bar(); + default: + def(); + } + } + expect: { + OUT: { + x(); + for (;;) if (foo) break OUT; + y(); + bar(); + def(); + } + } +} + +drop_default_1: { + options = { dead_code: true }; + input: { + switch (foo) { + case 'bar': baz(); + default: + } + } + expect: { + switch (foo) { + case 'bar': baz(); + } + } +} + +drop_default_2: { + options = { dead_code: true }; + input: { + switch (foo) { + case 'bar': baz(); break; + default: + break; + } + } + expect: { + switch (foo) { + case 'bar': baz(); + } + } +} + +keep_default: { + options = { dead_code: true }; + input: { + switch (foo) { + case 'bar': baz(); + default: + something(); + break; + } + } + expect: { + switch (foo) { + case 'bar': baz(); + default: + something(); + } + } +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/typeof.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/typeof.js new file mode 100644 index 0000000..cefdd43 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/compress/typeof.js @@ -0,0 +1,25 @@ +typeof_evaluation: { + options = { + evaluate: true + }; + input: { + a = typeof 1; + b = typeof 'test'; + c = typeof []; + d = typeof {}; + e = typeof /./; + f = typeof false; + g = typeof function(){}; + h = typeof undefined; + } + expect: { + a='number'; + b='string'; + c=typeof[]; + d=typeof{}; + e=typeof/./; + f='boolean'; + g='function'; + h='undefined'; + } +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/test/run-tests.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/run-tests.js new file mode 100755 index 0000000..0568c6a --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/test/run-tests.js @@ -0,0 +1,170 @@ +#! /usr/bin/env node + +var U = require("../tools/node"); +var path = require("path"); +var fs = require("fs"); +var assert = require("assert"); +var sys = require("util"); + +var tests_dir = path.dirname(module.filename); + +run_compress_tests(); + +/* -----[ utils ]----- */ + +function tmpl() { + return U.string_template.apply(this, arguments); +} + +function log() { + var txt = tmpl.apply(this, arguments); + sys.puts(txt); +} + +function log_directory(dir) { + log("*** Entering [{dir}]", { dir: dir }); +} + +function log_start_file(file) { + log("--- {file}", { file: file }); +} + +function log_test(name) { + log(" Running test [{name}]", { name: name }); +} + +function find_test_files(dir) { + var files = fs.readdirSync(dir).filter(function(name){ + return /\.js$/i.test(name); + }); + if (process.argv.length > 2) { + var x = process.argv.slice(2); + files = files.filter(function(f){ + return x.indexOf(f) >= 0; + }); + } + return files; +} + +function test_directory(dir) { + return path.resolve(tests_dir, dir); +} + +function as_toplevel(input) { + if (input instanceof U.AST_BlockStatement) input = input.body; + else if (input instanceof U.AST_Statement) input = [ input ]; + else throw new Error("Unsupported input syntax"); + var toplevel = new U.AST_Toplevel({ body: input }); + toplevel.figure_out_scope(); + return toplevel; +} + +function run_compress_tests() { + var dir = test_directory("compress"); + log_directory("compress"); + var files = find_test_files(dir); + function test_file(file) { + log_start_file(file); + function test_case(test) { + log_test(test.name); + var options = U.defaults(test.options, { + warnings: false + }); + var cmp = new U.Compressor(options, true); + var expect = make_code(as_toplevel(test.expect), false); + var input = as_toplevel(test.input); + var input_code = make_code(test.input); + var output = input.transform(cmp); + output.figure_out_scope(); + output = make_code(output, false); + if (expect != output) { + log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", { + input: input_code, + output: output, + expected: expect + }); + } + } + var tests = parse_test(path.resolve(dir, file)); + for (var i in tests) if (tests.hasOwnProperty(i)) { + test_case(tests[i]); + } + } + files.forEach(function(file){ + test_file(file); + }); +} + +function parse_test(file) { + var script = fs.readFileSync(file, "utf8"); + var ast = U.parse(script, { + filename: file + }); + var tests = {}; + var tw = new U.TreeWalker(function(node, descend){ + if (node instanceof U.AST_LabeledStatement + && tw.parent() instanceof U.AST_Toplevel) { + var name = node.label.name; + tests[name] = get_one_test(name, node.body); + return true; + } + if (!(node instanceof U.AST_Toplevel)) croak(node); + }); + ast.walk(tw); + return tests; + + function croak(node) { + throw new Error(tmpl("Can't understand test file {file} [{line},{col}]\n{code}", { + file: file, + line: node.start.line, + col: node.start.col, + code: make_code(node, false) + })); + } + + function get_one_test(name, block) { + var test = { name: name, options: {} }; + var tw = new U.TreeWalker(function(node, descend){ + if (node instanceof U.AST_Assign) { + if (!(node.left instanceof U.AST_SymbolRef)) { + croak(node); + } + var name = node.left.name; + test[name] = evaluate(node.right); + return true; + } + if (node instanceof U.AST_LabeledStatement) { + assert.ok( + node.label.name == "input" || node.label.name == "expect", + tmpl("Unsupported label {name} [{line},{col}]", { + name: node.label.name, + line: node.label.start.line, + col: node.label.start.col + }) + ); + var stat = node.body; + if (stat instanceof U.AST_BlockStatement) { + if (stat.body.length == 1) stat = stat.body[0]; + else if (stat.body.length == 0) stat = new U.AST_EmptyStatement(); + } + test[node.label.name] = stat; + return true; + } + }); + block.walk(tw); + return test; + }; +} + +function make_code(ast, beautify) { + if (arguments.length == 1) beautify = true; + var stream = U.OutputStream({ beautify: beautify }); + ast.print(stream); + return stream.get(); +} + +function evaluate(code) { + if (code instanceof U.AST_Node) + code = make_code(code); + return new Function("return(" + code + ")")(); +} diff --git a/node_modules/jade/node_modules/with/node_modules/uglify-js/tools/node.js b/node_modules/jade/node_modules/with/node_modules/uglify-js/tools/node.js new file mode 100644 index 0000000..614e083 --- /dev/null +++ b/node_modules/jade/node_modules/with/node_modules/uglify-js/tools/node.js @@ -0,0 +1,167 @@ +var path = require("path"); +var fs = require("fs"); +var vm = require("vm"); +var sys = require("util"); + +var UglifyJS = vm.createContext({ + sys : sys, + console : console, + MOZ_SourceMap : require("source-map") +}); + +function load_global(file) { + file = path.resolve(path.dirname(module.filename), file); + try { + var code = fs.readFileSync(file, "utf8"); + return vm.runInContext(code, UglifyJS, file); + } catch(ex) { + // XXX: in case of a syntax error, the message is kinda + // useless. (no location information). + sys.debug("ERROR in file: " + file + " / " + ex); + process.exit(1); + } +}; + +var FILES = exports.FILES = [ + "../lib/utils.js", + "../lib/ast.js", + "../lib/parse.js", + "../lib/transform.js", + "../lib/scope.js", + "../lib/output.js", + "../lib/compress.js", + "../lib/sourcemap.js", + "../lib/mozilla-ast.js" +].map(function(file){ + return path.join(path.dirname(fs.realpathSync(__filename)), file); +}); + +FILES.forEach(load_global); + +UglifyJS.AST_Node.warn_function = function(txt) { + sys.error("WARN: " + txt); +}; + +// XXX: perhaps we shouldn't export everything but heck, I'm lazy. +for (var i in UglifyJS) { + if (UglifyJS.hasOwnProperty(i)) { + exports[i] = UglifyJS[i]; + } +} + +exports.minify = function(files, options) { + options = UglifyJS.defaults(options, { + outSourceMap : null, + sourceRoot : null, + inSourceMap : null, + fromString : false, + warnings : false, + mangle : {}, + output : null, + compress : {} + }); + if (typeof files == "string") + files = [ files ]; + + UglifyJS.base54.reset(); + + // 1. parse + var toplevel = null; + files.forEach(function(file){ + var code = options.fromString + ? file + : fs.readFileSync(file, "utf8"); + toplevel = UglifyJS.parse(code, { + filename: options.fromString ? "?" : file, + toplevel: toplevel + }); + }); + + // 2. compress + if (options.compress) { + var compress = { warnings: options.warnings }; + UglifyJS.merge(compress, options.compress); + toplevel.figure_out_scope(); + var sq = UglifyJS.Compressor(compress); + toplevel = toplevel.transform(sq); + } + + // 3. mangle + if (options.mangle) { + toplevel.figure_out_scope(); + toplevel.compute_char_frequency(); + toplevel.mangle_names(options.mangle); + } + + // 4. output + var inMap = options.inSourceMap; + var output = {}; + if (typeof options.inSourceMap == "string") { + inMap = fs.readFileSync(options.inSourceMap, "utf8"); + } + if (options.outSourceMap) { + output.source_map = UglifyJS.SourceMap({ + file: options.outSourceMap, + orig: inMap, + root: options.sourceRoot + }); + } + if (options.output) { + UglifyJS.merge(output, options.output); + } + var stream = UglifyJS.OutputStream(output); + toplevel.print(stream); + return { + code : stream + "", + map : output.source_map + "" + }; +}; + +// exports.describe_ast = function() { +// function doitem(ctor) { +// var sub = {}; +// ctor.SUBCLASSES.forEach(function(ctor){ +// sub[ctor.TYPE] = doitem(ctor); +// }); +// var ret = {}; +// if (ctor.SELF_PROPS.length > 0) ret.props = ctor.SELF_PROPS; +// if (ctor.SUBCLASSES.length > 0) ret.sub = sub; +// return ret; +// } +// return doitem(UglifyJS.AST_Node).sub; +// } + +exports.describe_ast = function() { + var out = UglifyJS.OutputStream({ beautify: true }); + function doitem(ctor) { + out.print("AST_" + ctor.TYPE); + var props = ctor.SELF_PROPS.filter(function(prop){ + return !/^\$/.test(prop); + }); + if (props.length > 0) { + out.space(); + out.with_parens(function(){ + props.forEach(function(prop, i){ + if (i) out.space(); + out.print(prop); + }); + }); + } + if (ctor.documentation) { + out.space(); + out.print_string(ctor.documentation); + } + if (ctor.SUBCLASSES.length > 0) { + out.space(); + out.with_block(function(){ + ctor.SUBCLASSES.forEach(function(ctor, i){ + out.indent(); + doitem(ctor); + out.newline(); + }); + }); + } + }; + doitem(UglifyJS.AST_Node); + return out + ""; +}; diff --git a/node_modules/jade/node_modules/with/package.json b/node_modules/jade/node_modules/with/package.json new file mode 100644 index 0000000..1533d19 --- /dev/null +++ b/node_modules/jade/node_modules/with/package.json @@ -0,0 +1,34 @@ +{ + "name": "with", + "version": "1.1.1", + "description": "Compile time `with` for strict mode JavaScript", + "main": "index.js", + "scripts": { + "test": "mocha -R spec" + }, + "repository": { + "type": "git", + "url": "https://github.com/ForbesLindesay/with.git" + }, + "author": { + "name": "ForbesLindesay" + }, + "license": "MIT", + "dependencies": { + "uglify-js": "2.4.0" + }, + "devDependencies": { + "mocha": "~1.12.0" + }, + "readme": "# with\r\n\r\nCompile time `with` for strict mode JavaScript\r\n\r\n[![build status](https://secure.travis-ci.org/ForbesLindesay/with.png)](http://travis-ci.org/ForbesLindesay/with)\r\n[![Dependency Status](https://gemnasium.com/ForbesLindesay/with.png)](https://gemnasium.com/ForbesLindesay/with)\r\n[![NPM version](https://badge.fury.io/js/with.png)](http://badge.fury.io/js/with)\r\n\r\n## Installation\r\n\r\n $ npm install with\r\n\r\n## Usage\r\n\r\n```js\r\nvar addWith = require('with')\r\n\r\naddWith('obj', 'console.log(a)')\r\n// => \"var a = obj.a;console.log(a)\"\r\n\r\naddWith(\"obj || {}\", \"console.log(helper(a))\", [\"helper\"])\r\n// => var locals = (obj || {}),a = locals.a;console.log(helper(a))\r\n```\r\n\r\n## API\r\n\r\n### addWith(obj, src, [exclude])\r\n\r\nThe idea is that this is roughly equivallent to:\r\n\r\n```js\r\nwith (obj) {\r\n src\r\n}\r\n```\r\n\r\nThere are a few differences though. For starters, it will be assumed that all variables used in `src` come from `obj` so any that don't (e.g. template helpers) need to have their names parsed to `exclude` as an array.\r\n\r\nIt also makes everything be declared, so you can always do:\r\n\r\n```js\r\nif (foo === undefined)\r\n```\r\n\r\ninstead of\r\n\r\n```js\r\nif (typeof foo === 'undefined')\r\n```\r\n\r\nIt is also safe to use in strict mode (unlike `with`) and it minifies properly (`with` disables virtually all minification).\r\n\r\n## License\r\n\r\n MIT", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/ForbesLindesay/with/issues" + }, + "_id": "with@1.1.1", + "dist": { + "shasum": "28b54a6ce0257ba0f3a32de41efa311b40bceb84" + }, + "_from": "with@~1.1.0", + "_resolved": "https://registry.npmjs.org/with/-/with-1.1.1.tgz" +} diff --git a/node_modules/jade/package.json b/node_modules/jade/package.json new file mode 100644 index 0000000..35dee0e --- /dev/null +++ b/node_modules/jade/package.json @@ -0,0 +1,68 @@ +{ + "name": "jade", + "description": "Jade template engine", + "version": "0.35.0", + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "repository": { + "type": "git", + "url": "git://github.com/visionmedia/jade" + }, + "main": "./index.js", + "bin": { + "jade": "./bin/jade" + }, + "man": [ + "./jade.1" + ], + "dependencies": { + "commander": "2.0.0", + "mkdirp": "0.3.x", + "transformers": "2.1.0", + "character-parser": "1.2.0", + "monocle": "1.1.50", + "with": "~1.1.0", + "constantinople": "~1.0.1" + }, + "devDependencies": { + "coffee-script": "*", + "mocha": "*", + "markdown": "*", + "stylus": "*", + "uubench": "*", + "should": "*", + "less": "*", + "uglify-js": "*", + "browserify": "*", + "linify": "*" + }, + "component": { + "scripts": { + "jade": "runtime.js" + } + }, + "scripts": { + "test": "mocha -R spec", + "prepublish": "npm prune && linify transform bin && npm run build", + "build": "npm run compile", + "compile": "npm run compile-full && npm run compile-runtime", + "compile-full": "browserify ./lib/jade.js --standalone jade -x ./node_modules/transformers > jade.js", + "compile-runtime": "browserify ./lib/runtime.js --standalone jade > runtime.js" + }, + "browser": { + "./lib/filters.js": "./lib/filters-client.js" + }, + "readme": "# [![Jade - template engine ](http://i.imgur.com/5zf2aVt.png)](http://jade-lang.com/)\r\n\r\nFull documentation is at [jade-lang.com](http://jade-lang.com/)\r\n\r\n Jade is a high performance template engine heavily influenced by [Haml](http://haml-lang.com)\r\n and implemented with JavaScript for [node](http://nodejs.org). For discussion join the [Google Group](http://groups.google.com/group/jadejs).\r\n\r\n You can test drive Jade online [here](http://naltatis.github.com/jade-syntax-docs).\r\n\r\n [![Build Status](https://travis-ci.org/visionmedia/jade.png?branch=master)](https://travis-ci.org/visionmedia/jade)\r\n [![Dependency Status](https://gemnasium.com/visionmedia/jade.png)](https://gemnasium.com/visionmedia/jade)\r\n [![NPM version](https://badge.fury.io/js/jade.png)](http://badge.fury.io/js/jade)\r\n\r\n## Announcements\r\n\r\n**Deprecation of implicit script/style text-only:**\r\n\r\n Jade version 0.31.0 deprecated implicit text only support for scripts and styles. To fix this all you need to do is add a `.` character after the script or style tag.\r\n\r\n It is hoped that this change will make Jade easier for newcomers to learn without affecting the power of the language or leading to excessive verboseness.\r\n\r\n If you have a lot of Jade files that need fixing you can use [fix-jade](https://github.com/ForbesLindesay/fix-jade) to attempt to automate the process.\r\n\r\n**Command line option change:**\r\n\r\nsince `v0.31.0`, `-o` is preferred for `--out` where we used `-O` before.\r\n\r\n## Installation\r\n\r\nvia npm:\r\n\r\n```bash\r\n$ npm install jade\r\n```\r\n\r\n## Syntax\r\n\r\nJade is a clean, whitespace sensitive syntax for writing html. Here is a simple example:\r\n\r\n```jade\r\ndoctype 5\r\nhtml(lang=\"en\")\r\n head\r\n title= pageTitle\r\n script(type='text/javascript').\r\n if (foo) bar(1 + 5)\r\n body\r\n h1 Jade - node template engine\r\n #container.col\r\n if youAreUsingJade\r\n p You are amazing\r\n else\r\n p Get on it!\r\n p.\r\n Jade is a terse and simple templating language with a\r\n strong focus on performance and powerful features.\r\n```\r\n\r\nbecomes\r\n\r\n\r\n```html\r\n\r\n\r\n \r\n Jade\r\n \r\n \r\n \r\n

    Jade - node template engine

    \r\n
    \r\n

    You are amazing

    \r\n

    Jade is a terse and simple templating language with a strong focus on performance and powerful features.

    \r\n
    \r\n \r\n\r\n```\r\n\r\nThe official [jade tutorial](http://jade-lang.com/tutorial/) is a great place to start. While that (and the syntax documentation) is being finished, you can view some of the old documentation [here](https://github.com/visionmedia/jade/blob/master/jade.md) and [here](https://github.com/visionmedia/jade/blob/master/jade-language.md)\r\n\r\n## API\r\n\r\nFor full API, see [jade-lang.com/api](http://jade-lang.com/api/)\r\n\r\n```js\r\nvar jade = require('jade');\r\n\r\n// compile\r\nvar fn = jade.compile('string of jade', options);\r\nvar html = fn(locals);\r\n\r\n// render\r\nvar html = jade.render('string of jade', merge(options, locals));\r\n\r\n// renderFile\r\nvar html = jade.renderFile('filename.jade', merge(options, locals));\r\n```\r\n\r\n### Options\r\n\r\n - `filename` Used in exceptions, and required when using includes\r\n - `compileDebug` When `false` no debug instrumentation is compiled\r\n - `pretty` Add pretty-indentation whitespace to output _(false by default)_\r\n\r\n## Browser Support\r\n\r\n The latest version of jade can be download for the browser in standalone form from [here](https://github.com/visionmedia/jade/raw/master/jade.js). It only supports the very latest browsers though, and is a large file. It is recommended that you pre-compile your jade templates to JavaScript and then just use the [runtime.js](https://github.com/visionmedia/jade/raw/master/runtime.js) library on the client.\r\n\r\n To compile a template for use on the client using the command line, do:\r\n\r\n```console\r\n$ jade --client --no-debug filename.jade\r\n```\r\n\r\nwhich will produce `filename.js` containing the compiled template.\r\n\r\n## Command Line\r\n\r\nAfter installing the latest version of [node](http://nodejs.org/), install with:\r\n\r\n```console\r\n$ npm install jade -g\r\n```\r\n\r\nand run with\r\n\r\n```console\r\n$ jade --help\r\n```\r\n\r\n## Additional Resources\r\n\r\nTutorials:\r\n\r\n - cssdeck interactive [Jade syntax tutorial](http://cssdeck.com/labs/learning-the-jade-templating-engine-syntax)\r\n - cssdeck interactive [Jade logic tutorial](http://cssdeck.com/labs/jade-templating-tutorial-codecast-part-2)\r\n - in [Japanese](http://blog.craftgear.net/4f501e97c1347ec934000001/title/10%E5%88%86%E3%81%A7%E3%82%8F%E3%81%8B%E3%82%8Bjade%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%B3)\r\n\r\n\r\nImplementations in other languages:\r\n\r\n - [php](http://github.com/everzet/jade.php)\r\n - [scala](http://scalate.fusesource.org/versions/snapshot/documentation/scaml-reference.html)\r\n - [ruby](https://github.com/slim-template/slim)\r\n - [python](https://github.com/SyrusAkbary/pyjade)\r\n - [java](https://github.com/neuland/jade4j)\r\n\r\nOther:\r\n\r\n - [Emacs Mode](https://github.com/brianc/jade-mode)\r\n - [Vim Syntax](https://github.com/digitaltoad/vim-jade)\r\n - [TextMate Bundle](http://github.com/miksago/jade-tmbundle)\r\n - [Coda/SubEtha syntax Mode](https://github.com/aaronmccall/jade.mode)\r\n - [Screencasts](http://tjholowaychuk.com/post/1004255394/jade-screencast-template-engine-for-nodejs)\r\n - [html2jade](https://github.com/donpark/html2jade) converter\r\n\r\n## License\r\n\r\nMIT\r\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/jade/issues" + }, + "_id": "jade@0.35.0", + "dist": { + "shasum": "48b55975d691af0c475bdd4ed718aa4c4da4ae5c" + }, + "_from": "jade@0.35.x", + "_resolved": "https://registry.npmjs.org/jade/-/jade-0.35.0.tgz" +} diff --git a/node_modules/jade/runtime.js b/node_modules/jade/runtime.js new file mode 100644 index 0000000..5389ccb --- /dev/null +++ b/node_modules/jade/runtime.js @@ -0,0 +1,208 @@ +(function(e){if("function"==typeof bootstrap)bootstrap("jade",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeJade=e}else"undefined"!=typeof window?window.jade=e():global.jade=e()})(function(){var define,ses,bootstrap,module,exports; +return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o + * MIT Licensed + */ + +/** + * Lame Array.isArray() polyfill for now. + */ + +if (!Array.isArray) { + Array.isArray = function(arr){ + return '[object Array]' == Object.prototype.toString.call(arr); + }; +} + +/** + * Lame Object.keys() polyfill for now. + */ + +if (!Object.keys) { + Object.keys = function(obj){ + var arr = []; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + arr.push(key); + } + } + return arr; + } +} + +/** + * Merge two attribute objects giving precedence + * to values in object `b`. Classes are special-cased + * allowing for arrays and merging/joining appropriately + * resulting in a string. + * + * @param {Object} a + * @param {Object} b + * @return {Object} a + * @api private + */ + +exports.merge = function merge(a, b) { + var ac = a['class']; + var bc = b['class']; + + if (ac || bc) { + ac = ac || []; + bc = bc || []; + if (!Array.isArray(ac)) ac = [ac]; + if (!Array.isArray(bc)) bc = [bc]; + a['class'] = ac.concat(bc).filter(nulls); + } + + for (var key in b) { + if (key != 'class') { + a[key] = b[key]; + } + } + + return a; +}; + +/** + * Filter null `val`s. + * + * @param {*} val + * @return {Boolean} + * @api private + */ + +function nulls(val) { + return val != null && val !== ''; +} + +/** + * join array as classes. + * + * @param {*} val + * @return {String} + * @api private + */ + +function joinClasses(val) { + return Array.isArray(val) ? val.map(joinClasses).filter(nulls).join(' ') : val; +} + +/** + * Render the given attributes object. + * + * @param {Object} obj + * @param {Object} escaped + * @return {String} + * @api private + */ + +exports.attrs = function attrs(obj, escaped){ + var buf = [] + , terse = obj.terse; + + delete obj.terse; + var keys = Object.keys(obj) + , len = keys.length; + + if (len) { + buf.push(''); + for (var i = 0; i < len; ++i) { + var key = keys[i] + , val = obj[key]; + + if ('boolean' == typeof val || null == val) { + if (val) { + terse + ? buf.push(key) + : buf.push(key + '="' + key + '"'); + } + } else if (0 == key.indexOf('data') && 'string' != typeof val) { + buf.push(key + "='" + JSON.stringify(val) + "'"); + } else if ('class' == key) { + if (escaped && escaped[key]){ + if (val = exports.escape(joinClasses(val))) { + buf.push(key + '="' + val + '"'); + } + } else { + if (val = joinClasses(val)) { + buf.push(key + '="' + val + '"'); + } + } + } else if (escaped && escaped[key]) { + buf.push(key + '="' + exports.escape(val) + '"'); + } else { + buf.push(key + '="' + val + '"'); + } + } + } + + return buf.join(' '); +}; + +/** + * Escape the given string of `html`. + * + * @param {String} html + * @return {String} + * @api private + */ + +exports.escape = function escape(html){ + return String(html) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +}; + +/** + * Re-throw the given `err` in context to the + * the jade in `filename` at the given `lineno`. + * + * @param {Error} err + * @param {String} filename + * @param {String} lineno + * @api private + */ + +exports.rethrow = function rethrow(err, filename, lineno, str){ + if (!(err instanceof Error)) throw err; + if ((typeof window != 'undefined' || !filename) && !str) { + err.message += ' on line ' + lineno; + throw err; + } + try { + str = str || require('fs').readFileSync(filename, 'utf8') + } catch (ex) { + rethrow(err, null, lineno) + } + var context = 3 + , lines = str.split('\n') + , start = Math.max(lineno - context, 0) + , end = Math.min(lines.length, lineno + context); + + // Error context + var context = lines.slice(start, end).map(function(line, i){ + var curr = i + start + 1; + return (curr == lineno ? ' > ' : ' ') + + curr + + '| ' + + line; + }).join('\n'); + + // Alter exception message + err.path = filename; + err.message = (filename || 'Jade') + ':' + lineno + + '\n' + context + '\n\n' + err.message; + throw err; +}; + +},{"fs":2}],2:[function(require,module,exports){ +// nothing to see here... no file methods for the browser + +},{}]},{},[1])(1) +}); +; \ No newline at end of file diff --git a/node_modules/mongoose/.npmignore b/node_modules/mongoose/.npmignore new file mode 100644 index 0000000..df5ea94 --- /dev/null +++ b/node_modules/mongoose/.npmignore @@ -0,0 +1,13 @@ +lib-cov +**.swp +*.sw* +*.orig +.DS_Store +node_modules/ +benchmarks/ +docs/ +test/ +Makefile +CNAME +index.html +index.jade diff --git a/node_modules/mongoose/.travis.yml b/node_modules/mongoose/.travis.yml new file mode 100644 index 0000000..dcaf0f1 --- /dev/null +++ b/node_modules/mongoose/.travis.yml @@ -0,0 +1,6 @@ +language: node_js +node_js: + - 0.8 + - 0.10 +services: + - mongodb diff --git a/node_modules/mongoose/CONTRIBUTING.md b/node_modules/mongoose/CONTRIBUTING.md new file mode 100644 index 0000000..5860cb5 --- /dev/null +++ b/node_modules/mongoose/CONTRIBUTING.md @@ -0,0 +1,58 @@ +## Contributing to Mongoose + +If you have a question about Mongoose (not a bug report) please post it to either [StackOverflow](http://stackoverflow.com/questions/tagged/mongoose), our [Google Group](http://groups.google.com/group/mongoose-orm), or on the #mongoosejs irc channel on freenode. + +### Reporting bugs + +- Before opening a new issue, look for existing [issues](https://github.com/learnboost/mongoose/issues) to avoid duplication. If the issue does not yet exist, [create one](https://github.com/learnboost/mongoose/issues/new). + - Please describe the issue you are experiencing, along with any associated stack trace. + - Please post code that reproduces the issue, the version of mongoose, node version, and mongodb version. + - _The source of this project is written in javascript, not coffeescript, therefore your bug reports should be written in javascript_. + - In general, adding a "+1" comment to an existing issue does little to help get it resolved. A better way is to submit a well documented pull request with clean code and passing tests. + +### Requesting new features + +- Before opening a new issue, look for existing [issues](https://github.com/learnboost/mongoose/issues) to avoid duplication. If the issue does not yet exist, [create one](https://github.com/learnboost/mongoose/issues/new). +- Please describe a use case for it +- it would be ideal to include test cases as well +- In general, adding a "+1" comment to an existing issue does little to help get it resolved. A better way is to submit a well documented pull request with clean code and passing tests. + +### Fixing bugs / Adding features + +- Before starting to write code, look for existing [issues](https://github.com/learnboost/mongoose/issues). That way you avoid working on something that might not be of interest or that has been addressed already in a different branch. You can create a new issue [here](https://github.com/learnboost/mongoose/issues/new). + - _The source of this project is written in javascript, not coffeescript, therefore your bug reports should be written in javascript_. +- Fork the [repo](https://github.com/learnboost/mongoose) _or_ for small documentation changes, navigate to the source on github and click the [Edit](https://github.com/blog/844-forking-with-the-edit-button) button. +- Follow the general coding style of the rest of the project: + - 2 space tabs + - no trailing whitespace + - comma first + - inline documentation for new methods, class members, etc + - 1 space between conditionals/functions, and their parenthesis and curly braces + - `if (..) {` + - `for (..) {` + - `while (..) {` + - `function (err) {` +- Write tests and make sure they pass (tests are in the [test](https://github.com/LearnBoost/mongoose/tree/master/test) directory). + +### Running the tests +- Open a terminal and navigate to the root of the project +- execute `npm install` to install the necessary dependencies +- execute `make test` to run the tests (we're using [mocha](http://visionmedia.github.com/mocha/)) + - or to execute a single test `T="-g 'some regexp that matches the test description'" make test` + - any mocha flags can be specified with `T="..."` + +### Documentation + +To contribute to the [API documentation](http://mongoosejs.com/docs/api.html) just make your changes to the inline documentation of the appropriate [source code](https://github.com/LearnBoost/mongoose/tree/master/lib) in the master branch and submit a [pull request](https://help.github.com/articles/using-pull-requests/). You might also use the github [Edit](https://github.com/blog/844-forking-with-the-edit-button) button. + +To contribute to the [guide](http://mongoosejs.com/docs/guide.html) or [quick start](http://mongoosejs.com/docs/index.html) docs, make your changes to the appropriate `.jade` files in the [docs](https://github.com/LearnBoost/mongoose/tree/master/docs) directory of the master branch and submit a pull request. Again, the [Edit](https://github.com/blog/844-forking-with-the-edit-button) button might work for you here. + +If you'd like to preview your documentation changes, first commit your changes to your local 3.6.x branch, then execute `make docs` from the project root, which switches to the gh-pages branch, merges from the 3.6.x branch and builds all the static pages for you. Now execute `node static.js` from the project root which will launch a local webserver where you can browse the documentation site locally. If all looks good, submit a [pull request](https://help.github.com/articles/using-pull-requests/) to the 3.6.x branch with your changes. + +### Plugins website + +The [plugins](http://plugins.mongoosejs.com/) site is also an [open source project](https://github.com/aheckmann/mongooseplugins) that you can get involved with. Feel free to fork and improve it as well! + +### Sharing your projects + +All are welcome to share their creations which use mongoose on our [tumbler](http://mongoosejs.tumblr.com/). Just fill out the [simple submission form](http://mongoosejs.tumblr.com/submit). diff --git a/node_modules/mongoose/History.md b/node_modules/mongoose/History.md new file mode 100644 index 0000000..5cd9673 --- /dev/null +++ b/node_modules/mongoose/History.md @@ -0,0 +1,1974 @@ + +3.8.0 / 2013-10-31 +================== + + * updated; warn when using an unstable version + * updated; error message returned in doc.save() #1595 + * updated; mongodb driver to 1.3.19 (fix error swallowing behavior) + * updated; mquery to 0.3.2 + * updated; mocha to 1.12.0 + * updated; mpromise 0.3.0 + * updated; sliced 0.0.5 + * removed; mongoose.Error.DocumentError (never used) + * removed; namedscope (undocumented and broken) #679 #642 #455 #379 + * changed; no longer offically supporting node 0.6.x + * changed; query.within getter is now a method -> query.within() + * changed; query.intersects getter is now a method -> query.intersects() + * added; custom error msgs for built-in validators #747 + * added; discriminator support #1647 #1003 [j](https://github.com/j) + * added; support disabled collection name pluralization #1350 #1707 [refack](https://github.com/refack) + * added; support for GeoJSON to Query#near [ebensing](https://github.com/ebensing) + * added; stand-alone base query support - query.toConstructor() [ebensing](https://github.com/ebensing) + * added; promise support to geoSearch #1614 [ebensing](https://github.com/ebensing) + * added; promise support for geoNear #1614 [ebensing](https://github.com/ebensing) + * added; connection.useDb() #1124 [ebensing](https://github.com/ebensing) + * added; promise support to model.mapReduce() + * added; promise support to model.ensureIndexes() + * added; promise support to model.populate() + * added; benchmarks [ebensing](https://github.com/ebensing) + * added; publicly exposed connection states #1585 + * added; $geoWithin support #1529 $1455 [ebensing](https://github.com/ebensing) + * added; query method chain validation + * added; model.update `overwrite` option + * added; model.geoNear() support #1563 [ebensing](https://github.com/ebensing) + * added; model.geoSearch() support #1560 [ebensing](https://github.com/ebensing) + * added; MongooseBuffer#subtype() + * added; model.create() now returns a promise #1340 + * added; support for `awaitdata` query option + * added; pass the doc to doc.remove() callback #1419 [JoeWagner](https://github.com/JoeWagner) + * added; aggregation query builder #1404 [njoyard](https://github.com/njoyard) + * fixed; document.toObject when using `minimize` and `getters` options #1607 [JedWatson](https://github.com/JedWatson) + * fixed; Mixed types can now be required #1722 [Reggino](https://github.com/Reggino) + * fixed; do not pluralize model names not ending with letters #1703 [refack](https://github.com/refack) + * fixed; repopulating modified populated paths #1697 + * fixed; doc.equals() when _id option is set to false #1687 + * fixed; strict mode warnings #1686 + * fixed; $near GeoJSON casting #1683 + * fixed; nearSphere GeoJSON query builder + * fixed; population field selection w/ strings #1669 + * fixed; setters not firing on null values #1445 [ebensing](https://github.com/ebensing) + * fixed; handle another versioning edge case #1520 + * fixed; excluding subdocument fields #1280 [ebensing](https://github.com/ebensing) + * fixed; allow array properties to be set to null with findOneAndUpdate [aheuermann](https://github.com/aheuermann) + * fixed; subdocuments now use own toJSON opts #1376 [ebensing](https://github.com/ebensing) + * fixed; model#geoNear fulfills promise when results empty #1658 [ebensing](https://github.com/ebensing) + * fixed; utils.merge no longer overrides props and methods #1655 [j](https://github.com/j) + * fixed; subdocuments now use their own transform #1412 [ebensing](https://github.com/ebensing) + * fixed; model.remove() removes only what is necessary #1649 + * fixed; update() now only runs with cb or explicit true #1644 + * fixed; casting ref docs on creation #1606 [ebensing](https://github.com/ebensing) + * fixed; model.update "overwrite" option works as documented + * fixed; query#remove() works as documented + * fixed; "limit" correctly applies to individual items on population #1490 [ebensing](https://github.com/ebensing) + * fixed; issue with positional operator on ref docs #1572 [ebensing](https://github.com/ebensing) + * fixed; benchmarks to actually output valid json + * deprecated; promise#addBack (use promise#onResolve) + * deprecated; promise#complete (use promise#fulfill) + * deprecated; promise#addCallback (use promise#onFulFill) + * deprecated; promise#addErrback (use promise#onReject) + * deprecated; query.nearSphere() (use query.near) + * deprecated; query.center() (use query.circle) + * deprecated; query.centerSphere() (use query.circle) + * deprecated; query#slaveOk (use query#read) + * docs; custom validator messages + * docs; 10gen -> MongoDB + * docs; add Date method caveats #1598 + * docs; more validation details + * docs; state which branch is stable/unstable + * docs; mention that middleware does not run on Models + * docs; promise.fulfill() + * docs; fix readme spelling #1483 [yorchopolis](https://github.com/yorchopolis) + * docs; fixed up the README and examples [ebensing](https://github.com/ebensing) + * website; add "show code" for properties + * website; move "show code" links down + * website; update guide + * website; add unstable docs + * website; many improvements + * website; fix copyright #1439 + * website; server.js -> static.js #1546 [nikmartin](https://github.com/nikmartin) + * tests; refactor 1703 + * tests; add test generator + * tests; validate formatMessage() throws + * tests; add script for continuously running tests + * tests; fixed versioning tests + * tests; race conditions in tests + * tests; added for nested and/or queries + * tests; close some test connections + * tests; validate db contents + * tests; remove .only + * tests; close some test connections + * tests; validate db contents + * tests; remove .only + * tests; replace deprecated method names + * tests; convert id to string + * tests; fix sharding tests for MongoDB 2.4.5 + * tests; now 4-5 seconds faster + * tests; fix race condition + * make; suppress warning msg in test + * benchmarks; updated for pull requests + * examples; improved and expanded [ebensing](https://github.com/ebensing) + +3.7.4 (unstable) / 2013-10-01 +============================= + + * updated; mquery to 0.3.2 + * removed; mongoose.Error.DocumentError (never used) + * added; custom error msgs for built-in validators #747 + * added; discriminator support #1647 #1003 [j](https://github.com/j) + * added; support disabled collection name pluralization #1350 #1707 [refack](https://github.com/refack) + * fixed; do not pluralize model names not ending with letters #1703 [refack](https://github.com/refack) + * fixed; repopulating modified populated paths #1697 + * fixed; doc.equals() when _id option is set to false #1687 + * fixed; strict mode warnings #1686 + * fixed; $near GeoJSON casting #1683 + * fixed; nearSphere GeoJSON query builder + * fixed; population field selection w/ strings #1669 + * docs; custom validator messages + * docs; 10gen -> MongoDB + * docs; add Date method caveats #1598 + * docs; more validation details + * website; add "show code" for properties + * website; move "show code" links down + * tests; refactor 1703 + * tests; add test generator + * tests; validate formatMessage() throws + +3.7.3 (unstable) / 2013-08-22 +============================= + + * updated; warn when using an unstable version + * updated; mquery to 0.3.1 + * updated; mocha to 1.12.0 + * updated; mongodb driver to 1.3.19 (fix error swallowing behavior) + * changed; no longer offically supporting node 0.6.x + * added; support for GeoJSON to Query#near [ebensing](https://github.com/ebensing) + * added; stand-alone base query support - query.toConstructor() [ebensing](https://github.com/ebensing) + * added; promise support to geoSearch #1614 [ebensing](https://github.com/ebensing) + * added; promise support for geoNear #1614 [ebensing](https://github.com/ebensing) + * fixed; setters not firing on null values #1445 [ebensing](https://github.com/ebensing) + * fixed; handle another versioning edge case #1520 + * fixed; excluding subdocument fields #1280 [ebensing](https://github.com/ebensing) + * fixed; allow array properties to be set to null with findOneAndUpdate [aheuermann](https://github.com/aheuermann) + * fixed; subdocuments now use own toJSON opts #1376 [ebensing](https://github.com/ebensing) + * fixed; model#geoNear fulfills promise when results empty #1658 [ebensing](https://github.com/ebensing) + * fixed; utils.merge no longer overrides props and methods #1655 [j](https://github.com/j) + * fixed; subdocuments now use their own transform #1412 [ebensing](https://github.com/ebensing) + * make; suppress warning msg in test + * docs; state which branch is stable/unstable + * docs; mention that middleware does not run on Models + * tests; add script for continuously running tests + * tests; fixed versioning tests + * benchmarks; updated for pull requests + +3.7.2 (unstable) / 2013-08-15 +================== + + * fixed; model.remove() removes only what is necessary #1649 + * fixed; update() now only runs with cb or explicit true #1644 + * tests; race conditions in tests + * website; update guide + +3.7.1 (unstable) / 2013-08-13 +============================= + + * updated; driver to 1.3.18 (fixes memory leak) + * added; connection.useDb() #1124 [ebensing](https://github.com/ebensing) + * added; promise support to model.mapReduce() + * added; promise support to model.ensureIndexes() + * added; promise support to model.populate() + * fixed; casting ref docs on creation #1606 [ebensing](https://github.com/ebensing) + * fixed; model.update "overwrite" option works as documented + * fixed; query#remove() works as documented + * fixed; "limit" correctly applies to individual items on population #1490 [ebensing](https://github.com/ebensing) + * fixed; issue with positional operator on ref docs #1572 [ebensing](https://github.com/ebensing) + * fixed; benchmarks to actually output valid json + * tests; added for nested and/or queries + * tests; close some test connections + * tests; validate db contents + * tests; remove .only + * tests; close some test connections + * tests; validate db contents + * tests; remove .only + * tests; replace deprecated method names + * tests; convert id to string + * docs; promise.fulfill() + +3.7.0 (unstable) / 2013-08-05 +=================== + + * changed; query.within getter is now a method -> query.within() + * changed; query.intersects getter is now a method -> query.intersects() + * deprecated; promise#addBack (use promise#onResolve) + * deprecated; promise#complete (use promise#fulfill) + * deprecated; promise#addCallback (use promise#onFulFill) + * deprecated; promise#addErrback (use promise#onReject) + * deprecated; query.nearSphere() (use query.near) + * deprecated; query.center() (use query.circle) + * deprecated; query.centerSphere() (use query.circle) + * deprecated; query#slaveOk (use query#read) + * removed; namedscope (undocumented and broken) #679 #642 #455 #379 + * added; benchmarks [ebensing](https://github.com/ebensing) + * added; publicly exposed connection states #1585 + * added; $geoWithin support #1529 $1455 [ebensing](https://github.com/ebensing) + * added; query method chain validation + * added; model.update `overwrite` option + * added; model.geoNear() support #1563 [ebensing](https://github.com/ebensing) + * added; model.geoSearch() support #1560 [ebensing](https://github.com/ebensing) + * added; MongooseBuffer#subtype() + * added; model.create() now returns a promise #1340 + * added; support for `awaitdata` query option + * added; pass the doc to doc.remove() callback #1419 [JoeWagner](https://github.com/JoeWagner) + * added; aggregation query builder #1404 [njoyard](https://github.com/njoyard) + * updated; integrate mquery #1562 [ebensing](https://github.com/ebensing) + * updated; error msg in doc.save() #1595 + * updated; bump driver to 1.3.15 + * updated; mpromise 0.3.0 + * updated; sliced 0.0.5 + * tests; fix sharding tests for MongoDB 2.4.5 + * tests; now 4-5 seconds faster + * tests; fix race condition + * docs; fix readme spelling #1483 [yorchopolis](https://github.com/yorchopolis) + * docs; fixed up the README and examples [ebensing](https://github.com/ebensing) + * website; add unstable docs + * website; many improvements + * website; fix copyright #1439 + * website; server.js -> static.js #1546 [nikmartin](https://github.com/nikmartin) + * examples; improved and expanded [ebensing](https://github.com/ebensing) + +3.6.20 (stable) / 2013-09-23 +=================== + + * fixed; repopulating modified populated paths #1697 + * fixed; doc.equals w/ _id false #1687 + * fixed; strict mode warning #1686 + * docs; near/nearSphere + +3.6.19 (stable) / 2013-09-04 +================== + + * fixed; population field selection w/ strings #1669 + * docs; Date method caveats #1598 + +3.6.18 (stable) / 2013-08-22 +=================== + + * updated; warn when using an unstable version of mongoose + * updated; mocha to 1.12.0 + * updated; mongodb driver to 1.3.19 (fix error swallowing behavior) + * fixed; setters not firing on null values #1445 [ebensing](https://github.com/ebensing) + * fixed; properly exclude subdocument fields #1280 [ebensing](https://github.com/ebensing) + * fixed; cast error in findAndModify #1643 [aheuermann](https://github.com/aheuermann) + * website; update guide + * website; added documentation for safe:false and versioning interaction + * docs; mention that middleware dont run on Models + * docs; fix indexes link + * make; suppress warning msg in test + * tests; moar + +3.6.17 / 2013-08-13 +=================== + + * updated; driver to 1.3.18 (fixes memory leak) + * fixed; casting ref docs on creation #1606 + * docs; query options + +3.6.16 / 2013-08-08 +=================== + + * added; publicly expose connection states #1585 + * fixed; limit applies to individual items on population #1490 [ebensing](https://github.com/ebensing) + * fixed; positional operator casting in updates #1572 [ebensing](https://github.com/ebensing) + * updated; MongoDB driver to 1.3.17 + * updated; sliced to 0.0.5 + * website; tweak homepage + * tests; fixed + added + * docs; fix some examples + * docs; multi-mongos support details + * docs; auto open browser after starting static server + +3.6.15 / 2013-07-16 +================== + + * added; mongos failover support #1037 + * updated; make schematype return vals return self #1580 + * docs; add note to model.update #571 + * docs; document third param to document.save callback #1536 + * tests; tweek mongos test timeout + +3.6.14 / 2013-07-05 +=================== + + * updated; driver to 1.3.11 + * fixed; issue with findOneAndUpdate not returning null on upserts #1533 [ebensing](https://github.com/ebensing) + * fixed; missing return statement in SchemaArray#$geoIntersects() #1498 [bsrykt](https://github.com/bsrykt) + * fixed; wrong isSelected() behavior #1521 [kyano](https://github.com/kyano) + * docs; note about toObject behavior during save() + * docs; add callbacks details #1547 [nikmartin](https://github.com/nikmartin) + +3.6.13 / 2013-06-27 +=================== + + * fixed; calling model.distinct without conditions #1541 + * fixed; regression in Query#count() #1542 + * now working on 3.6.13 + +3.6.12 / 2013-06-25 +=================== + + * updated; driver to 1.3.10 + * updated; clearer capped collection error message #1509 [bitmage](https://github.com/bitmage) + * fixed; MongooseBuffer subtype loss during casting #1517 [zedgu](https://github.com/zedgu) + * fixed; docArray#id when doc.id is disabled #1492 + * fixed; docArray#id now supports matches on populated arrays #1492 [pgherveou](https://github.com/pgherveou) + * website; fix example + * website; improve _id disabling example + * website; fix typo #1494 [dejj](https://github.com/dejj) + * docs; added a 'Requesting new features' section #1504 [shovon](https://github.com/shovon) + * docs; improve subtypes description + * docs; clarify _id disabling + * docs: display by alphabetical order the methods list #1508 [nicolasleger](https://github.com/nicolasleger) + * tests; refactor isSelected checks + * tests; remove pointless test + * tests; fixed timeouts + +3.6.11 / 2013-05-15 +=================== + + * updated; driver to 1.3.5 + * fixed; compat w/ Object.create(null) #1484 #1485 + * fixed; cloning objects w/ missing constructors + * fixed; prevent multiple min number validators #1481 [nrako](https://github.com/nrako) + * docs; add doc.increment() example + * docs; add $size example + * docs; add "distinct" example + +3.6.10 / 2013-05-09 +================== + + * update driver to 1.3.3 + * fixed; increment() works without other changes #1475 + * website; fix links to posterous + * docs; fix link #1472 + +3.6.9 / 2013-05-02 +================== + + * fixed; depopulation of mixed documents #1471 + * fixed; use of $options in array #1462 + * tests; fix race condition + * docs; fix default example + +3.6.8 / 2013-04-25 +================== + + * updated; driver to 1.3.0 + * fixed; connection.model should retain options #1458 [vedmalex](https://github.com/vedmalex) + * tests; 4-5 seconds faster + +3.6.7 / 2013-04-19 +================== + + * fixed; population regression in 3.6.6 #1444 + +3.6.6 / 2013-04-18 +================== + + * fixed; saving populated new documents #1442 + * fixed; population regession in 3.6.5 #1441 + * website; fix copyright #1439 + +3.6.5 / 2013-04-15 +================== + + * fixed; strict:throw edge case using .set(path, val) + * fixed; schema.pathType() on some numbericAlpha paths + * fixed; numbericAlpha path versioning + * fixed; setting nested mixed paths #1418 + * fixed; setting nested objects with null prop #1326 + * fixed; regression in v3.6 population performance #1426 [vedmalex](https://github.com/vedmalex) + * fixed; read pref typos #1422 [kyano](https://github.com/kyano) + * docs; fix method example + * website; update faq + * website; add more deep links + * website; update poolSize docs + * website; add 3.6 release notes + * website; note about keepAlive + +3.6.4 / 2013-04-03 +================== + + * fixed; +field conflict with $slice #1370 + * fixed; nested deselection conflict #1333 + * fixed; RangeError in ValidationError.toString() #1296 + * fixed; do not save user defined transforms #1415 + * tests; fix race condition + +3.6.3 / 2013-04-02 +================== + + * fixed; setting subdocuments deeply nested fields #1394 + * fixed; regression: populated streams #1411 + * docs; mention hooks/validation with findAndModify + * docs; mention auth + * docs; add more links + * examples; add document methods example + * website; display "see" links for properties + * website; clean up homepage + +3.6.2 / 2013-03-29 +================== + + * fixed; corrupted sub-doc array #1408 + * fixed; document#update returns a Query #1397 + * docs; readpref strategy + +3.6.1 / 2013-03-27 +================== + + * added; populate support to findAndModify varients #1395 + * added; text index type to schematypes + * expose allowed index types as Schema.indexTypes + * fixed; use of `setMaxListeners` as path + * fixed; regression in node 0.6 on docs with > 10 arrays + * fixed; do not alter schema arguments #1364 + * fixed; subdoc#ownerDocument() #1385 + * website; change search id + * website; add search from google [jackdbernier](https://github.com/jackdbernier) + * website; fix link + * website; add 3.5.x docs release + * website; fix link + * docs; fix geometry + * docs; hide internal constructor + * docs; aggregation does not cast arguments #1399 + * docs; querystream options + * examples; added for population + +3.6.0 / 2013-03-18 +================== + + * changed; cast 'true'/'false' to boolean #1282 [mgrach](https://github.com/mgrach) + * changed; Buffer arrays can now contain nulls + * added; QueryStream transform option + * added; support for authSource driver option + * added; {mongoose,db}.modelNames() + * added; $push w/ $slice,$sort support (MongoDB 2.4) + * added; hashed index type (MongoDB 2.4) + * added; support for mongodb 2.4 geojson (MongoDB 2.4) + * added; value at time of validation error + * added; support for object literal schemas + * added; bufferCommands schema option + * added; allow auth option in connections #1360 [geoah](https://github.com/geoah) + * added; performance improvements to populate() [263ece9](https://github.com/LearnBoost/mongoose/commit/263ece9) + * added; allow adding uncasted docs to populated arrays and properties #570 + * added; doc#populated(path) stores original populated _ids + * added; lean population #1260 + * added; query.populate() now accepts an options object + * added; document#populate(opts, callback) + * added; Model.populate(docs, opts, callback) + * added; support for rich nested path population + * added; doc.array.remove(value) subdoc with _id value support #1278 + * added; optionally allow non-strict sets and updates + * added; promises/A+ comformancy with [mpromise](https://github.com/aheckmann/mpromise) + * added; promise#then + * added; promise#end + * fixed; use of `model` as doc property + * fixed; lean population #1382 + * fixed; empty object mixed defaults #1380 + * fixed; populate w/ deselected _id using string syntax + * fixed; attempted save of divergent populated arrays #1334 related + * fixed; better error msg when attempting toObject as property name + * fixed; non population buffer casting from doc + * fixed; setting populated paths #570 + * fixed; casting when added docs to populated arrays #570 + * fixed; prohibit updating arrays selected with $elemMatch #1334 + * fixed; pull / set subdoc combination #1303 + * fixed; multiple bg index creation #1365 + * fixed; manual reconnection to single mongod + * fixed; Constructor / version exposure #1124 + * fixed; CastError race condition + * fixed; no longer swallowing misuse of subdoc#invalidate() + * fixed; utils.clone retains RegExp opts + * fixed; population of non-schema property + * fixed; allow updating versionKey #1265 + * fixed; add EventEmitter props to reserved paths #1338 + * fixed; can now deselect populated doc _ids #1331 + * fixed; properly pass subtype to Binary in MongooseBuffer + * fixed; casting _id from document with non-ObjectId _id + * fixed; specifying schema type edge case { path: [{type: "String" }] } + * fixed; typo in schemdate #1329 [jplock](https://github.com/jplock) + * updated; driver to 1.2.14 + * updated; muri to 0.3.1 + * updated; mpromise to 0.2.1 + * updated; mocha 1.8.1 + * updated; mpath to 0.1.1 + * deprecated; pluralization will die in 4.x + * refactor; rename private methods to something unusable as doc properties + * refactor MongooseArray#remove + * refactor; move expires index to SchemaDate #1328 + * refactor; internal document properties #1171 #1184 + * tests; added + * docs; indexes + * docs; validation + * docs; populate + * docs; populate + * docs; add note about stream compatibility with node 0.8 + * docs; fix for private names + * docs; Buffer -> mongodb.Binary #1363 + * docs; auth options + * docs; improved + * website; update FAQ + * website; add more api links + * website; add 3.5.x docs to prior releases + * website; Change mongoose-types to an active repo [jackdbernier](https://github.com/jackdbernier) + * website; compat with node 0.10 + * website; add news section + * website; use T for generic type + * benchmark; make adjustable + +3.6.0rc1 / 2013-03-12 +====================== + + * refactor; rename private methods to something unusable as doc properties + * added; {mongoose,db}.modelNames() + * added; $push w/ $slice,$sort support (MongoDB 2.4) + * added; hashed index type (MongoDB 2.4) + * added; support for mongodb 2.4 geojson (MongoDB 2.4) + * added; value at time of validation error + * added; support for object literal schemas + * added; bufferCommands schema option + * added; allow auth option in connections #1360 [geoah](https://github.com/geoah) + * fixed; lean population #1382 + * fixed; empty object mixed defaults #1380 + * fixed; populate w/ deselected _id using string syntax + * fixed; attempted save of divergent populated arrays #1334 related + * fixed; better error msg when attempting toObject as property name + * fixed; non population buffer casting from doc + * fixed; setting populated paths #570 + * fixed; casting when added docs to populated arrays #570 + * fixed; prohibit updating arrays selected with $elemMatch #1334 + * fixed; pull / set subdoc combination #1303 + * fixed; multiple bg index creation #1365 + * fixed; manual reconnection to single mongod + * fixed; Constructor / version exposure #1124 + * fixed; CastError race condition + * fixed; no longer swallowing misuse of subdoc#invalidate() + * fixed; utils.clone retains RegExp opts + * fixed; population of non-schema property + * fixed; allow updating versionKey #1265 + * fixed; add EventEmitter props to reserved paths #1338 + * fixed; can now deselect populated doc _ids #1331 + * updated; muri to 0.3.1 + * updated; driver to 1.2.12 + * updated; mpromise to 0.2.1 + * deprecated; pluralization will die in 4.x + * docs; Buffer -> mongodb.Binary #1363 + * docs; auth options + * docs; improved + * website; add news section + * benchmark; make adjustable + +3.6.0rc0 / 2013-02-03 +====================== + + * changed; cast 'true'/'false' to boolean #1282 [mgrach](https://github.com/mgrach) + * changed; Buffer arrays can now contain nulls + * fixed; properly pass subtype to Binary in MongooseBuffer + * fixed; casting _id from document with non-ObjectId _id + * fixed; specifying schema type edge case { path: [{type: "String" }] } + * fixed; typo in schemdate #1329 [jplock](https://github.com/jplock) + * refactor; move expires index to SchemaDate #1328 + * refactor; internal document properties #1171 #1184 + * added; performance improvements to populate() [263ece9](https://github.com/LearnBoost/mongoose/commit/263ece9) + * added; allow adding uncasted docs to populated arrays and properties #570 + * added; doc#populated(path) stores original populated _ids + * added; lean population #1260 + * added; query.populate() now accepts an options object + * added; document#populate(opts, callback) + * added; Model.populate(docs, opts, callback) + * added; support for rich nested path population + * added; doc.array.remove(value) subdoc with _id value support #1278 + * added; optionally allow non-strict sets and updates + * added; promises/A+ comformancy with [mpromise](https://github.com/aheckmann/mpromise) + * added; promise#then + * added; promise#end + * updated; mocha 1.8.1 + * updated; muri to 0.3.0 + * updated; mpath to 0.1.1 + * updated; docs + +3.5.16 / 2013-08-13 +=================== + + * updated; driver to 1.3.18 + +3.5.15 / 2013-07-26 +================== + + * updated; sliced to 0.0.5 + * updated; driver to 1.3.12 + * fixed; regression in Query#count() due to driver change + * tests; fixed timeouts + * tests; handle differing test uris + +3.5.14 / 2013-05-15 +=================== + + * updated; driver to 1.3.5 + * fixed; compat w/ Object.create(null) #1484 #1485 + * fixed; cloning objects missing constructors + * fixed; prevent multiple min number validators #1481 [nrako](https://github.com/nrako) + +3.5.13 / 2013-05-09 +================== + + * update driver to 1.3.3 + * fixed; use of $options in array #1462 + +3.5.12 / 2013-04-25 +=================== + + * updated; driver to 1.3.0 + * fixed; connection.model should retain options #1458 [vedmalex](https://github.com/vedmalex) + * fixed; read pref typos #1422 [kyano](https://github.com/kyano) + +3.5.11 / 2013-04-03 +================== + + * fixed; +field conflict with $slice #1370 + * fixed; RangeError in ValidationError.toString() #1296 + * fixed; nested deselection conflict #1333 + * remove time from Makefile + +3.5.10 / 2013-04-02 +================== + + * fixed; setting subdocuments deeply nested fields #1394 + * fixed; do not alter schema arguments #1364 + +3.5.9 / 2013-03-15 +================== + + * updated; driver to 1.2.14 + * added; support for authSource driver option (mongodb 2.4) + * added; QueryStream transform option (node 0.10 helper) + * fixed; backport for saving required populated buffers + * fixed; pull / set subdoc combination #1303 + * fixed; multiple bg index creation #1365 + * test; added for saveable required populated buffers + * test; added for #1365 + * test; add authSource test + +3.5.8 / 2013-03-12 +================== + + * added; auth option in connection [geoah](https://github.com/geoah) + * fixed; CastError race condition + * docs; add note about stream compatibility with node 0.8 + +3.5.7 / 2013-02-22 +================== + + * updated; driver to 1.2.13 + * updated; muri to 0.3.1 #1347 + * fixed; utils.clone retains RegExp opts #1355 + * fixed; deepEquals RegExp support + * tests; fix a connection test + * website; clean up docs [afshinm](https://github.com/afshinm) + * website; update homepage + * website; migragtion: emphasize impact of strict docs #1264 + +3.5.6 / 2013-02-14 +================== + + * updated; driver to 1.2.12 + * fixed; properly pass Binary subtype + * fixed; add EventEmitter props to reserved paths #1338 + * fixed; use correct node engine version + * fixed; display empty docs as {} in log output #953 follow up + * improved; "bad $within $box argument" error message + * populate; add unscientific benchmark + * website; add stack overflow to help section + * website; use better code font #1336 [risseraka](https://github.com/risseraka) + * website; clarify where help is available + * website; fix source code links #1272 [floatingLomas](https://github.com/floatingLomas) + * docs; be specific about _id schema option #1103 + * docs; add ensureIndex error handling example + * docs; README + * docs; CONTRIBUTING.md + +3.5.5 / 2013-01-29 +================== + + * updated; driver to 1.2.11 + * removed; old node < 0.6x shims + * fixed; documents with Buffer _ids equality + * fixed; MongooseBuffer properly casts numbers + * fixed; reopening closed connection on alt host/port #1287 + * docs; fixed typo in Readme #1298 [rened](https://github.com/rened) + * docs; fixed typo in migration docs [Prinzhorn](https://github.com/Prinzhorn) + * docs; fixed incorrect annotation in SchemaNumber#min [bilalq](https://github.com/bilalq) + * docs; updated + +3.5.4 / 2013-01-07 +================== + + * changed; "_pres" & "_posts" are now reserved pathnames #1261 + * updated; driver to 1.2.8 + * fixed; exception when reopening a replica set. #1263 [ethankan](https://github.com/ethankan) + * website; updated + +3.5.3 / 2012-12-26 +================== + + * added; support for geo object notation #1257 + * fixed; $within query casting with arrays + * fixed; unix domain socket support #1254 + * updated; driver to 1.2.7 + * updated; muri to 0.0.5 + +3.5.2 / 2012-12-17 +================== + + * fixed; using auth with replica sets #1253 + +3.5.1 / 2012-12-12 +================== + + * fixed; regression when using subdoc with `path` as pathname #1245 [daeq](https://github.com/daeq) + * fixed; safer db option checks + * updated; driver to 1.2.5 + * website; add more examples + * website; clean up old docs + * website; fix prev release urls + * docs; clarify streaming with HTTP responses + +3.5.0 / 2012-12-10 +================== + + * added; paths to CastErrors #1239 + * added; support for mongodb connection string spec #1187 + * added; post validate event + * added; Schema#get (to retrieve schema options) + * added; VersionError #1071 + * added; npmignore [hidekiy](https://github.com/hidekiy) + * update; driver to 1.2.3 + * fixed; stackoverflow in setter #1234 + * fixed; utils.isObject() + * fixed; do not clobber user specified driver writeConcern #1227 + * fixed; always pass current document to post hooks + * fixed; throw error when user attempts to overwrite a model + * fixed; connection.model only caches on connection #1209 + * fixed; respect conn.model() creation when matching global model exists #1209 + * fixed; passing model name + collection name now always honors collection name + * fixed; setting virtual field to an empty object #1154 + * fixed; subclassed MongooseErrors exposure, now available in mongoose.Error.xxxx + * fixed; model.remove() ignoring callback when executed twice [daeq](https://github.com/daeq) #1210 + * docs; add collection option to schema api docs #1222 + * docs; NOTE about db safe options + * docs; add post hooks docs + * docs; connection string options + * docs; middleware is not executed with Model.remove #1241 + * docs; {g,s}etter introspection #777 + * docs; update validation docs + * docs; add link to plugins page + * docs; clarify error returned by unique indexes #1225 + * docs; more detail about disabling autoIndex behavior + * docs; add homepage section to package (npm docs mongoose) + * docs; more detail around collection name pluralization #1193 + * website; add .important css + * website; update models page + * website; update getting started + * website; update quick start + +3.4.0 / 2012-11-10 +================== + + * added; support for generic toJSON/toObject transforms #1160 #1020 #1197 + * added; doc.set() merge support #1148 [NuORDER](https://github.com/NuORDER) + * added; query#add support #1188 [aleclofabbro](https://github.com/aleclofabbro) + * changed; adding invalid nested paths to non-objects throws 4216f14 + * changed; fixed; stop invalid function cloning (internal fix) + * fixed; add query $and casting support #1180 [anotheri](https://github.com/anotheri) + * fixed; overwriting of query arguments #1176 + * docs; fix expires examples + * docs; transforms + * docs; schema `collection` option docs [hermanjunge](https://github.com/hermanjunge) + * website; updated + * tests; added + +3.3.1 / 2012-10-11 +================== + + * fixed; allow goose.connect(uris, dbname, opts) #1144 + * docs; persist API private checked state across page loads + +3.3.0 / 2012-10-10 +================== + + * fixed; passing options as 2nd arg to connect() #1144 + * fixed; race condition after no-op save #1139 + * fixed; schema field selection application in findAndModify #1150 + * fixed; directly setting arrays #1126 + * updated; driver to 1.1.11 + * updated; collection pluralization rules [mrickard](https://github.com/mrickard) + * tests; added + * docs; updated + +3.2.2 / 2012-10-08 +================== + + * updated; driver to 1.1.10 #1143 + * updated; use sliced 0.0.3 + * fixed; do not recast embedded docs unnecessarily + * fixed; expires schema option helper #1132 + * fixed; built in string setters #1131 + * fixed; debug output for Dates/ObjectId properties #1129 + * docs; fixed Javascript syntax error in example [olalonde](https://github.com/olalonde) + * docs; fix toJSON example #1137 + * docs; add ensureIndex production notes + * docs; fix spelling + * docs; add blogposts about v3 + * website; updated + * removed; undocumented inGroupsOf util + * tests; added + +3.2.1 / 2012-09-28 +================== + + * fixed; remove query batchSize option default of 1000 https://github.com/learnboost/mongoose/commit/3edaa8651 + * docs; updated + * website; updated + +3.2.0 / 2012-09-27 +================== + + * added; direct array index assignment with casting support `doc.array.set(index, value)` + * fixed; QueryStream#resume within same tick as pause() #1116 + * fixed; default value validatation #1109 + * fixed; array splice() not casting #1123 + * fixed; default array construction edge case #1108 + * fixed; query casting for inequalities in arrays #1101 [dpatti](https://github.com/dpatti) + * tests; added + * website; more documentation + * website; fixed layout issue #1111 [SlashmanX](https://github.com/SlashmanX) + * website; refactored [guille](https://github.com/guille) + +3.1.2 / 2012-09-10 +================== + + * added; ReadPreferrence schema option #1097 + * updated; driver to 1.1.7 + * updated; default query batchSize to 1000 + * fixed; we now cast the mapReduce query option #1095 + * fixed; $elemMatch+$in with field selection #1091 + * fixed; properly cast $elemMatch+$in conditions #1100 + * fixed; default field application of subdocs #1027 + * fixed; querystream prematurely dying #1092 + * fixed; querystream never resumes when paused at getMore boundries #1092 + * fixed; querystream occasionally emits data events after destroy #1092 + * fixed; remove unnecessary ObjectId creation in querystream + * fixed; allow ne(boolean) again #1093 + * docs; add populate/field selection syntax notes + * docs; add toObject/toJSON options detail + * docs; `read` schema option + +3.1.1 / 2012-08-31 +================== + + * updated; driver to 1.1.6 + +3.1.0 / 2012-08-29 +================== + + * changed; fixed; directly setting nested objects now overwrites entire object (previously incorrectly merged them) + * added; read pref support (mongodb 2.2) 205a709c + * added; aggregate support (mongodb 2.2) f3a5bd3d + * added; virtual {g,s}etter introspection (#1070) + * updated; docs [brettz9](https://github.com/brettz9) + * updated; driver to 1.1.5 + * fixed; retain virtual setter return values (#1069) + +3.0.3 / 2012-08-23 +================== + + * fixed; use of nested paths beginning w/ numbers #1062 + * fixed; query population edge case #1053 #1055 [jfremy](https://github.com/jfremy) + * fixed; simultaneous top and sub level array modifications #1073 + * added; id and _id schema option aliases + tests + * improve debug formatting to allow copy/paste logged queries into mongo shell [eknkc](https://github.com/eknkc) + * docs + +3.0.2 / 2012-08-17 +================== + + * added; missing support for v3 sort/select syntax to findAndModify helpers (#1058) + * fixed; replset fullsetup event emission + * fixed; reconnected event for replsets + * fixed; server reconnection setting discovery + * fixed; compat with non-schema path props using positional notation (#1048) + * fixed; setter/casting order (#665) + * docs; updated + +3.0.1 / 2012-08-11 +================== + + * fixed; throw Error on bad validators (1044) + * fixed; typo in EmbeddedDocument#parentArray [lackac] + * fixed; repair mongoose.SchemaTypes alias + * updated; docs + +3.0.0 / 2012-08-07 +================== + + * removed; old subdocument#commit method + * fixed; setting arrays of matching docs [6924cbc2] + * fixed; doc!remove event now emits in save order as save for consistency + * fixed; pre-save hooks no longer fire on subdocuments when validation fails + * added; subdoc#parent() and subdoc#parentArray() to access subdocument parent objects + * added; query#lean() helper + +3.0.0rc0 / 2012-08-01 +===================== + + * fixed; allow subdoc literal declarations containing "type" pathname (#993) + * fixed; unsetting a default array (#758) + * fixed; boolean $in queries (#998) + * fixed; allow use of `options` as a pathname (#529) + * fixed; `model` is again a permitted schema path name + * fixed; field selection option on subdocs (#1022) + * fixed; handle another edge case with subdoc saving (#975) + * added; emit save err on model if listening + * added; MongoDB TTL collection support (#1006) + * added; $center options support + * added; $nearSphere and $polygon support + * updated; driver version to 1.1.2 + +3.0.0alpha2 / 2012-07-18 +========================= + + * changed; index errors are now emitted on their model and passed to an optional callback (#984) + * fixed; specifying index along with sparse/unique option no longer overwrites (#1004) + * fixed; never swallow connection errors (#618) + * fixed; creating object from model with emded object no longer overwrites defaults [achurkin] (#859) + * fixed; stop needless validation of unchanged/unselected fields (#891) + * fixed; document#equals behavior of objectids (#974) + * fixed; honor the minimize schema option (#978) + * fixed; provide helpful error msgs when reserved schema path is used (#928) + * fixed; callback to conn#disconnect is optional (#875) + * fixed; handle missing protocols in connection urls (#987) + * fixed; validate args to query#where (#969) + * fixed; saving modified/removed subdocs (#975) + * fixed; update with $pull from Mixed array (#735) + * fixed; error with null shard key value + * fixed; allow unsetting enums (#967) + * added; support for manual index creation (#984) + * added; support for disabled auto-indexing (#984) + * added; support for preserving MongooseArray#sort changes (#752) + * added; emit state change events on connection + * added; support for specifying BSON subtype in MongooseBuffer#toObject [jcrugzz] + * added; support for disabled versioning (#977) + * added; implicit "new" support for models and Schemas + +3.0.0alpha1 / 2012-06-15 +========================= + + * removed; doc#commit (use doc#markModified) + * removed; doc.modified getter (#950) + * removed; mongoose{connectSet,createSetConnection}. use connect,createConnection instead + * removed; query alias methods 1149804c + * removed; MongooseNumber + * changed; now creating indexes in background by default + * changed; strict mode now enabled by default (#952) + * changed; doc#modifiedPaths is now a method (#950) + * changed; getters no longer cast (#820); casting happens during set + * fixed; no need to pass updateArg to findOneAndUpdate (#931) + * fixed: utils.merge bug when merging nested non-objects. [treygriffith] + * fixed; strict:throw should produce errors in findAndModify (#963) + * fixed; findAndUpdate no longer overwrites document (#962) + * fixed; setting default DocumentArrays (#953) + * fixed; selection of _id with schema deselection (#954) + * fixed; ensure promise#error emits instanceof Error + * fixed; CursorStream: No stack overflow on any size result (#929) + * fixed; doc#remove now passes safe options + * fixed; invalid use of $set during $pop + * fixed; array#{$pop,$shift} mirror MongoDB behavior + * fixed; no longer test non-required vals in string match (#934) + * fixed; edge case with doc#inspect + * fixed; setter order (#665) + * fixed; setting invalid paths in strict mode (#916) + * fixed; handle docs without id in DocumentArray#id method (#897) + * fixed; do not save virtuals during model.update (#894) + * fixed; sub doc toObject virtuals application (#889) + * fixed; MongooseArray#pull of ObjectId (#881) + * fixed; handle passing db name with any repl set string + * fixed; default application of selected fields (#870) + * fixed; subdoc paths reported in validation errors (#725) + * fixed; incorrect reported num of affected docs in update ops (#862) + * fixed; connection assignment in Model#model (#853) + * fixed; stringifying arrays of docs (#852) + * fixed; modifying subdoc and parent array works (#842) + * fixed; passing undefined to next hook (#785) + * fixed; Query#{update,remove}() works without callbacks (#788) + * fixed; set/updating nested objects by parent pathname (#843) + * fixed; allow null in number arrays (#840) + * fixed; isNew on sub doc after insertion error (#837) + * fixed; if an insert fails, set isNew back to false [boutell] + * fixed; isSelected when only _id is selected (#730) + * fixed; setting an unset default value (#742) + * fixed; query#sort error messaging (#671) + * fixed; support for passing $options with $regex + * added; array of object literal notation in schema creates DocumentArrays + * added; gt,gte,lt,lte query support for arrays (#902) + * added; capped collection support (#938) + * added; document versioning support + * added; inclusion of deselected schema path (#786) + * added; non-atomic array#pop + * added; EmbeddedDocument constructor is now exposed in DocArray#create 7cf8beec + * added; mapReduce support (#678) + * added; support for a configurable minimize option #to{Object,JSON}(option) (#848) + * added; support for strict: `throws` [regality] + * added; support for named schema types (#795) + * added; to{Object,JSON} schema options (#805) + * added; findByIdAnd{Update,Remove}() + * added; findOneAnd{Update,Remove}() + * added; query.setOptions() + * added; instance.update() (#794) + * added; support specifying model in populate() [DanielBaulig] + * added; `lean` query option [gitfy] + * added; multi-atomic support to MongooseArray#nonAtomicPush + * added; support for $set + other $atomic ops on single array + * added; tests + * updated; driver to 1.0.2 + * updated; query.sort() syntax to mirror query.select() + * updated; clearer cast error msg for array numbers + * updated; docs + * updated; doc.clone 3x faster (#950) + * updated; only create _id if necessary (#950) + +2.7.3 / 2012-08-01 +================== + + * fixed; boolean $in queries (#998) + * fixed field selection option on subdocs (#1022) + +2.7.2 / 2012-07-18 +================== + + * fixed; callback to conn#disconnect is optional (#875) + * fixed; handle missing protocols in connection urls (#987) + * fixed; saving modified/removed subdocs (#975) + * updated; tests + +2.7.1 / 2012-06-26 +=================== + + * fixed; sharding: when a document holds a null as a value of the shard key + * fixed; update() using $pull on an array of Mixed (gh-735) + * deprecated; MongooseNumber#{inc, increment, decrement} methods + * tests; now using mocha + +2.7.0 / 2012-06-14 +=================== + + * added; deprecation warnings to methods being removed in 3.x + +2.6.8 / 2012-06-14 +=================== + + * fixed; edge case when using 'options' as a path name (#961) + +2.6.7 / 2012-06-08 +=================== + + * fixed; ensure promise#error always emits instanceof Error + * fixed; selection of _id w/ another excluded path (#954) + * fixed; setting default DocumentArrays (#953) + +2.6.6 / 2012-06-06 +=================== + + * fixed; stack overflow in query stream with large result sets (#929) + * added; $gt, $gte, $lt, $lte support to arrays (#902) + * fixed; pass option `safe` along to doc#remove() calls + +2.6.5 / 2012-05-24 +=================== + + * fixed; do not save virtuals in Model.update (#894) + * added; missing $ prefixed query aliases (going away in 3.x) (#884) [timoxley] + * fixed; setting invalid paths in strict mode (#916) + * fixed; resetting isNew after insert failure (#837) [boutell] + +2.6.4 / 2012-05-15 +=================== + + * updated; backport string regex $options to 2.x + * updated; use driver 1.0.2 (performance improvements) (#914) + * fixed; calling MongooseDocumentArray#id when the doc has no _id (#897) + +2.6.3 / 2012-05-03 +=================== + + * fixed; repl-set connectivity issues during failover on MongoDB 2.0.1 + * updated; driver to 1.0.0 + * fixed; virtuals application of subdocs when using toObject({ virtuals: true }) (#889) + * fixed; MongooseArray#pull of ObjectId correctly updates the array itself (#881) + +2.6.2 / 2012-04-30 +=================== + + * fixed; default field application of selected fields (#870) + +2.6.1 / 2012-04-30 +=================== + + * fixed; connection assignment in mongoose#model (#853, #877) + * fixed; incorrect reported num of affected docs in update ops (#862) + +2.6.0 / 2012-04-19 +=================== + + * updated; hooks.js to 0.2.1 + * fixed; issue with passing undefined to a hook callback. thanks to [chrisleishman] for reporting. + * fixed; updating/setting nested objects in strict schemas (#843) as reported by [kof] + * fixed; Query#{update,remove}() work without callbacks again (#788) + * fixed; modifying subdoc along with parent array $atomic op (#842) + +2.5.14 / 2012-04-13 +=================== + + * fixed; setting an unset default value (#742) + * fixed; doc.isSelected(otherpath) when only _id is selected (#730) + * updated; docs + +2.5.13 / 2012-03-22 +=================== + + * fixed; failing validation of unselected required paths (#730,#713) + * fixed; emitting connection error when only one listener (#759) + * fixed; MongooseArray#splice was not returning values (#784) [chrisleishman] + +2.5.12 / 2012-03-21 +=================== + + * fixed; honor the `safe` option in all ensureIndex calls + * updated; node-mongodb-native driver to 0.9.9-7 + +2.5.11 / 2012-03-15 +=================== + + * added; introspection for getters/setters (#745) + * updated; node-mongodb-driver to 0.9.9-5 + * added; tailable method to Query (#769) [holic] + * fixed; Number min/max validation of null (#764) [btamas] + * added; more flexible user/password connection options (#738) [KarneAsada] + +2.5.10 / 2012-03-06 +=================== + + * updated; node-mongodb-native driver to 0.9.9-4 + * added; Query#comment() + * fixed; allow unsetting arrays + * fixed; hooking the set method of subdocuments (#746) + * fixed; edge case in hooks + * fixed; allow $id and $ref in queries (fixes compatibility with mongoose-dbref) (#749) [richtera] + * added; default path selection to SchemaTypes + +2.5.9 / 2012-02-22 +=================== + + * fixed; properly cast nested atomic update operators for sub-documents + +2.5.8 / 2012-02-21 +=================== + + * added; post 'remove' middleware includes model that was removed (#729) [timoxley] + +2.5.7 / 2012-02-09 +=================== + + * fixed; RegExp validators on node >= v0.6.x + +2.5.6 / 2012-02-09 +=================== + + * fixed; emit errors returned from db.collection() on the connection (were being swallowed) + * added; can add multiple validators in your schema at once (#718) [diogogmt] + * fixed; strict embedded documents (#717) + * updated; docs [niemyjski] + * added; pass number of affected docs back in model.update/save + +2.5.5 / 2012-02-03 +=================== + + * fixed; RangeError: maximum call stack exceed error when removing docs with Number _id (#714) + +2.5.4 / 2012-02-03 +=================== + + * fixed; RangeError: maximum call stack exceed error (#714) + +2.5.3 / 2012-02-02 +=================== + + * added; doc#isSelected(path) + * added; query#equals() + * added; beta sharding support + * added; more descript error msgs (#700) [obeleh] + * added; document.modifiedPaths (#709) [ljharb] + * fixed; only functions can be added as getters/setters (#707,704) [ljharb] + +2.5.2 / 2012-01-30 +=================== + + * fixed; rollback -native driver to 0.9.7-3-5 (was causing timeouts and other replica set weirdness) + * deprecated; MongooseNumber (will be moved to a separate repo for 3.x) + * added; init event is emitted on schemas + +2.5.1 / 2012-01-27 +=================== + + * fixed; honor strict schemas in Model.update (#699) + +2.5.0 / 2012-01-26 +=================== + + * added; doc.toJSON calls toJSON on embedded docs when exists [jerem] + * added; populate support for refs of type Buffer (#686) [jerem] + * added; $all support for ObjectIds and Dates (#690) + * fixed; virtual setter calling on instantiation when strict: true (#682) [hunterloftis] + * fixed; doc construction triggering getters (#685) + * fixed; MongooseBuffer check in deepEquals (#688) + * fixed; range error when using Number _ids with `instance.save()` (#691) + * fixed; isNew on embedded docs edge case (#680) + * updated; driver to 0.9.8-3 + * updated; expose `model()` method within static methods + +2.4.10 / 2012-01-10 +=================== + + * added; optional getter application in .toObject()/.toJSON() (#412) + * fixed; nested $operators in $all queries (#670) + * added; $nor support (#674) + * fixed; bug when adding nested schema (#662) [paulwe] + +2.4.9 / 2012-01-04 +=================== + + * updated; driver to 0.9.7-3-5 to fix Linux performance degradation on some boxes + +2.4.8 / 2011-12-22 +=================== + + * updated; bump -native to 0.9.7.2-5 + * fixed; compatibility with date.js (#646) [chrisleishman] + * changed; undocumented schema "lax" option to "strict" + * fixed; default value population for strict schemas + * updated; the nextTick helper for small performance gain. 1bee2a2 + +2.4.7 / 2011-12-16 +=================== + + * fixed; bug in 2.4.6 with path setting + * updated; bump -native to 0.9.7.2-1 + * added; strict schema option [nw] + +2.4.6 / 2011-12-16 +=================== + + * fixed; conflicting mods on update bug [sirlantis] + * improved; doc.id getter performance + +2.4.5 / 2011-12-14 +=================== + + * fixed; bad MongooseArray behavior in 2.4.2 - 2.4.4 + +2.4.4 / 2011-12-14 +=================== + + * fixed; MongooseArray#doAtomics throwing after sliced + +2.4.3 / 2011-12-14 +=================== + + * updated; system.profile schema for MongoDB 2x + +2.4.2 / 2011-12-12 +=================== + + * fixed; partially populating multiple children of subdocs (#639) [kenpratt] + * fixed; allow Update of numbers to null (#640) [jerem] + +2.4.1 / 2011-12-02 +=================== + + * added; options support for populate() queries + * updated; -native driver to 0.9.7-1.4 + +2.4.0 / 2011-11-29 +=================== + + * added; QueryStreams (#614) + * added; debug print mode for development + * added; $within support to Array queries (#586) [ggoodale] + * added; $centerSphere query support + * fixed; $within support + * added; $unset is now used when setting a path to undefined (#519) + * added; query#batchSize support + * updated; docs + * updated; -native driver to 0.9.7-1.3 (provides Windows support) + +2.3.13 / 2011-11-15 +=================== + + * fixed; required validation for Refs (#612) [ded] + * added; $nearSphere support for Arrays (#610) + +2.3.12 / 2011-11-09 +=================== + + * fixed; regression, objects passed to Model.update should not be changed (#605) + * fixed; regression, empty Model.update should not be executed + +2.3.11 / 2011-11-08 +=================== + + * fixed; using $elemMatch on arrays of Mixed types (#591) + * fixed; allow using $regex when querying Arrays (#599) + * fixed; calling Model.update with no atomic keys (#602) + +2.3.10 / 2011-11-05 +=================== + + * fixed; model.update casting for nested paths works (#542) + +2.3.9 / 2011-11-04 +================== + + * fixed; deepEquals check for MongooseArray returned false + * fixed; reset modified flags of embedded docs after save [gitfy] + * fixed; setting embedded doc with identical values no longer marks modified [gitfy] + * updated; -native driver to 0.9.6.23 [mlazarov] + * fixed; Model.update casting (#542, #545, #479) + * fixed; populated refs no longer fail required validators (#577) + * fixed; populating refs of objects with custom ids works + * fixed; $pop & $unset work with Model.update (#574) + * added; more helpful debugging message for Schema#add (#578) + * fixed; accessing .id when no _id exists now returns null (#590) + +2.3.8 / 2011-10-26 +================== + + * added; callback to query#findOne is now optional (#581) + +2.3.7 / 2011-10-24 +================== + + * fixed; wrapped save/remove callbacks in nextTick to mitigate -native swallowing thrown errors + +2.3.6 / 2011-10-21 +================== + + * fixed; exclusion of embedded doc _id from query results (#541) + +2.3.5 / 2011-10-19 +================== + + * fixed; calling queries without passing a callback works (#569) + * fixed; populate() works with String and Number _ids too (#568) + +2.3.4 / 2011-10-18 +================== + + * added; Model.create now accepts an array as a first arg + * fixed; calling toObject on a DocumentArray with nulls no longer throws + * fixed; calling inspect on a DocumentArray with nulls no longer throws + * added; MongooseArray#unshift support + * fixed; save hooks now fire on embedded documents [gitfy] (#456) + * updated; -native driver to 0.9.6-22 + * fixed; correctly pass $addToSet op instead of $push + * fixed; $addToSet properly detects dates + * fixed; $addToSet with multiple items works + * updated; better node 0.6 Buffer support + +2.3.3 / 2011-10-12 +================== + + * fixed; population conditions in multi-query settings [vedmalex] (#563) + * fixed; now compatible with Node v0.5.x + +2.3.2 / 2011-10-11 +================== + + * fixed; population of null subdoc properties no longer hangs (#561) + +2.3.1 / 2011-10-10 +================== + + * added; support for Query filters to populate() [eneko] + * fixed; querying with number no longer crashes mongodb (#555) [jlbyrey] + * updated; version of -native driver to 0.9.6-21 + * fixed; prevent query callbacks that throw errors from corrupting -native connection state + +2.3.0 / 2011-10-04 +================== + + * fixed; nulls as default values for Boolean now works as expected + * updated; version of -native driver to 0.9.6-20 + +2.2.4 / 2011-10-03 +================== + + * fixed; populate() works when returned array contains undefined/nulls + +2.2.3 / 2011-09-29 +================== + + * updated; version of -native driver to 0.9.6-19 + +2.2.2 / 2011-09-28 +================== + + * added; $regex support to String [davidandrewcope] + * added; support for other contexts like repl etc (#535) + * fixed; clear modified state properly after saving + * added; $addToSet support to Array + +2.2.1 / 2011-09-22 +================== + + * more descript error when casting undefined to string + * updated; version of -native driver to 0.9.6-18 + +2.2.0 / 2011-09-22 +================== + + * fixed; maxListeners warning on schemas with many arrays (#530) + * changed; return / apply defaults based on fields selected in query (#423) + * fixed; correctly detect Mixed types within schema arrays (#532) + +2.1.4 / 2011-09-20 +================== + + * fixed; new private methods that stomped on users code + * changed; finished removing old "compat" support which did nothing + +2.1.3 / 2011-09-16 +================== + + * updated; version of -native driver to 0.9.6-15 + * added; emit `error` on connection when open fails [edwardhotchkiss] + * added; index support to Buffers (thanks justmoon for helping track this down) + * fixed; passing collection name via schema in conn.model() now works (thanks vedmalex for reporting) + +2.1.2 / 2011-09-07 +================== + + * fixed; Query#find with no args no longer throws + +2.1.1 / 2011-09-07 +================== + + * added; support Model.count(fn) + * fixed; compatibility with node >=0.4.0 < 0.4.3 + * added; pass model.options.safe through with .save() so w:2, wtimeout:5000 options work [andrewjstone] + * added; support for $type queries + * added; support for Query#or + * added; more tests + * optimized populate queries + +2.1.0 / 2011-09-01 +================== + + * changed; document#validate is a public method + * fixed; setting number to same value no longer marks modified (#476) [gitfy] + * fixed; Buffers shouldn't have default vals + * added; allow specifying collection name in schema (#470) [ixti] + * fixed; reset modified paths and atomics after saved (#459) + * fixed; set isNew on embedded docs to false after save + * fixed; use self to ensure proper scope of options in doOpenSet (#483) [andrewjstone] + +2.0.4 / 2011-08-29 +================== + + * Fixed; Only send the depopulated ObjectId instead of the entire doc on save (DBRefs) + * Fixed; Properly cast nested array values in Model.update (the data was stored in Mongo incorrectly but recast on document fetch was "fixing" it) + +2.0.3 / 2011-08-28 +================== + + * Fixed; manipulating a populated array no longer causes infinite loop in BSON serializer during save (#477) + * Fixed; populating an empty array no longer hangs foreeeeeeeever (#481) + +2.0.2 / 2011-08-25 +================== + + * Fixed; Maintain query option key order (fixes 'bad hint' error from compound query hints) + +2.0.1 / 2011-08-25 +================== + + * Fixed; do not over-write the doc when no valide props exist in Model.update (#473) + +2.0.0 / 2011-08-24 +=================== + + * Added; support for Buffers [justmoon] + * Changed; improved error handling [maelstrom] + * Removed: unused utils.erase + * Fixed; support for passing other context object into Schemas (#234) [Sija] + * Fixed; getters are no longer circular refs to themselves (#366) + * Removed; unused compat.js + * Fixed; getter/setter scopes are set properly + * Changed; made several private properties more obvious by prefixing _ + * Added; DBRef support [guille] + * Changed; removed support for multiple collection names per model + * Fixed; no longer applying setters when document returned from db + * Changed; default auto_reconnect to true + * Changed; Query#bind no longer clones the query + * Fixed; Model.update now accepts $pull, $inc and friends (#404) + * Added; virtual type option support [nw] + +1.8.4 / 2011-08-21 +=================== + + * Fixed; validation bug when instantiated with non-schema properties (#464) [jmreidy] + +1.8.3 / 2011-08-19 +=================== + + * Fixed; regression in connection#open [jshaw86] + +1.8.2 / 2011-08-17 +=================== + + * fixed; reset connection.readyState after failure [tomseago] + * fixed; can now query positionally for non-embedded docs (arrays of numbers/strings etc) + * fixed; embedded document query casting + * added; support for passing options to node-mongo-native db, server, and replsetserver [tomseago] + +1.8.1 / 2011-08-10 +=================== + + * fixed; ObjectIds were always marked modified + * fixed; can now query using document instances + * fixed; can now query/update using documents with subdocs + +1.8.0 / 2011-08-04 +=================== + + * fixed; can now use $all with String and Number + * fixed; can query subdoc array with $ne: null + * fixed; instance.subdocs#id now works with custom _ids + * fixed; do not apply setters when doc returned from db (change in bad behavior) + +1.7.4 / 2011-07-25 +=================== + + * fixed; sparse now a valid seperate schema option + * fixed; now catching cast errors in queries + * fixed; calling new Schema with object created in vm.runInNewContext now works (#384) [Sija] + * fixed; String enum was disallowing null + * fixed; Find by nested document _id now works (#389) + +1.7.3 / 2011-07-16 +=================== + + * fixed; MongooseArray#indexOf now works with ObjectIds + * fixed; validation scope now set properly (#418) + * fixed; added missing colors dependency (#398) + +1.7.2 / 2011-07-13 +=================== + + * changed; node-mongodb-native driver to v0.9.6.7 + +1.7.1 / 2011-07-12 +=================== + + * changed; roll back node-mongodb-native driver to v0.9.6.4 + +1.7.0 / 2011-07-12 +=================== + + * fixed; collection name misspelling [mathrawka] + * fixed; 2nd param is required for ReplSetServers [kevinmarvin] + * fixed; MongooseArray behaves properly with Object.keys + * changed; node-mongodb-native driver to v0.9.6.6 + * fixed/changed; Mongodb segfault when passed invalid ObjectId (#407) + - This means invalid data passed to the ObjectId constructor will now error + +1.6.0 / 2011-07-07 +=================== + + * changed; .save() errors are now emitted on the instances db instead of the instance 9782463fc + * fixed; errors occurring when creating indexes now properly emit on db + * added; $maxDistance support to MongooseArrays + * fixed; RegExps now work with $all + * changed; node-mongodb-native driver to v0.9.6.4 + * fixed; model names are now accessible via .modelName + * added; Query#slaveOk support + +1.5.0 / 2011-06-27 +=================== + + * changed; saving without a callback no longer ignores the error (@bnoguchi) + * changed; hook-js version bump to 0.1.9 + * changed; node-mongodb-native version bumped to 0.9.6.1 - When .remove() doesn't + return an error, null is no longer passed. + * fixed; two memory leaks (@justmoon) + * added; sparse index support + * added; more ObjectId conditionals (gt, lt, gte, lte) (@phillyqueso) + * added; options are now passed in model#remote (@JerryLuke) + +1.4.0 / 2011-06-10 +=================== + + * bumped hooks-js dependency (fixes issue passing null as first arg to next()) + * fixed; document#inspect now works properly with nested docs + * fixed; 'set' now works as a schema attribute (GH-365) + * fixed; _id is now set properly within pre-init hooks (GH-289) + * added; Query#distinct / Model#distinct support (GH-155) + * fixed; embedded docs now can use instance methods (GH-249) + * fixed; can now overwrite strings conflicting with schema type + +1.3.7 / 2011-06-03 +=================== + + * added MongooseArray#splice support + * fixed; 'path' is now a valid Schema pathname + * improved hooks (utilizing https://github.com/bnoguchi/hooks-js) + * fixed; MongooseArray#$shift now works (never did) + * fixed; Document.modified no longer throws + * fixed; modifying subdoc property sets modified paths for subdoc and parent doc + * fixed; marking subdoc path as modified properly persists the value to the db + * fixed; RexExps can again be saved ( #357 ) + +1.3.6 / 2011-05-18 +=================== + + * fixed; corrected casting for queries against array types + * added; Document#set now accepts Document instances + +1.3.5 / 2011-05-17 +=================== + + * fixed; $ne queries work properly with single vals + * added; #inspect() methods to improve console.log output + +1.3.4 / 2011-05-17 +=================== + + * fixed; find by Date works as expected (#336) + * added; geospatial 2d index support + * added; support for $near (#309) + * updated; node-mongodb-native driver + * fixed; updating numbers work (#342) + * added; better error msg when try to remove an embedded doc without an _id (#307) + * added; support for 'on-the-fly' schemas (#227) + * changed; virtual id getters can now be skipped + * fixed; .index() called on subdoc schema now works as expected + * fixed; db.setProfile() now buffers until the db is open (#340) + +1.3.3 / 2011-04-27 +=================== + + * fixed; corrected query casting on nested mixed types + +1.3.2 / 2011-04-27 +=================== + + * fixed; query hints now retain key order + +1.3.1 / 2011-04-27 +=================== + + * fixed; setting a property on an embedded array no longer overwrites entire array (GH-310) + * fixed; setting nested properties works when sibling prop is named "type" + * fixed; isModified is now much finer grained when .set() is used (GH-323) + * fixed; mongoose.model() and connection.model() now return the Model (GH-308, GH-305) + * fixed; can now use $gt, $lt, $gte, $lte with String schema types (GH-317) + * fixed; .lowercase() -> .toLowerCase() in pluralize() + * fixed; updating an embedded document by index works (GH-334) + * changed; .save() now passes the instance to the callback (GH-294, GH-264) + * added; can now query system.profile and system.indexes collections + * added; db.model('system.profile') is now included as a default Schema + * added; db.setProfiling(level, ms, callback) + * added; Query#hint() support + * added; more tests + * updated node-mongodb-native to 0.9.3 + +1.3.0 / 2011-04-19 +=================== + + * changed; save() callbacks now fire only once on failed validation + * changed; Errors returned from save() callbacks now instances of ValidationError + * fixed; MongooseArray#indexOf now works properly + +1.2.0 / 2011-04-11 +=================== + + * changed; MongooseNumber now casts empty string to null + +1.1.25 / 2011-04-08 +=================== + + * fixed; post init now fires at proper time + +1.1.24 / 2011-04-03 +=================== + + * fixed; pushing an array onto an Array works on existing docs + +1.1.23 / 2011-04-01 +=================== + + * Added Model#model + +1.1.22 / 2011-03-31 +=================== + + * Fixed; $in queries on mixed types now work + +1.1.21 / 2011-03-31 +=================== + + * Fixed; setting object root to null/undefined works + +1.1.20 / 2011-03-31 +=================== + + * Fixed; setting multiple props on null field works + +1.1.19 / 2011-03-31 +=================== + + * Fixed; no longer using $set on paths to an unexisting fields + +1.1.18 / 2011-03-30 +=================== + + * Fixed; non-mixed type object setters work after initd from null + +1.1.17 / 2011-03-30 +=================== + + * Fixed; nested object property access works when root initd with null value + +1.1.16 / 2011-03-28 +=================== + + * Fixed; empty arrays are now saved + +1.1.15 / 2011-03-28 +=================== + + * Fixed; `null` and `undefined` are set atomically. + +1.1.14 / 2011-03-28 +=================== + + * Changed; more forgiving date casting, accepting '' as null. + +1.1.13 / 2011-03-26 +=================== + + * Fixed setting values as `undefined`. + +1.1.12 / 2011-03-26 +=================== + + * Fixed; nested objects now convert to JSON properly + * Fixed; setting nested objects directly now works + * Update node-mongodb-native + +1.1.11 / 2011-03-25 +=================== + + * Fixed for use of `type` as a key. + +1.1.10 / 2011-03-23 +=================== + + * Changed; Make sure to only ensure indexes while connected + +1.1.9 / 2011-03-2 +================== + + * Fixed; Mixed can now default to empty arrays + * Fixed; keys by the name 'type' are now valid + * Fixed; null values retrieved from the database are hydrated as null values. + * Fixed repeated atomic operations when saving a same document twice. + +1.1.8 / 2011-03-23 +================== + + * Fixed 'id' overriding. [bnoguchi] + +1.1.7 / 2011-03-22 +================== + + * Fixed RegExp query casting when querying against an Array of Strings [bnoguchi] + * Fixed getters/setters for nested virtualsl. [bnoguchi] + +1.1.6 / 2011-03-22 +================== + + * Only doValidate when path exists in Schema [aheckmann] + * Allow function defaults for Array types [aheckmann] + * Fix validation hang [aheckmann] + * Fix setting of isRequired of SchemaType [aheckmann] + * Fix SchemaType#required(false) filter [aheckmann] + * More backwards compatibility [aheckmann] + * More tests [aheckmann] + +1.1.5 / 2011-03-14 +================== + + * Added support for `uri, db, fn` and `uri, fn` signatures for replica sets. + * Improved/extended replica set tests. + +1.1.4 / 2011-03-09 +================== + + * Fixed; running an empty Query doesn't throw. [aheckmann] + * Changed; Promise#addBack returns promise. [aheckmann] + * Added streaming cursor support. [aheckmann] + * Changed; Query#update defaults to use$SetOnSave now. [brian] + * Added more docs. + +1.1.3 / 2011-03-04 +================== + + * Added Promise#resolve [aheckmann] + * Fixed backward compatibility with nulls [aheckmann] + * Changed; Query#{run,exec} return promises [aheckmann] + +1.1.2 / 2011-03-03 +================== + + * Restored Query#exec and added notion of default operation [brian] + * Fixed ValidatorError messages [brian] + +1.1.1 / 2011-03-01 +================== + + * Added SchemaType String `lowercase`, `uppercase`, `trim`. + * Public exports (`Model`, `Document`) and tests. + * Added ObjectId casting support for `Document`s. + +1.1.0 / 2011-02-25 +================== + + * Added support for replica sets. + +1.0.16 / 2011-02-18 +=================== + + * Added $nin as another whitelisted $conditional for SchemaArray [brian] + * Changed #with to #where [brian] + * Added ability to use $in conditional with Array types [brian] + +1.0.15 / 2011-02-18 +=================== + + * Added `id` virtual getter for documents to easily access the hexString of + the `_id`. + +1.0.14 / 2011-02-17 +=================== + + * Fix for arrays within subdocuments [brian] + +1.0.13 / 2011-02-16 +=================== + + * Fixed embedded documents saving. + +1.0.12 / 2011-02-14 +=================== + + * Minor refactorings [brian] + +1.0.11 / 2011-02-14 +=================== + + * Query refactor and $ne, $slice, $or, $size, $elemMatch, $nin, $exists support [brian] + * Named scopes sugar [brian] + +1.0.10 / 2011-02-11 +=================== + + * Updated node-mongodb-native driver [thanks John Allen] + +1.0.9 / 2011-02-09 +================== + + * Fixed single member arrays as defaults [brian] + +1.0.8 / 2011-02-09 +================== + + * Fixed for collection-level buffering of commands [gitfy] + * Fixed `Document#toJSON` [dalejefferson] + * Fixed `Connection` authentication [robrighter] + * Fixed clash of accessors in getters/setters [eirikurn] + * Improved `Model#save` promise handling + +1.0.7 / 2011-02-05 +================== + + * Fixed memory leak warnings for test suite on 0.3 + * Fixed querying documents that have an array that contain at least one + specified member. [brian] + * Fixed default value for Array types (fixes GH-210). [brian] + * Fixed example code. + +1.0.6 / 2011-02-03 +================== + + * Fixed `post` middleware + * Fixed; it's now possible to instantiate a model even when one of the paths maps + to an undefined value [brian] + +1.0.5 / 2011-02-02 +================== + + * Fixed; combo $push and $pushAll auto-converts into a $pushAll [brian] + * Fixed; combo $pull and $pullAll auto-converts to a single $pullAll [brian] + * Fixed; $pullAll now removes said members from array before save (so it acts just + like pushAll) [brian] + * Fixed; multiple $pulls and $pushes become a single $pullAll and $pushAll. + Moreover, $pull now modifies the array before save to reflect the immediate + change [brian] + * Added tests for nested shortcut getters [brian] + * Added tests that show that Schemas with nested Arrays don't apply defaults + [brian] + +1.0.4 / 2011-02-02 +================== + + * Added MongooseNumber#toString + * Added MongooseNumber unit tests + +1.0.3 / 2011-02-02 +================== + + * Make sure safe mode works with Model#save + * Changed Schema options: safe mode is now the default + * Updated node-mongodb-native to HEAD + +1.0.2 / 2011-02-02 +================== + + * Added a Model.create shortcut for creating documents. [brian] + * Fixed; we can now instantiate models with hashes that map to at least one + null value. [brian] + * Fixed Schema with more than 2 nested levels. [brian] + +1.0.1 / 2011-02-02 +================== + + * Improved `MongooseNumber`, works almost like the native except for `typeof` + not being `'number'`. diff --git a/node_modules/mongoose/README.md b/node_modules/mongoose/README.md new file mode 100644 index 0000000..fa71038 --- /dev/null +++ b/node_modules/mongoose/README.md @@ -0,0 +1,271 @@ +# Mongoose + +Mongoose is a [MongoDB](http://www.mongodb.org/) object modeling tool designed to work in an asynchronous environment. + +[![Build Status](https://travis-ci.org/LearnBoost/mongoose.png?branch=3.6.x)](https://travis-ci.org/LearnBoost/mongoose) + +## Documentation + +[mongoosejs.com](http://mongoosejs.com/) + +## Support + + - [Stack Overflow](http://stackoverflow.com/questions/tagged/mongoose) + - [bug reports](https://github.com/learnboost/mongoose/issues/) + - [help forum](http://groups.google.com/group/mongoose-orm) + - [MongoDB support](http://www.mongodb.org/display/DOCS/Technical+Support) + - (irc) #mongoosejs on freenode + +## Plugins + +Check out the [plugins search site](http://plugins.mongoosejs.com/) to see hundreds of related modules from the community. + +## Contributors + +View all 90+ [contributors](https://github.com/learnboost/mongoose/graphs/contributors). Stand up and be counted as a [contributor](https://github.com/LearnBoost/mongoose/blob/master/CONTRIBUTING.md) too! + +## Live Examples + + +## Installation + +First install [node.js](http://nodejs.org/) and [mongodb](http://www.mongodb.org/downloads). Then: + + $ npm install mongoose + +## Stablility + +The current stable branch is [3.6.x](https://github.com/LearnBoost/mongoose/tree/3.6.x). New (unstable) development always occurs on the [master](https://github.com/LearnBoost/mongoose/tree/master) branch. + +## Overview + +### Connecting to MongoDB + +First, we need to define a connection. If your app uses only one database, you should use `mongoose.connect`. If you need to create additional connections, use `mongoose.createConnection`. + +Both `connect` and `createConnection` take a `mongodb://` URI, or the parameters `host, database, port, options`. + + var mongoose = require('mongoose'); + + mongoose.connect('mongodb://localhost/my_database'); + +Once connected, the `open` event is fired on the `Connection` instance. If you're using `mongoose.connect`, the `Connection` is `mongoose.connection`. Otherwise, `mongoose.createConnection` return value is a `Connection`. + +**Important!** Mongoose buffers all the commands until it's connected to the database. This means that you don't have to wait until it connects to MongoDB in order to define models, run queries, etc. + +### Defining a Model + +Models are defined through the `Schema` interface. + + var Schema = mongoose.Schema + , ObjectId = Schema.ObjectId; + + var BlogPost = new Schema({ + author : ObjectId + , title : String + , body : String + , date : Date + }); + +Aside from defining the structure of your documents and the types of data you're storing, a Schema handles the definition of: + +* [Validators](http://mongoosejs.com/docs/validation.html) (async and sync) +* [Defaults](http://mongoosejs.com/docs/api.html#schematype_SchemaType-default) +* [Getters](http://mongoosejs.com/docs/api.html#schematype_SchemaType-get) +* [Setters](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set) +* [Indexes](http://mongoosejs.com/docs/guide.html#indexes) +* [Middleware](http://mongoosejs.com/docs/middleware.html) +* [Methods](http://mongoosejs.com/docs/guide.html#methods) definition +* [Statics](http://mongoosejs.com/docs/guide.html#statics) definition +* [Plugins](http://mongoosejs.com/docs/plugins.html) +* [pseudo-JOINs](http://mongoosejs.com/docs/populate.html) + +The following example shows some of these features: + + var Comment = new Schema({ + name : { type: String, default: 'hahaha' } + , age : { type: Number, min: 18, index: true } + , bio : { type: String, match: /[a-z]/ } + , date : { type: Date, default: Date.now } + , buff : Buffer + }); + + // a setter + Comment.path('name').set(function (v) { + return capitalize(v); + }); + + // middleware + Comment.pre('save', function (next) { + notify(this.get('email')); + next(); + }); + +Take a look at the example in `examples/schema.js` for an end-to-end example of a typical setup. + +### Accessing a Model + +Once we define a model through `mongoose.model('ModelName', mySchema)`, we can access it through the same function + + var myModel = mongoose.model('ModelName'); + +Or just do it all at once + + var MyModel = mongoose.model('ModelName', mySchema); + +We can then instantiate it, and save it: + + var instance = new MyModel(); + instance.my.key = 'hello'; + instance.save(function (err) { + // + }); + +Or we can find documents from the same collection + + MyModel.find({}, function (err, docs) { + // docs.forEach + }); + +You can also `findOne`, `findById`, `update`, etc. For more details check out [the docs](http://mongoosejs.com/docs/queries.html). + +**Important!** If you opened a separate connection using `mongoose.createConnection()` but attempt to access the model through `mongoose.model('ModelName')` it will not work as expected since it is not hooked up to an active db connection. In this case access your model through the connection you created: + + var conn = mongoose.createConnection('your connection string'); + var MyModel = conn.model('ModelName', schema); + var m = new MyModel; + m.save() // works + + vs + + var conn = mongoose.createConnection('your connection string'); + var MyModel = mongoose.model('ModelName', schema); + var m = new MyModel; + m.save() // does not work b/c the default connection object was never connected + +### Embedded Documents + +In the first example snippet, we defined a key in the Schema that looks like: + + comments: [Comments] + +Where `Comments` is a `Schema` we created. This means that creating embedded documents is as simple as: + + // retrieve my model + var BlogPost = mongoose.model('BlogPost'); + + // create a blog post + var post = new BlogPost(); + + // create a comment + post.comments.push({ title: 'My comment' }); + + post.save(function (err) { + if (!err) console.log('Success!'); + }); + +The same goes for removing them: + + BlogPost.findById(myId, function (err, post) { + if (!err) { + post.comments[0].remove(); + post.save(function (err) { + // do something + }); + } + }); + +Embedded documents enjoy all the same features as your models. Defaults, validators, middleware. Whenever an error occurs, it's bubbled to the `save()` error callback, so error handling is a snap! + +Mongoose interacts with your embedded documents in arrays _atomically_, out of the box. + +### Middleware + +See the [docs](http://mongoosejs.com/docs/middleware.html) page. + +#### Intercepting and mutating method arguments + +You can intercept method arguments via middleware. + +For example, this would allow you to broadcast changes about your Documents every time someone `set`s a path in your Document to a new value: + + schema.pre('set', function (next, path, val, typel) { + // `this` is the current Document + this.emit('set', path, val); + + // Pass control to the next pre + next(); + }); + +Moreover, you can mutate the incoming `method` arguments so that subsequent middleware see different values for those arguments. To do so, just pass the new values to `next`: + + .pre(method, function firstPre (next, methodArg1, methodArg2) { + // Mutate methodArg1 + next("altered-" + methodArg1.toString(), methodArg2); + }) + + // pre declaration is chainable + .pre(method, function secondPre (next, methodArg1, methodArg2) { + console.log(methodArg1); + // => 'altered-originalValOfMethodArg1' + + console.log(methodArg2); + // => 'originalValOfMethodArg2' + + // Passing no arguments to `next` automatically passes along the current argument values + // i.e., the following `next()` is equivalent to `next(methodArg1, methodArg2)` + // and also equivalent to, with the example method arg + // values, `next('altered-originalValOfMethodArg1', 'originalValOfMethodArg2')` + next(); + }) + +#### Schema gotcha + +`type`, when used in a schema has special meaning within Mongoose. If your schema requires using `type` as a nested property you must use object notation: + + new Schema({ + broken: { type: Boolean } + , asset : { + name: String + , type: String // uh oh, it broke. asset will be interpreted as String + } + }); + + new Schema({ + works: { type: Boolean } + , asset : { + name: String + , type: { type: String } // works. asset is an object with a type property + } + }); + +### Driver access + +The driver being used defaults to [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) and is directly accessible through `YourModel.collection`. **Note**: using the driver directly bypasses all Mongoose power-tools like validation, getters, setters, hooks, etc. + +## API Docs + +Find the API docs [here](http://mongoosejs.com/docs/api.html), generated using [dox](http://github.com/visionmedia/dox). + +## License + +Copyright (c) 2010 LearnBoost <dev@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/node_modules/mongoose/contRun.sh b/node_modules/mongoose/contRun.sh new file mode 100755 index 0000000..cd5610d --- /dev/null +++ b/node_modules/mongoose/contRun.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +make test + +ret=$? + +while [ $ret == 0 ]; do + make test + ret=$? +done diff --git a/node_modules/mongoose/examples/README.md b/node_modules/mongoose/examples/README.md new file mode 100644 index 0000000..cb32898 --- /dev/null +++ b/node_modules/mongoose/examples/README.md @@ -0,0 +1,41 @@ +This directory contains runnable sample mongoose programs. + +To run: + + - first install [Node.js](http://nodejs.org/) + - from the root of the project, execute `npm install -d` + - in the example directory, run `npm install -d` + - from the command line, execute: `node example.js`, replacing "example.js" with the name of a program. + + +Goal is to show: + +- ~~global schemas~~ +- ~~GeoJSON schemas / use (with crs)~~ +- text search (once MongoDB removes the "Experimental/beta" label) +- ~~lean queries~~ +- ~~statics~~ +- methods and statics on subdocs +- custom types +- ~~querybuilder~~ +- ~~promises~~ +- accessing driver collection, db +- ~~connecting to replica sets~~ +- connecting to sharded clusters +- enabling a fail fast mode +- on the fly schemas +- storing files +- ~~map reduce~~ +- ~~aggregation~~ +- advanced hooks +- using $elemMatch to return a subset of an array +- query casting +- upserts +- pagination +- express + mongoose session handling +- ~~group by (use aggregation)~~ +- authentication +- schema migration techniques +- converting documents to plain objects (show transforms) +- how to $unset + diff --git a/node_modules/mongoose/examples/aggregate/aggregate.js b/node_modules/mongoose/examples/aggregate/aggregate.js new file mode 100644 index 0000000..e58d25d --- /dev/null +++ b/node_modules/mongoose/examples/aggregate/aggregate.js @@ -0,0 +1,78 @@ + +// import async to make control flow simplier +var async = require('async'); + +// import the rest of the normal stuff +var mongoose = require('../../lib'); + +require('./person.js')(); + +var Person = mongoose.model('Person'); + +// define some dummy data +var data = [ + { name : 'bill', age : 25, birthday : new Date().setFullYear((new + Date().getFullYear() - 25)), gender : "Male", + likes : ['movies', 'games', 'dogs']}, + { name : 'mary', age : 30, birthday : new Date().setFullYear((new + Date().getFullYear() - 30)), gender : "Female", + likes : ['movies', 'birds', 'cats']}, + { name : 'bob', age : 21, birthday : new Date().setFullYear((new + Date().getFullYear() - 21)), gender : "Male", + likes : ['tv', 'games', 'rabbits']}, + { name : 'lilly', age : 26, birthday : new Date().setFullYear((new + Date().getFullYear() - 26)), gender : "Female", + likes : ['books', 'cats', 'dogs']}, + { name : 'alucard', age : 1000, birthday : new Date().setFullYear((new + Date().getFullYear() - 1000)), gender : "Male", + likes : ['glasses', 'wine', 'the night']}, +]; + + +mongoose.connect('mongodb://localhost/persons', function (err) { + if (err) throw err; + + // create all of the dummy people + async.each(data, function (item, cb) { + Person.create(item, cb); + }, function (err) { + + // run an aggregate query that will get all of the people who like a given + // item. To see the full documentation on ways to use the aggregate + // framework, see http://docs.mongodb.org/manual/core/aggregation/ + Person.aggregate( + // select the fields we want to deal with + { $project : { name : 1, likes : 1 } }, + // unwind 'likes', which will create a document for each like + { $unwind : "$likes" }, + // group everything by the like and then add each name with that like to + // the set for the like + { $group : { + _id : { likes : "$likes" }, + likers : { $addToSet : "$name" } + } }, + function (err, result) { + if (err) throw err; + console.log(result); + //[ { _id: { likes: 'the night' }, likers: [ 'alucard' ] }, + //{ _id: { likes: 'wine' }, likers: [ 'alucard' ] }, + //{ _id: { likes: 'books' }, likers: [ 'lilly' ] }, + //{ _id: { likes: 'glasses' }, likers: [ 'alucard' ] }, + //{ _id: { likes: 'birds' }, likers: [ 'mary' ] }, + //{ _id: { likes: 'rabbits' }, likers: [ 'bob' ] }, + //{ _id: { likes: 'cats' }, likers: [ 'lilly', 'mary' ] }, + //{ _id: { likes: 'dogs' }, likers: [ 'lilly', 'bill' ] }, + //{ _id: { likes: 'tv' }, likers: [ 'bob' ] }, + //{ _id: { likes: 'games' }, likers: [ 'bob', 'bill' ] }, + //{ _id: { likes: 'movies' }, likers: [ 'mary', 'bill' ] } ] + + cleanup(); + }); + }); +}); + +function cleanup() { + Person.remove(function() { + mongoose.disconnect(); + }); +} diff --git a/node_modules/mongoose/examples/aggregate/package.json b/node_modules/mongoose/examples/aggregate/package.json new file mode 100644 index 0000000..53ed2e1 --- /dev/null +++ b/node_modules/mongoose/examples/aggregate/package.json @@ -0,0 +1,14 @@ +{ + "name": "aggregate-example", + "private": "true", + "version": "0.0.0", + "description": "deps for aggregate example", + "main": "aggregate.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { "async": "*" }, + "repository": "", + "author": "", + "license": "BSD" +} diff --git a/node_modules/mongoose/examples/aggregate/person.js b/node_modules/mongoose/examples/aggregate/person.js new file mode 100644 index 0000000..5046b1f --- /dev/null +++ b/node_modules/mongoose/examples/aggregate/person.js @@ -0,0 +1,17 @@ + +// import the necessary modules +var mongoose = require('../../lib'); +var Schema = mongoose.Schema; + +// create an export function to encapsulate the model creation +module.exports = function() { + // define schema + var PersonSchema = new Schema({ + name : String, + age : Number, + birthday : Date, + gender: String, + likes: [String] + }); + mongoose.model('Person', PersonSchema); +}; diff --git a/node_modules/mongoose/examples/doc-methods.js b/node_modules/mongoose/examples/doc-methods.js new file mode 100644 index 0000000..373a46b --- /dev/null +++ b/node_modules/mongoose/examples/doc-methods.js @@ -0,0 +1,70 @@ + +var mongoose = require('mongoose') +var Schema = mongoose.Schema; + +console.log('Running mongoose version %s', mongoose.version); + +/** + * Schema + */ + +var CharacterSchema = Schema({ + name: { type: String, required: true } + , health: { type: Number, min: 0, max: 100 } +}) + +/** + * Methods + */ + +CharacterSchema.methods.attack = function () { + console.log('%s is attacking', this.name); +} + +/** + * Character model + */ + +var Character = mongoose.model('Character', CharacterSchema); + +/** + * Connect to the database on localhost with + * the default port (27017) + */ + +var dbname = 'mongoose-example-doc-methods-' + ((Math.random()*10000)|0); +var uri = 'mongodb://localhost/' + dbname; + +console.log('connecting to %s', uri); + +mongoose.connect(uri, function (err) { + // if we failed to connect, abort + if (err) throw err; + + // we connected ok + example(); +}) + +/** + * Use case + */ + +function example () { + Character.create({ name: 'Link', health: 100 }, function (err, link) { + if (err) return done(err); + console.log('found', link); + link.attack(); // 'Link is attacking' + done(); + }) +} + +/** + * Clean up + */ + +function done (err) { + if (err) console.error(err); + mongoose.connection.db.dropDatabase(function () { + mongoose.disconnect(); + }) +} diff --git a/node_modules/mongoose/examples/express/README.md b/node_modules/mongoose/examples/express/README.md new file mode 100644 index 0000000..7ba07b8 --- /dev/null +++ b/node_modules/mongoose/examples/express/README.md @@ -0,0 +1 @@ +Mongoose + Express examples diff --git a/node_modules/mongoose/examples/express/connection-sharing/README.md b/node_modules/mongoose/examples/express/connection-sharing/README.md new file mode 100644 index 0000000..fc709a3 --- /dev/null +++ b/node_modules/mongoose/examples/express/connection-sharing/README.md @@ -0,0 +1,6 @@ + +To run: + +- Execute `npm install` from this directory +- Execute `node app.js` +- Navigate to `localhost:8000` diff --git a/node_modules/mongoose/examples/express/connection-sharing/app.js b/node_modules/mongoose/examples/express/connection-sharing/app.js new file mode 100644 index 0000000..fe3332c --- /dev/null +++ b/node_modules/mongoose/examples/express/connection-sharing/app.js @@ -0,0 +1,18 @@ + +var express = require('express') +var mongoose = require('../../../lib') + +var uri = 'mongodb://localhost/mongoose-shared-connection'; +global.db = mongoose.createConnection(uri); + +var routes = require('./routes') + +var app = express(); +app.get('/', routes.home); +app.get('/insert', routes.insert); +app.get('/name', routes.modelName); + +app.listen(8000, function () { + console.log('listening on http://localhost:8000'); +}) + diff --git a/node_modules/mongoose/examples/express/connection-sharing/modelA.js b/node_modules/mongoose/examples/express/connection-sharing/modelA.js new file mode 100644 index 0000000..a387161 --- /dev/null +++ b/node_modules/mongoose/examples/express/connection-sharing/modelA.js @@ -0,0 +1,6 @@ + +var Schema = require('../../../lib').Schema; +var mySchema = Schema({ name: String }); + +// db is global +module.exports = db.model('MyModel', mySchema); diff --git a/node_modules/mongoose/examples/express/connection-sharing/package.json b/node_modules/mongoose/examples/express/connection-sharing/package.json new file mode 100644 index 0000000..e326165 --- /dev/null +++ b/node_modules/mongoose/examples/express/connection-sharing/package.json @@ -0,0 +1,14 @@ +{ + "name": "connection-sharing", + "private": "true", + "version": "0.0.0", + "description": "ERROR: No README.md file found!", + "main": "app.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { "express": "3.1.1" }, + "repository": "", + "author": "", + "license": "BSD" +} diff --git a/node_modules/mongoose/examples/express/connection-sharing/routes.js b/node_modules/mongoose/examples/express/connection-sharing/routes.js new file mode 100644 index 0000000..d8fe8bf --- /dev/null +++ b/node_modules/mongoose/examples/express/connection-sharing/routes.js @@ -0,0 +1,20 @@ + +var model = require('./modelA') + +exports.home = function (req, res, next) { + model.find(function (err, docs) { + if (err) return next(err); + res.send(docs); + }) +} + +exports.modelName = function (req, res) { + res.send('my model name is ' + model.modelName); +} + +exports.insert = function (req, res, next) { + model.create({ name: 'inserting ' + Date.now() }, function (err, doc) { + if (err) return next(err); + res.send(doc); + }) +} diff --git a/node_modules/mongoose/examples/geospatial/geoJSONSchema.js b/node_modules/mongoose/examples/geospatial/geoJSONSchema.js new file mode 100644 index 0000000..e9ad28d --- /dev/null +++ b/node_modules/mongoose/examples/geospatial/geoJSONSchema.js @@ -0,0 +1,22 @@ + +// import the necessary modules +var mongoose = require('../../lib'); +var Schema = mongoose.Schema; + +// create an export function to encapsulate the model creation +module.exports = function() { + // define schema + // NOTE : This object must conform *precisely* to the geoJSON specification + // you cannot embed a geoJSON doc inside a model or anything like that- IT + // MUST BE VANILLA + var LocationObject = new Schema({ + loc: { + type: { type: String }, + coordinates: [] + } + }); + // define the index + LocationObject.index({ loc : '2dsphere' }); + + mongoose.model('Location', LocationObject); +}; diff --git a/node_modules/mongoose/examples/geospatial/geoJSONexample.js b/node_modules/mongoose/examples/geospatial/geoJSONexample.js new file mode 100644 index 0000000..b1c9199 --- /dev/null +++ b/node_modules/mongoose/examples/geospatial/geoJSONexample.js @@ -0,0 +1,49 @@ + +// import async to make control flow simplier +var async = require('async'); + +// import the rest of the normal stuff +var mongoose = require('../../lib'); + +require('./geoJSONSchema.js')(); + +var Location = mongoose.model('Location'); + +// define some dummy data +// note: the type can be Point, LineString, or Polygon +var data = [ + { loc: { type: 'Point', coordinates: [-20.0, 5.0] }}, + { loc: { type: 'Point', coordinates: [6.0, 10.0] }}, + { loc: { type: 'Point', coordinates: [34.0, -50.0] }}, + { loc: { type: 'Point', coordinates: [-100.0, 70.0] }}, + { loc: { type: 'Point', coordinates: [38.0, 38.0] }} +]; + + +mongoose.connect('mongodb://localhost/locations', function (err) { + if (err) throw err; + + Location.on('index', function(err) { + if (err) throw err; + // create all of the dummy locations + async.each(data, function (item, cb) { + Location.create(item, cb); + }, function (err) { + if (err) throw err; + // create the location we want to search for + var coords = { type : 'Point', coordinates : [-5, 5] }; + // search for it + Location.find({ loc : { $near : coords }}).limit(1).exec(function(err, res) { + if (err) throw err; + console.log("Closest to %s is %s", JSON.stringify(coords), res); + cleanup(); + }); + }); + }); +}); + +function cleanup() { + Location.remove(function() { + mongoose.disconnect(); + }); +} diff --git a/node_modules/mongoose/examples/geospatial/geospatial.js b/node_modules/mongoose/examples/geospatial/geospatial.js new file mode 100644 index 0000000..bec89e3 --- /dev/null +++ b/node_modules/mongoose/examples/geospatial/geospatial.js @@ -0,0 +1,67 @@ + +// import async to make control flow simplier +var async = require('async'); + +// import the rest of the normal stuff +var mongoose = require('../../lib'); + +require('./person.js')(); + +var Person = mongoose.model('Person'); + +// define some dummy data +var data = [ + { name : 'bill', age : 25, birthday : new Date().setFullYear((new + Date().getFullYear() - 25)), gender : "Male", + likes : ['movies', 'games', 'dogs'], loc : [0, 0]}, + { name : 'mary', age : 30, birthday : new Date().setFullYear((new + Date().getFullYear() - 30)), gender : "Female", + likes : ['movies', 'birds', 'cats'], loc : [1, 1]}, + { name : 'bob', age : 21, birthday : new Date().setFullYear((new + Date().getFullYear() - 21)), gender : "Male", + likes : ['tv', 'games', 'rabbits'], loc : [3, 3]}, + { name : 'lilly', age : 26, birthday : new Date().setFullYear((new + Date().getFullYear() - 26)), gender : "Female", + likes : ['books', 'cats', 'dogs'], loc : [6, 6]}, + { name : 'alucard', age : 1000, birthday : new Date().setFullYear((new + Date().getFullYear() - 1000)), gender : "Male", + likes : ['glasses', 'wine', 'the night'], loc : [10, 10]}, +]; + + +mongoose.connect('mongodb://localhost/persons', function (err) { + if (err) throw err; + + // create all of the dummy people + async.each(data, function (item, cb) { + Person.create(item, cb); + }, function (err) { + + // let's find the closest person to bob + Person.find({ name : 'bob' }, function (err, res) { + if (err) throw err; + + res[0].findClosest(function (err, closest) { + if (err) throw err; + + console.log("%s is closest to %s", res[0].name, closest); + + + // we can also just query straight off of the model. For more + // information about geospatial queries and indexes, see + // http://docs.mongodb.org/manual/applications/geospatial-indexes/ + var coords = [7,7]; + Person.find({ loc : { $nearSphere : coords }}).limit(1).exec(function(err, res) { + console.log("Closest to %s is %s", coords, res); + cleanup(); + }); + }); + }); + }); +}); + +function cleanup() { + Person.remove(function() { + mongoose.disconnect(); + }); +} diff --git a/node_modules/mongoose/examples/geospatial/package.json b/node_modules/mongoose/examples/geospatial/package.json new file mode 100644 index 0000000..75c2a0e --- /dev/null +++ b/node_modules/mongoose/examples/geospatial/package.json @@ -0,0 +1,14 @@ +{ + "name": "geospatial-example", + "private": "true", + "version": "0.0.0", + "description": "deps for geospatial example", + "main": "geospatial.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { "async": "*" }, + "repository": "", + "author": "", + "license": "BSD" +} diff --git a/node_modules/mongoose/examples/geospatial/person.js b/node_modules/mongoose/examples/geospatial/person.js new file mode 100644 index 0000000..c84273e --- /dev/null +++ b/node_modules/mongoose/examples/geospatial/person.js @@ -0,0 +1,28 @@ + +// import the necessary modules +var mongoose = require('../../lib'); +var Schema = mongoose.Schema; + +// create an export function to encapsulate the model creation +module.exports = function() { + // define schema + var PersonSchema = new Schema({ + name : String, + age : Number, + birthday : Date, + gender: String, + likes: [String], + // define the geospatial field + loc: { type : [Number], index: '2d' } + }); + + // define a method to find the closest person + PersonSchema.methods.findClosest = function(cb) { + return this.model('Person').find({ + loc : { $nearSphere : this.loc }, + name : { $ne : this.name } + }).limit(1).exec(cb); + }; + + mongoose.model('Person', PersonSchema); +}; diff --git a/node_modules/mongoose/examples/globalschemas/gs_example.js b/node_modules/mongoose/examples/globalschemas/gs_example.js new file mode 100644 index 0000000..547c6e7 --- /dev/null +++ b/node_modules/mongoose/examples/globalschemas/gs_example.js @@ -0,0 +1,40 @@ + +var mongoose = require('../../lib'); + + +// import the global schema, this can be done in any file that needs the model +require('./person.js')(); + +// grab the person model object +var Person = mongoose.model("Person"); + +// connect to a server to do a quick write / read example + +mongoose.connect('mongodb://localhost/persons', function(err) { + if (err) throw err; + + Person.create({ + name : 'bill', + age : 25, + birthday : new Date().setFullYear((new Date().getFullYear() - 25)) + }, function (err, bill) { + if (err) throw err; + console.log("People added to db: %s", bill.toString()); + Person.find({}, function(err, people) { + if (err) throw err; + + people.forEach(function(person) { + console.log("People in the db: %s", person.toString()); + }); + + // make sure to clean things up after we're done + setTimeout(function () { cleanup(); }, 2000); + }); + }); +}); + +function cleanup() { + Person.remove(function() { + mongoose.disconnect(); + }); +} diff --git a/node_modules/mongoose/examples/globalschemas/person.js b/node_modules/mongoose/examples/globalschemas/person.js new file mode 100644 index 0000000..f9c9a27 --- /dev/null +++ b/node_modules/mongoose/examples/globalschemas/person.js @@ -0,0 +1,15 @@ + +// import the necessary modules +var mongoose = require('../../lib'); +var Schema = mongoose.Schema; + +// create an export function to encapsulate the model creation +module.exports = function() { + // define schema + var PersonSchema = new Schema({ + name : String, + age : Number, + birthday : Date + }); + mongoose.model('Person', PersonSchema); +}; diff --git a/node_modules/mongoose/examples/lean/lean.js b/node_modules/mongoose/examples/lean/lean.js new file mode 100644 index 0000000..6780f16 --- /dev/null +++ b/node_modules/mongoose/examples/lean/lean.js @@ -0,0 +1,61 @@ + +// import async to make control flow simplier +var async = require('async'); + +// import the rest of the normal stuff +var mongoose = require('../../lib'); + +require('./person.js')(); + +var Person = mongoose.model('Person'); + +// define some dummy data +var data = [ + { name : 'bill', age : 25, birthday : new Date().setFullYear((new + Date().getFullYear() - 25)), gender : "Male", + likes : ['movies', 'games', 'dogs']}, + { name : 'mary', age : 30, birthday : new Date().setFullYear((new + Date().getFullYear() - 30)), gender : "Female", + likes : ['movies', 'birds', 'cats']}, + { name : 'bob', age : 21, birthday : new Date().setFullYear((new + Date().getFullYear() - 21)), gender : "Male", + likes : ['tv', 'games', 'rabbits']}, + { name : 'lilly', age : 26, birthday : new Date().setFullYear((new + Date().getFullYear() - 26)), gender : "Female", + likes : ['books', 'cats', 'dogs']}, + { name : 'alucard', age : 1000, birthday : new Date().setFullYear((new + Date().getFullYear() - 1000)), gender : "Male", + likes : ['glasses', 'wine', 'the night']}, +]; + + +mongoose.connect('mongodb://localhost/persons', function (err) { + if (err) throw err; + + // create all of the dummy people + async.each(data, function (item, cb) { + Person.create(item, cb); + }, function (err) { + + // lean queries return just plain javascript objects, not + // MongooseDocuments. This makes them good for high performance read + // situations + + // when using .lean() the default is true, but you can explicitly set the + // value by passing in a boolean value. IE. .lean(false) + var q = Person.find({ age : { $lt : 1000 }}).sort('age').limit(2).lean(); + q.exec(function (err, results) { + if (err) throw err; + console.log("Are the results MongooseDocuments?: %s", results[0] instanceof mongoose.Document); + + console.log(results); + cleanup(); + }); + }); +}); + +function cleanup() { + Person.remove(function() { + mongoose.disconnect(); + }); +} diff --git a/node_modules/mongoose/examples/lean/package.json b/node_modules/mongoose/examples/lean/package.json new file mode 100644 index 0000000..6ee511d --- /dev/null +++ b/node_modules/mongoose/examples/lean/package.json @@ -0,0 +1,14 @@ +{ + "name": "lean-example", + "private": "true", + "version": "0.0.0", + "description": "deps for lean example", + "main": "lean.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { "async": "*" }, + "repository": "", + "author": "", + "license": "BSD" +} diff --git a/node_modules/mongoose/examples/lean/person.js b/node_modules/mongoose/examples/lean/person.js new file mode 100644 index 0000000..5046b1f --- /dev/null +++ b/node_modules/mongoose/examples/lean/person.js @@ -0,0 +1,17 @@ + +// import the necessary modules +var mongoose = require('../../lib'); +var Schema = mongoose.Schema; + +// create an export function to encapsulate the model creation +module.exports = function() { + // define schema + var PersonSchema = new Schema({ + name : String, + age : Number, + birthday : Date, + gender: String, + likes: [String] + }); + mongoose.model('Person', PersonSchema); +}; diff --git a/node_modules/mongoose/examples/mapreduce/mapreduce.js b/node_modules/mongoose/examples/mapreduce/mapreduce.js new file mode 100644 index 0000000..52d16f2 --- /dev/null +++ b/node_modules/mongoose/examples/mapreduce/mapreduce.js @@ -0,0 +1,77 @@ + +// import async to make control flow simplier +var async = require('async'); + +// import the rest of the normal stuff +var mongoose = require('../../lib'); + +require('./person.js')(); + +var Person = mongoose.model('Person'); + +// define some dummy data +var data = [ + { name : 'bill', age : 25, birthday : new Date().setFullYear((new + Date().getFullYear() - 25)), gender : "Male" }, + { name : 'mary', age : 30, birthday : new Date().setFullYear((new + Date().getFullYear() - 30)), gender : "Female" }, + { name : 'bob', age : 21, birthday : new Date().setFullYear((new + Date().getFullYear() - 21)), gender : "Male" }, + { name : 'lilly', age : 26, birthday : new Date().setFullYear((new + Date().getFullYear() - 26)), gender : "Female" }, + { name : 'alucard', age : 1000, birthday : new Date().setFullYear((new + Date().getFullYear() - 1000)), gender : "Male" }, +]; + + +mongoose.connect('mongodb://localhost/persons', function (err) { + if (err) throw err; + + // create all of the dummy people + async.each(data, function (item, cb) { + Person.create(item, cb); + }, function (err) { + + // alright, simple map reduce example. We will find the total ages of each + // gender + + // create the options object + var o = {}; + + o.map = function () { + // in this function, 'this' refers to the current document being + // processed. Return the (gender, age) tuple using emit() + emit(this.gender, this.age); + }; + + // the reduce function receives the array of ages that are grouped by the + // id, which in this case is the gender + o.reduce = function (id, ages) { + return Array.sum(ages); + }; + + // other options that can be specified + + // o.query = { age : { $lt : 1000 }}; // the query object + // o.limit = 3; // max number of documents + // o.keeptemp = true; // default is false, specifies whether to keep temp data + // o.finalize = someFunc; // function called after reduce + // o.scope = {}; // the scope variable exposed to map/reduce/finalize + // o.jsMode = true; // default is false, force execution to stay in JS + o.verbose = true; // default is false, provide stats on the job + // o.out = {}; // objects to specify where output goes, by default is + // returned, but can also be stored in a new collection + // see: http://mongoosejs.com/docs/api.html#model_Model.mapReduce + Person.mapReduce(o, function (err, results, stats) { + console.log("map reduce took %d ms", stats.processtime); + console.log(results); + cleanup(); + }); + }); +}); + +function cleanup() { + Person.remove(function() { + mongoose.disconnect(); + }); +} diff --git a/node_modules/mongoose/examples/mapreduce/package.json b/node_modules/mongoose/examples/mapreduce/package.json new file mode 100644 index 0000000..4240068 --- /dev/null +++ b/node_modules/mongoose/examples/mapreduce/package.json @@ -0,0 +1,14 @@ +{ + "name": "map-reduce-example", + "private": "true", + "version": "0.0.0", + "description": "deps for map reduce example", + "main": "mapreduce.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { "async": "*" }, + "repository": "", + "author": "", + "license": "BSD" +} diff --git a/node_modules/mongoose/examples/mapreduce/person.js b/node_modules/mongoose/examples/mapreduce/person.js new file mode 100644 index 0000000..6d476ec --- /dev/null +++ b/node_modules/mongoose/examples/mapreduce/person.js @@ -0,0 +1,16 @@ + +// import the necessary modules +var mongoose = require('../../lib'); +var Schema = mongoose.Schema; + +// create an export function to encapsulate the model creation +module.exports = function() { + // define schema + var PersonSchema = new Schema({ + name : String, + age : Number, + birthday : Date, + gender: String + }); + mongoose.model('Person', PersonSchema); +}; diff --git a/node_modules/mongoose/examples/population/population-across-three-collections.js b/node_modules/mongoose/examples/population/population-across-three-collections.js new file mode 100644 index 0000000..4073965 --- /dev/null +++ b/node_modules/mongoose/examples/population/population-across-three-collections.js @@ -0,0 +1,135 @@ + +var assert = require('assert') +var mongoose = require('../../lib'); +var Schema = mongoose.Schema; +var ObjectId = mongoose.Types.ObjectId; + +/** + * Connect to the db + */ + +var dbname = 'testing_populateAdInfinitum_' + require('../lib/utils').random() +mongoose.connect('localhost', dbname); +mongoose.connection.on('error', function() { + console.error('connection error', arguments); +}); + +/** + * Schemas + */ + +var user = new Schema({ + name: String, + friends: [{ + type: Schema.ObjectId, + ref: 'User' + }] +}); +var User = mongoose.model('User', user); + +var blogpost = Schema({ + title: String, + tags: [String], + author: { + type: Schema.ObjectId, + ref: 'User' + } +}) +var BlogPost = mongoose.model('BlogPost', blogpost); + +/** + * example + */ + +mongoose.connection.on('open', function() { + + /** + * Generate data + */ + + var userIds = [new ObjectId, new ObjectId, new ObjectId, new ObjectId]; + var users = []; + + users.push({ + _id: userIds[0], + name: 'mary', + friends: [userIds[1], userIds[2], userIds[3]] + }); + users.push({ + _id: userIds[1], + name: 'bob', + friends: [userIds[0], userIds[2], userIds[3]] + }); + users.push({ + _id: userIds[2], + name: 'joe', + friends: [userIds[0], userIds[1], userIds[3]] + }); + users.push({ + _id: userIds[3], + name: 'sally', + friends: [userIds[0], userIds[1], userIds[2]] + }); + + User.create(users, function(err, docs) { + assert.ifError(err); + + var blogposts = []; + blogposts.push({ + title: 'blog 1', + tags: ['fun', 'cool'], + author: userIds[3] + }) + blogposts.push({ + title: 'blog 2', + tags: ['cool'], + author: userIds[1] + }) + blogposts.push({ + title: 'blog 3', + tags: ['fun', 'odd'], + author: userIds[2] + }) + + BlogPost.create(blogposts, function(err, docs) { + assert.ifError(err); + + /** + * Population + */ + + BlogPost + .find({ tags: 'fun' }) + .lean() + .populate('author') + .exec(function(err, docs) { + assert.ifError(err); + + /** + * Populate the populated documents + */ + + var opts = { + path: 'author.friends', + select: 'name', + options: { limit: 2 } + } + + BlogPost.populate(docs, opts, function(err, docs) { + assert.ifError(err); + console.log('populated'); + var s = require('util').inspect(docs, { depth: null }) + console.log(s); + done(); + }) + }) + }) + }) +}); + +function done(err) { + if (err) console.error(err.stack); + mongoose.connection.db.dropDatabase(function() { + mongoose.connection.close(); + }); +} diff --git a/node_modules/mongoose/examples/population/population-basic.js b/node_modules/mongoose/examples/population/population-basic.js new file mode 100644 index 0000000..7b16fb5 --- /dev/null +++ b/node_modules/mongoose/examples/population/population-basic.js @@ -0,0 +1,95 @@ + +var mongoose = require('../../lib') +var Schema = mongoose.Schema; + +console.log('Running mongoose version %s', mongoose.version); + +/** + * Console schema + */ + +var consoleSchema = Schema({ + name: String + , manufacturer: String + , released: Date +}) +var Console = mongoose.model('Console', consoleSchema); + +/** + * Game schema + */ + +var gameSchema = Schema({ + name: String + , developer: String + , released: Date + , consoles: [{ type: Schema.Types.ObjectId, ref: 'Console' }] +}) +var Game = mongoose.model('Game', gameSchema); + +/** + * Connect to the console database on localhost with + * the default port (27017) + */ + +mongoose.connect('mongodb://localhost/console', function (err) { + // if we failed to connect, abort + if (err) throw err; + + // we connected ok + createData(); +}) + +/** + * Data generation + */ + +function createData () { + Console.create({ + name: 'Nintendo 64' + , manufacturer: 'Nintendo' + , released: 'September 29, 1996' + }, function (err, nintendo64) { + if (err) return done(err); + + Game.create({ + name: 'Legend of Zelda: Ocarina of Time' + , developer: 'Nintendo' + , released: new Date('November 21, 1998') + , consoles: [nintendo64] + }, function (err) { + if (err) return done(err); + example(); + }) + }) +} + +/** + * Population + */ + +function example () { + Game + .findOne({ name: /^Legend of Zelda/ }) + .populate('consoles') + .exec(function (err, ocinara) { + if (err) return done(err); + + console.log( + '"%s" was released for the %s on %s' + , ocinara.name + , ocinara.consoles[0].name + , ocinara.released.toLocaleDateString()); + + done(); + }) +} + +function done (err) { + if (err) console.error(err); + Console.remove(function () { + Game.remove(function () { + mongoose.disconnect(); + }) + }) +} diff --git a/node_modules/mongoose/examples/population/population-of-existing-doc.js b/node_modules/mongoose/examples/population/population-of-existing-doc.js new file mode 100644 index 0000000..980cc7f --- /dev/null +++ b/node_modules/mongoose/examples/population/population-of-existing-doc.js @@ -0,0 +1,101 @@ + +var mongoose = require('../../lib') +var Schema = mongoose.Schema; + +console.log('Running mongoose version %s', mongoose.version); + +/** + * Console schema + */ + +var consoleSchema = Schema({ + name: String + , manufacturer: String + , released: Date +}) +var Console = mongoose.model('Console', consoleSchema); + +/** + * Game schema + */ + +var gameSchema = Schema({ + name: String + , developer: String + , released: Date + , consoles: [{ type: Schema.Types.ObjectId, ref: 'Console' }] +}) +var Game = mongoose.model('Game', gameSchema); + +/** + * Connect to the console database on localhost with + * the default port (27017) + */ + +mongoose.connect('mongodb://localhost/console', function (err) { + // if we failed to connect, abort + if (err) throw err; + + // we connected ok + createData(); +}) + +/** + * Data generation + */ + +function createData () { + Console.create({ + name: 'Nintendo 64' + , manufacturer: 'Nintendo' + , released: 'September 29, 1996' + }, function (err, nintendo64) { + if (err) return done(err); + + Game.create({ + name: 'Legend of Zelda: Ocarina of Time' + , developer: 'Nintendo' + , released: new Date('November 21, 1998') + , consoles: [nintendo64] + }, function (err) { + if (err) return done(err); + example(); + }) + }) +} + +/** + * Population + */ + +function example () { + Game + .findOne({ name: /^Legend of Zelda/ }) + .exec(function (err, ocinara) { + if (err) return done(err); + + console.log('"%s" console _id: %s', ocinara.name, ocinara.consoles[0]); + + // population of existing document + ocinara.populate('consoles', function (err) { + if (err) return done(err); + + console.log( + '"%s" was released for the %s on %s' + , ocinara.name + , ocinara.consoles[0].name + , ocinara.released.toLocaleDateString()); + + done(); + }) + }) +} + +function done (err) { + if (err) console.error(err); + Console.remove(function () { + Game.remove(function () { + mongoose.disconnect(); + }) + }) +} diff --git a/node_modules/mongoose/examples/population/population-of-multiple-existing-docs.js b/node_modules/mongoose/examples/population/population-of-multiple-existing-docs.js new file mode 100644 index 0000000..e4d154d --- /dev/null +++ b/node_modules/mongoose/examples/population/population-of-multiple-existing-docs.js @@ -0,0 +1,112 @@ + +var mongoose = require('../../lib') +var Schema = mongoose.Schema; + +console.log('Running mongoose version %s', mongoose.version); + +/** + * Console schema + */ + +var consoleSchema = Schema({ + name: String + , manufacturer: String + , released: Date +}) +var Console = mongoose.model('Console', consoleSchema); + +/** + * Game schema + */ + +var gameSchema = Schema({ + name: String + , developer: String + , released: Date + , consoles: [{ type: Schema.Types.ObjectId, ref: 'Console' }] +}) +var Game = mongoose.model('Game', gameSchema); + +/** + * Connect to the console database on localhost with + * the default port (27017) + */ + +mongoose.connect('mongodb://localhost/console', function (err) { + // if we failed to connect, abort + if (err) throw err; + + // we connected ok + createData(); +}) + +/** + * Data generation + */ + +function createData () { + Console.create({ + name: 'Nintendo 64' + , manufacturer: 'Nintendo' + , released: 'September 29, 1996' + }, { + name: 'Super Nintendo' + , manufacturer: 'Nintendo' + , released: 'August 23, 1991' + }, function (err, nintendo64, superNintendo) { + if (err) return done(err); + + Game.create({ + name: 'Legend of Zelda: Ocarina of Time' + , developer: 'Nintendo' + , released: new Date('November 21, 1998') + , consoles: [nintendo64] + }, { + name: 'Mario Kart' + , developer: 'Nintendo' + , released: 'September 1, 1992' + , consoles: [superNintendo] + }, function (err) { + if (err) return done(err); + example(); + }) + }) +} + +/** + * Population + */ + +function example () { + Game + .find({}) + .exec(function (err, games) { + if (err) return done(err); + + console.log('found %d games', games.length); + + var options = { path: 'consoles', select: 'name released -_id' }; + Game.populate(games, options, function (err, games) { + if (err) return done(err); + + games.forEach(function (game) { + console.log( + '"%s" was released for the %s on %s' + , game.name + , game.consoles[0].name + , game.released.toLocaleDateString()); + }) + + done() + }) + }) +} + +function done (err) { + if (err) console.error(err); + Console.remove(function () { + Game.remove(function () { + mongoose.disconnect(); + }) + }) +} diff --git a/node_modules/mongoose/examples/population/population-options.js b/node_modules/mongoose/examples/population/population-options.js new file mode 100644 index 0000000..b65e3ec --- /dev/null +++ b/node_modules/mongoose/examples/population/population-options.js @@ -0,0 +1,124 @@ + +var mongoose = require('../../lib') +var Schema = mongoose.Schema; + +console.log('Running mongoose version %s', mongoose.version); + +/** + * Console schema + */ + +var consoleSchema = Schema({ + name: String + , manufacturer: String + , released: Date +}) +var Console = mongoose.model('Console', consoleSchema); + +/** + * Game schema + */ + +var gameSchema = Schema({ + name: String + , developer: String + , released: Date + , consoles: [{ type: Schema.Types.ObjectId, ref: 'Console' }] +}) +var Game = mongoose.model('Game', gameSchema); + +/** + * Connect to the console database on localhost with + * the default port (27017) + */ + +mongoose.connect('mongodb://localhost/console', function (err) { + // if we failed to connect, abort + if (err) throw err; + + // we connected ok + createData(); +}) + +/** + * Data generation + */ + +function createData () { + Console.create({ + name: 'Nintendo 64' + , manufacturer: 'Nintendo' + , released: 'September 29, 1996' + }, { + name: 'Super Nintendo' + , manufacturer: 'Nintendo' + , released: 'August 23, 1991' + }, { + name: 'XBOX 360' + , manufacturer: 'Microsoft' + , released: 'November 22, 2005' + }, function (err, nintendo64, superNintendo, xbox360) { + if (err) return done(err); + + Game.create({ + name: 'Legend of Zelda: Ocarina of Time' + , developer: 'Nintendo' + , released: new Date('November 21, 1998') + , consoles: [nintendo64] + }, { + name: 'Mario Kart' + , developer: 'Nintendo' + , released: 'September 1, 1992' + , consoles: [superNintendo] + }, { + name: 'Perfect Dark Zero' + , developer: 'Rare' + , released: 'November 17, 2005' + , consoles: [xbox360] + }, function (err) { + if (err) return done(err); + example(); + }) + }) +} + +/** + * Population + */ + +function example () { + Game + .find({}) + .populate({ + path: 'consoles' + , match: { manufacturer: 'Nintendo' } + , select: 'name' + , options: { comment: 'population' } + }) + .exec(function (err, games) { + if (err) return done(err); + + games.forEach(function (game) { + console.log( + '"%s" was released for the %s on %s' + , game.name + , game.consoles.length ? game.consoles[0].name : '??' + , game.released.toLocaleDateString()); + }) + + return done(); + }) +} + +/** + * Clean up + */ + +function done (err) { + if (err) console.error(err); + Console.remove(function () { + Game.remove(function () { + mongoose.disconnect(); + }) + }) +} diff --git a/node_modules/mongoose/examples/population/population-plain-objects.js b/node_modules/mongoose/examples/population/population-plain-objects.js new file mode 100644 index 0000000..026259a --- /dev/null +++ b/node_modules/mongoose/examples/population/population-plain-objects.js @@ -0,0 +1,96 @@ + +var mongoose = require('../../lib') +var Schema = mongoose.Schema; + +console.log('Running mongoose version %s', mongoose.version); + +/** + * Console schema + */ + +var consoleSchema = Schema({ + name: String + , manufacturer: String + , released: Date +}) +var Console = mongoose.model('Console', consoleSchema); + +/** + * Game schema + */ + +var gameSchema = Schema({ + name: String + , developer: String + , released: Date + , consoles: [{ type: Schema.Types.ObjectId, ref: 'Console' }] +}) +var Game = mongoose.model('Game', gameSchema); + +/** + * Connect to the console database on localhost with + * the default port (27017) + */ + +mongoose.connect('mongodb://localhost/console', function (err) { + // if we failed to connect, abort + if (err) throw err; + + // we connected ok + createData(); +}) + +/** + * Data generation + */ + +function createData () { + Console.create({ + name: 'Nintendo 64' + , manufacturer: 'Nintendo' + , released: 'September 29, 1996' + }, function (err, nintendo64) { + if (err) return done(err); + + Game.create({ + name: 'Legend of Zelda: Ocarina of Time' + , developer: 'Nintendo' + , released: new Date('November 21, 1998') + , consoles: [nintendo64] + }, function (err) { + if (err) return done(err); + example(); + }) + }) +} + +/** + * Population + */ + +function example () { + Game + .findOne({ name: /^Legend of Zelda/ }) + .populate('consoles') + .lean() // just return plain objects, not documents wrapped by mongoose + .exec(function (err, ocinara) { + if (err) return done(err); + + console.log( + '"%s" was released for the %s on %s' + , ocinara.name + , ocinara.consoles[0].name + , ocinara.released.toLocaleDateString()); + + done(); + }) +} + +function done (err) { + if (err) console.error(err); + Console.remove(function () { + Game.remove(function () { + mongoose.disconnect(); + }) + }) +} diff --git a/node_modules/mongoose/examples/promises/package.json b/node_modules/mongoose/examples/promises/package.json new file mode 100644 index 0000000..1983250 --- /dev/null +++ b/node_modules/mongoose/examples/promises/package.json @@ -0,0 +1,14 @@ +{ + "name": "promise-example", + "private": "true", + "version": "0.0.0", + "description": "deps for promise example", + "main": "promise.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { "async": "*" }, + "repository": "", + "author": "", + "license": "BSD" +} diff --git a/node_modules/mongoose/examples/promises/person.js b/node_modules/mongoose/examples/promises/person.js new file mode 100644 index 0000000..f9c9a27 --- /dev/null +++ b/node_modules/mongoose/examples/promises/person.js @@ -0,0 +1,15 @@ + +// import the necessary modules +var mongoose = require('../../lib'); +var Schema = mongoose.Schema; + +// create an export function to encapsulate the model creation +module.exports = function() { + // define schema + var PersonSchema = new Schema({ + name : String, + age : Number, + birthday : Date + }); + mongoose.model('Person', PersonSchema); +}; diff --git a/node_modules/mongoose/examples/promises/promise.js b/node_modules/mongoose/examples/promises/promise.js new file mode 100644 index 0000000..7b02b1f --- /dev/null +++ b/node_modules/mongoose/examples/promises/promise.js @@ -0,0 +1,70 @@ + +// import async to make control flow simplier +var async = require('async'); + +// import the rest of the normal stuff +var mongoose = require('../../lib'); + +require('./person.js')(); + +var Person = mongoose.model('Person'); + +// define some dummy data +var data = [ + { name : 'bill', age : 25, birthday : new Date().setFullYear((new + Date().getFullYear() - 25)) }, + { name : 'mary', age : 30, birthday : new Date().setFullYear((new + Date().getFullYear() - 30)) }, + { name : 'bob', age : 21, birthday : new Date().setFullYear((new + Date().getFullYear() - 21)) }, + { name : 'lilly', age : 26, birthday : new Date().setFullYear((new + Date().getFullYear() - 26)) }, + { name : 'alucard', age : 1000, birthday : new Date().setFullYear((new + Date().getFullYear() - 1000)) }, +]; + + +mongoose.connect('mongodb://localhost/persons', function (err) { + if (err) throw err; + + // create all of the dummy people + async.each(data, function (item, cb) { + Person.create(item, cb); + }, function (err) { + + // create a promise (get one from the query builder) + var prom = Person.find({age : { $lt : 1000 }}).exec(); + + // add a callback on the promise. This will be called on both error and + // complete + prom.addBack(function () { console.log("completed"); }); + + // add a callback that is only called on complete (success) events + prom.addCallback(function () { console.log("Successful Completion!"); }); + + // add a callback that is only called on err (rejected) events + prom.addErrback(function () { console.log("Fail Boat"); }); + + // you can chain things just like in the promise/A+ spec + // note: each then() is returning a new promise, so the above methods + // that we defined will all fire after the initial promise is fulfilled + prom.then(function (people) { + + // just getting the stuff for the next query + var ids = people.map(function (p) { + return p._id; + }); + + // return the next promise + return Person.find({ _id : { $nin : ids }}).exec(); + }).then(function (oldest) { + console.log("Oldest person is: %s", oldest); + }).then(cleanup); + }); +}); + +function cleanup() { + Person.remove(function() { + mongoose.disconnect(); + }); +} diff --git a/node_modules/mongoose/examples/querybuilder/package.json b/node_modules/mongoose/examples/querybuilder/package.json new file mode 100644 index 0000000..1a3450a --- /dev/null +++ b/node_modules/mongoose/examples/querybuilder/package.json @@ -0,0 +1,14 @@ +{ + "name": "query-builder-example", + "private": "true", + "version": "0.0.0", + "description": "deps for query builder example", + "main": "querybuilder.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { "async": "*" }, + "repository": "", + "author": "", + "license": "BSD" +} diff --git a/node_modules/mongoose/examples/querybuilder/person.js b/node_modules/mongoose/examples/querybuilder/person.js new file mode 100644 index 0000000..f9c9a27 --- /dev/null +++ b/node_modules/mongoose/examples/querybuilder/person.js @@ -0,0 +1,15 @@ + +// import the necessary modules +var mongoose = require('../../lib'); +var Schema = mongoose.Schema; + +// create an export function to encapsulate the model creation +module.exports = function() { + // define schema + var PersonSchema = new Schema({ + name : String, + age : Number, + birthday : Date + }); + mongoose.model('Person', PersonSchema); +}; diff --git a/node_modules/mongoose/examples/querybuilder/querybuilder.js b/node_modules/mongoose/examples/querybuilder/querybuilder.js new file mode 100644 index 0000000..ecc0fe8 --- /dev/null +++ b/node_modules/mongoose/examples/querybuilder/querybuilder.js @@ -0,0 +1,65 @@ + +// import async to make control flow simplier +var async = require('async'); + +// import the rest of the normal stuff +var mongoose = require('../../lib'); + +require('./person.js')(); + +var Person = mongoose.model('Person'); + +// define some dummy data +var data = [ + { name : 'bill', age : 25, birthday : new Date().setFullYear((new + Date().getFullYear() - 25)) }, + { name : 'mary', age : 30, birthday : new Date().setFullYear((new + Date().getFullYear() - 30)) }, + { name : 'bob', age : 21, birthday : new Date().setFullYear((new + Date().getFullYear() - 21)) }, + { name : 'lilly', age : 26, birthday : new Date().setFullYear((new + Date().getFullYear() - 26)) }, + { name : 'alucard', age : 1000, birthday : new Date().setFullYear((new + Date().getFullYear() - 1000)) }, +]; + + +mongoose.connect('mongodb://localhost/persons', function (err) { + if (err) throw err; + + // create all of the dummy people + async.each(data, function (item, cb) { + Person.create(item, cb); + }, function (err) { + if (err) throw err; + + // when querying data, instead of providing a callback, you can instead + // leave that off and get a query object returned + var query = Person.find({ age : { $lt : 1000 }}); + + // this allows you to continue applying modifiers to it + query.sort('birthday'); + query.select('name'); + + // you can chain them together as well + // a full list of methods can be found: + // http://mongoosejs.com/docs/api.html#query-js + query.where('age').gt(21); + + // finally, when ready to execute the query, call the exec() function + query.exec(function (err, results) { + if (err) throw err; + + console.log(results); + + cleanup(); + }); + + }); +}); + +function cleanup() { + Person.remove(function() { + mongoose.disconnect(); + }); +} diff --git a/node_modules/mongoose/examples/replicasets/package.json b/node_modules/mongoose/examples/replicasets/package.json new file mode 100644 index 0000000..927dfd2 --- /dev/null +++ b/node_modules/mongoose/examples/replicasets/package.json @@ -0,0 +1,14 @@ +{ + "name": "replica-set-example", + "private": "true", + "version": "0.0.0", + "description": "deps for replica set example", + "main": "querybuilder.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { "async": "*" }, + "repository": "", + "author": "", + "license": "BSD" +} diff --git a/node_modules/mongoose/examples/replicasets/person.js b/node_modules/mongoose/examples/replicasets/person.js new file mode 100644 index 0000000..f9c9a27 --- /dev/null +++ b/node_modules/mongoose/examples/replicasets/person.js @@ -0,0 +1,15 @@ + +// import the necessary modules +var mongoose = require('../../lib'); +var Schema = mongoose.Schema; + +// create an export function to encapsulate the model creation +module.exports = function() { + // define schema + var PersonSchema = new Schema({ + name : String, + age : Number, + birthday : Date + }); + mongoose.model('Person', PersonSchema); +}; diff --git a/node_modules/mongoose/examples/replicasets/replica-sets.js b/node_modules/mongoose/examples/replicasets/replica-sets.js new file mode 100644 index 0000000..5b69f49 --- /dev/null +++ b/node_modules/mongoose/examples/replicasets/replica-sets.js @@ -0,0 +1,53 @@ + +// import async to make control flow simplier +var async = require('async'); + +// import the rest of the normal stuff +var mongoose = require('../../lib'); + +require('./person.js')(); + +var Person = mongoose.model('Person'); + +// define some dummy data +var data = [ + { name : 'bill', age : 25, birthday : new Date().setFullYear((new + Date().getFullYear() - 25)) }, + { name : 'mary', age : 30, birthday : new Date().setFullYear((new + Date().getFullYear() - 30)) }, + { name : 'bob', age : 21, birthday : new Date().setFullYear((new + Date().getFullYear() - 21)) }, + { name : 'lilly', age : 26, birthday : new Date().setFullYear((new + Date().getFullYear() - 26)) }, + { name : 'alucard', age : 1000, birthday : new Date().setFullYear((new + Date().getFullYear() - 1000)) }, +]; + + +// to connect to a replica set, pass in the comma delimited uri and optionally +// any connection options such as the rs_name. +var opts = { + replSet : { rs_name : "rs0" } +}; +mongoose.connect('mongodb://localhost:27018/persons,localhost:27019,localhost:27020', opts, function (err) { + if (err) throw err; + + // create all of the dummy people + async.each(data, function (item, cb) { + Person.create(item, cb); + }, function (err) { + + // create and delete some data + var prom = Person.find({age : { $lt : 1000 }}).exec(); + + prom.then(function (people) { + console.log("young people: %s", people); + }).then(cleanup); + }); +}); + +function cleanup() { + Person.remove(function() { + mongoose.disconnect(); + }); +} diff --git a/node_modules/mongoose/examples/schema/schema.js b/node_modules/mongoose/examples/schema/schema.js new file mode 100644 index 0000000..7fb171c --- /dev/null +++ b/node_modules/mongoose/examples/schema/schema.js @@ -0,0 +1,102 @@ + +/** + * Module dependencies. + */ + +var mongoose = require('../../lib') + , Schema = mongoose.Schema; + +/** + * Schema definition + */ + +// recursive embedded-document schema + +var Comment = new Schema(); + +Comment.add({ + title : { type: String, index: true } + , date : Date + , body : String + , comments : [Comment] +}); + +var BlogPost = new Schema({ + title : { type: String, index: true } + , slug : { type: String, lowercase: true, trim: true } + , date : Date + , buf : Buffer + , comments : [Comment] + , creator : Schema.ObjectId +}); + +var Person = new Schema({ + name: { + first: String + , last : String + } + , email: { type: String, required: true, index: { unique: true, sparse: true } } + , alive: Boolean +}); + +/** + * Accessing a specific schema type by key + */ + +BlogPost.path('date') +.default(function(){ + return new Date() + }) +.set(function(v){ + return v == 'now' ? new Date() : v; + }); + +/** + * Pre hook. + */ + +BlogPost.pre('save', function(next, done){ + emailAuthor(done); // some async function + next(); +}); + +/** + * Methods + */ + +BlogPost.methods.findCreator = function (callback) { + return this.db.model('Person').findById(this.creator, callback); +} + +BlogPost.statics.findByTitle = function (title, callback) { + return this.find({ title: title }, callback); +} + +BlogPost.methods.expressiveQuery = function (creator, date, callback) { + return this.find('creator', creator).where('date').gte(date).run(callback); +} + +/** + * Plugins + */ + +function slugGenerator (options){ + options = options || {}; + var key = options.key || 'title'; + + return function slugGenerator(schema){ + schema.path(key).set(function(v){ + this.slug = v.toLowerCase().replace(/[^a-z0-9]/g, '').replace(/-+/g, ''); + return v; + }); + }; +}; + +BlogPost.plugin(slugGenerator()); + +/** + * Define model. + */ + +mongoose.model('BlogPost', BlogPost); +mongoose.model('Person', Person); diff --git a/node_modules/mongoose/examples/schema/storing-schemas-as-json/index.js b/node_modules/mongoose/examples/schema/storing-schemas-as-json/index.js new file mode 100644 index 0000000..1e05b41 --- /dev/null +++ b/node_modules/mongoose/examples/schema/storing-schemas-as-json/index.js @@ -0,0 +1,27 @@ + +// modules +var mongoose = require('../../../lib') +var Schema = mongoose.Schema; + +// parse json +var raw = require('./schema.json'); + +// create a schema +var timeSignatureSchema = Schema(raw); + +// compile the model +var TimeSignature = mongoose.model('TimeSignatures', timeSignatureSchema); + +// create a TimeSignature document +var threeFour = new TimeSignature({ + count: 3 + , unit: 4 + , description: "3/4" + , additive: false + , created: new Date + , links: ["http://en.wikipedia.org/wiki/Time_signature"] + , user_id: "518d31a0ef32bbfa853a9814" +}); + +// print its description +console.log(threeFour) diff --git a/node_modules/mongoose/examples/schema/storing-schemas-as-json/schema.json b/node_modules/mongoose/examples/schema/storing-schemas-as-json/schema.json new file mode 100644 index 0000000..5afc626 --- /dev/null +++ b/node_modules/mongoose/examples/schema/storing-schemas-as-json/schema.json @@ -0,0 +1,9 @@ +{ + "count": "number", + "unit": "number", + "description": "string", + "links": ["string"], + "created": "date", + "additive": "boolean", + "user_id": "ObjectId" +} diff --git a/node_modules/mongoose/examples/statics/person.js b/node_modules/mongoose/examples/statics/person.js new file mode 100644 index 0000000..45dbfde --- /dev/null +++ b/node_modules/mongoose/examples/statics/person.js @@ -0,0 +1,21 @@ + +// import the necessary modules +var mongoose = require('../../lib'); +var Schema = mongoose.Schema; + +// create an export function to encapsulate the model creation +module.exports = function() { + // define schema + var PersonSchema = new Schema({ + name : String, + age : Number, + birthday : Date + }); + + // define a static + PersonSchema.statics.findPersonByName = function (name, cb) { + this.find({ name : new RegExp(name, 'i') }, cb); + }; + + mongoose.model('Person', PersonSchema); +}; diff --git a/node_modules/mongoose/examples/statics/statics.js b/node_modules/mongoose/examples/statics/statics.js new file mode 100644 index 0000000..7af642f --- /dev/null +++ b/node_modules/mongoose/examples/statics/statics.js @@ -0,0 +1,38 @@ + +var mongoose = require('../../lib'); + + +// import the schema +require('./person.js')(); + +// grab the person model object +var Person = mongoose.model("Person"); + +// connect to a server to do a quick write / read example + +mongoose.connect('mongodb://localhost/persons', function(err) { + if (err) throw err; + + Person.create({ + name : 'bill', + age : 25, + birthday : new Date().setFullYear((new Date().getFullYear() - 25)) + }, function (err, bill) { + if (err) throw err; + console.log("People added to db: %s", bill.toString()); + + // using the static + Person.findPersonByName('bill', function(err, result) { + if (err) throw err; + + console.log(result); + cleanup(); + }); + }); +}); + +function cleanup() { + Person.remove(function() { + mongoose.disconnect(); + }); +} diff --git a/node_modules/mongoose/index.js b/node_modules/mongoose/index.js new file mode 100644 index 0000000..e7e6278 --- /dev/null +++ b/node_modules/mongoose/index.js @@ -0,0 +1,7 @@ + +/** + * Export lib/mongoose + * + */ + +module.exports = require('./lib/'); diff --git a/node_modules/mongoose/lib/aggregate.js b/node_modules/mongoose/lib/aggregate.js new file mode 100644 index 0000000..e75044d --- /dev/null +++ b/node_modules/mongoose/lib/aggregate.js @@ -0,0 +1,408 @@ +/*! + * Module dependencies + */ + +var Promise = require('./promise') + , util = require('util') + , utils = require('./utils') + , Query = require('./query') + , read = Query.prototype.read + +/** + * Aggregate constructor used for building aggregation pipelines. + * + * ####Example: + * + * new Aggregate(); + * new Aggregate({ $project: { a: 1, b: 1 } }); + * new Aggregate({ $project: { a: 1, b: 1 } }, { $skip: 5 }); + * new Aggregate([{ $project: { a: 1, b: 1 } }, { $skip: 5 }]); + * + * Returned when calling Model.aggregate(). + * + * ####Example: + * + * Model + * .aggregate({ $match: { age: { $gte: 21 }}}) + * .unwind('tags') + * .exec(callback) + * + * ####Note: + * + * - The documents returned are plain javascript objects, not mongoose documents (since any shape of document can be returned). + * - Requires MongoDB >= 2.1 + * + * @see MongoDB http://docs.mongodb.org/manual/applications/aggregation/ + * @see driver http://mongodb.github.com/node-mongodb-native/api-generated/collection.html#aggregate + * @param {Object|Array} [ops] aggregation operator(s) or operator array + * @api public + */ + +function Aggregate () { + this._pipeline = []; + this._model = undefined; + this.options = undefined; + + if (1 === arguments.length && util.isArray(arguments[0])) { + this.append.apply(this, arguments[0]); + } else { + this.append.apply(this, arguments); + } +} + +/** + * Binds this aggregate to a model. + * + * @param {Model} model the model to which the aggregate is to be bound + * @return {Aggregate} + * @api private + */ + +Aggregate.prototype.bind = function (model) { + this._model = model; + return this; +} + +/** + * Appends new operators to this aggregate pipeline + * + * ####Examples: + * + * aggregate.append({ $project: { field: 1 }}, { $limit: 2 }); + * + * // or pass an array + * var pipeline = [{ $match: { daw: 'Logic Audio X' }} ]; + * aggregate.append(pipeline); + * + * @param {Object} ops operator(s) to append + * @return {Aggregate} + * @api public + */ + +Aggregate.prototype.append = function () { + var args = utils.args(arguments) + , arg; + + if (!args.every(isOperator)) { + throw new Error("Arguments must be aggregate pipeline operators"); + } + + this._pipeline = this._pipeline.concat(args); + + return this; +} + +/** + * Appends a new $project operator to this aggregate pipeline. + * + * Mongoose query [selection syntax](#query_Query-select) is also supported. + * + * ####Examples: + * + * // include a, include b, exclude _id + * aggregate.project("a b -_id"); + * + * // or you may use object notation, useful when + * // you have keys already prefixed with a "-" + * aggregate.project({a: 1, b: 1, _id: 0}); + * + * // reshaping documents + * aggregate.project({ + * newField: '$b.nested' + * , plusTen: { $add: ['$val', 10]} + * , sub: { + * name: '$a' + * } + * }) + * + * // etc + * aggregate.project({ salary_k: { $divide: [ "$salary", 1000 ] } }); + * + * @param {Object|String} arg field specification + * @see projection http://docs.mongodb.org/manual/reference/aggregation/project/ + * @return {Aggregate} + * @api public + */ + +Aggregate.prototype.project = function (arg) { + var fields = {}; + + if ('object' === typeof arg && !util.isArray(arg)) { + Object.keys(arg).forEach(function (field) { + fields[field] = arg[field]; + }); + } else if (1 === arguments.length && 'string' === typeof arg) { + arg.split(/\s+/).forEach(function (field) { + if (!field) return; + var include = '-' == field[0] ? 0 : 1; + if (include === 0) field = field.substring(1); + fields[field] = include; + }); + } else { + throw new Error("Invalid project() argument. Must be string or object"); + } + + return this.append({ $project: fields }); +} + +/** + * Appends a new custom $group operator to this aggregate pipeline. + * + * ####Examples: + * + * aggregate.group({ _id: "$department" }); + * + * @see $group http://docs.mongodb.org/manual/reference/aggregation/group/ + * @method group + * @memberOf Aggregate + * @param {Object} arg $group operator contents + * @return {Aggregate} + * @api public + */ + +/** + * Appends a new custom $match operator to this aggregate pipeline. + * + * ####Examples: + * + * aggregate.match({ department: { $in: [ "sales", "engineering" } } }); + * + * @see $match http://docs.mongodb.org/manual/reference/aggregation/match/ + * @method match + * @memberOf Aggregate + * @param {Object} arg $match operator contents + * @return {Aggregate} + * @api public + */ + +/** + * Appends a new $skip operator to this aggregate pipeline. + * + * ####Examples: + * + * aggregate.skip(10); + * + * @see $skip http://docs.mongodb.org/manual/reference/aggregation/skip/ + * @method skip + * @memberOf Aggregate + * @param {Number} num number of records to skip before next stage + * @return {Aggregate} + * @api public + */ + +/** + * Appends a new $limit operator to this aggregate pipeline. + * + * ####Examples: + * + * aggregate.limit(10); + * + * @see $limit http://docs.mongodb.org/manual/reference/aggregation/limit/ + * @method limit + * @memberOf Aggregate + * @param {Number} num maximum number of records to pass to the next stage + * @return {Aggregate} + * @api public + */ + +/** + * Appends a new $geoNear operator to this aggregate pipeline. + * + * ####NOTE: + * + * **MUST** be used as the first operator in the pipeline. + * + * ####Examples: + * + * aggregate.near({ + * near: [40.724, -73.997], + * distanceField: "dist.calculated", // required + * maxDistance: 0.008, + * query: { type: "public" }, + * includeLocs: "dist.location", + * uniqueDocs: true, + * num: 5 + * }); + * + * @see $geoNear http://docs.mongodb.org/manual/reference/aggregation/geoNear/ + * @method near + * @memberOf Aggregate + * @param {Object} parameters + * @return {Aggregate} + * @api public + */ + +Aggregate.prototype.near = function (arg) { + var op = {}; + op.$geoNear = arg; + return this.append(op); +}; + +/*! + * define methods + */ + +'group match skip limit'.split(' ').forEach(function ($operator) { + Aggregate.prototype[$operator] = function (arg) { + var op = {}; + op['$' + $operator] = arg; + return this.append(op); + }; +}); + +/** + * Appends new custom $unwind operator(s) to this aggregate pipeline. + * + * ####Examples: + * + * aggregate.unwind("tags"); + * aggregate.unwind("a", "b", "c"); + * + * @see $unwind http://docs.mongodb.org/manual/reference/aggregation/unwind/ + * @param {String} fields the field(s) to unwind + * @return {Aggregate} + * @api public + */ + +Aggregate.prototype.unwind = function () { + var args = utils.args(arguments); + + return this.append.apply(this, args.map(function (arg) { + return { $unwind: '$' + arg }; + })); +} + +/** + * Appends a new $sort operator to this aggregate pipeline. + * + * If an object is passed, values allowed are `asc`, `desc`, `ascending`, `descending`, `1`, and `-1`. + * + * If a string is passed, it must be a space delimited list of path names. The sort order of each path is ascending unless the path name is prefixed with `-` which will be treated as descending. + * + * ####Examples: + * + * // these are equivalent + * aggregate.sort({ field: 'asc', test: -1 }); + * aggregate.sort('field -test'); + * + * @see $sort http://docs.mongodb.org/manual/reference/aggregation/sort/ + * @param {Object|String} arg + * @return {Query} this + * @api public + */ + +Aggregate.prototype.sort = function (arg) { + // TODO refactor to reuse the query builder logic + + var sort = {}; + + if ('Object' === arg.constructor.name) { + var desc = ['desc', 'descending', -1]; + Object.keys(arg).forEach(function (field) { + sort[field] = desc.indexOf(arg[field]) === -1 ? 1 : -1; + }); + } else if (1 === arguments.length && 'string' == typeof arg) { + arg.split(/\s+/).forEach(function (field) { + if (!field) return; + var ascend = '-' == field[0] ? -1 : 1; + if (ascend === -1) field = field.substring(1); + sort[field] = ascend; + }); + } else { + throw new TypeError('Invalid sort() argument. Must be a string or object.'); + } + + return this.append({ $sort: sort }); +} + +/** + * Sets the readPreference option for the aggregation query. + * + * ####Example: + * + * Model.aggregate(..).read('primaryPreferred').exec(callback) + * + * @param {String} pref one of the listed preference options or their aliases + * @param {Array} [tags] optional tags for this query + * @see mongodb http://docs.mongodb.org/manual/applications/replication/#read-preference + * @see driver http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences + */ + +Aggregate.prototype.read = function (pref) { + if (!this.options) this.options = {}; + read.apply(this, arguments); + return this; +} + +/** + * Executes the aggregate pipeline on the currently bound Model. + * + * ####Example: + * + * aggregate.exec(callback); + * + * // Because a promise is returned, the `callback` is optional. + * var promise = aggregate.exec(); + * promise.then(..); + * + * @see Promise #promise_Promise + * @param {Function} [callback] + * @return {Promise} + * @api public + */ + +Aggregate.prototype.exec = function (callback) { + var promise = new Promise(); + + if (callback) { + promise.addBack(callback); + } + + if (!this._pipeline.length) { + promise.error(new Error("Aggregate has empty pipeline")); + return promise; + } + + if (!this._model) { + promise.error(new Error("Aggregate not bound to any Model")); + return promise; + } + + this._model + .collection + .aggregate(this._pipeline, this.options || {}, promise.resolve.bind(promise)); + + return promise; +} + +/*! + * Helpers + */ + +/** + * Checks whether an object is likely a pipeline operator + * + * @param {Object} obj object to check + * @return {Boolean} + * @api private + */ + +function isOperator (obj) { + var k; + + if ('object' !== typeof obj) { + return false; + } + + k = Object.keys(obj); + + return 1 === k.length && k.some(function (key) { + return '$' === key[0]; + }); +} + +/*! + * Exports + */ + +module.exports = Aggregate; diff --git a/node_modules/mongoose/lib/collection.js b/node_modules/mongoose/lib/collection.js new file mode 100644 index 0000000..1c38286 --- /dev/null +++ b/node_modules/mongoose/lib/collection.js @@ -0,0 +1,188 @@ + +/*! + * Module dependencies. + */ + +var STATES = require('./connectionstate') + +/** + * Abstract Collection constructor + * + * This is the base class that drivers inherit from and implement. + * + * @param {String} name name of the collection + * @param {Connection} conn A MongooseConnection instance + * @param {Object} opts optional collection options + * @api public + */ + +function Collection (name, conn, opts) { + if (undefined === opts) opts = {}; + if (undefined === opts.capped) opts.capped = {}; + + opts.bufferCommands = undefined === opts.bufferCommands + ? true + : opts.bufferCommands; + + if ('number' == typeof opts.capped) { + opts.capped = { size: opts.capped }; + } + + this.opts = opts; + this.name = name; + this.conn = conn; + this.queue = []; + this.buffer = this.opts.bufferCommands; + + if (STATES.connected == this.conn.readyState) { + this.onOpen(); + } +}; + +/** + * The collection name + * + * @api public + * @property name + */ + +Collection.prototype.name; + +/** + * The Connection instance + * + * @api public + * @property conn + */ + +Collection.prototype.conn; + +/** + * Called when the database connects + * + * @api private + */ + +Collection.prototype.onOpen = function () { + var self = this; + this.buffer = false; + self.doQueue(); +}; + +/** + * Called when the database disconnects + * + * @api private + */ + +Collection.prototype.onClose = function () { + if (this.opts.bufferCommands) { + this.buffer = true; + } +}; + +/** + * Queues a method for later execution when its + * database connection opens. + * + * @param {String} name name of the method to queue + * @param {Array} args arguments to pass to the method when executed + * @api private + */ + +Collection.prototype.addQueue = function (name, args) { + this.queue.push([name, args]); + return this; +}; + +/** + * Executes all queued methods and clears the queue. + * + * @api private + */ + +Collection.prototype.doQueue = function () { + for (var i = 0, l = this.queue.length; i < l; i++){ + this[this.queue[i][0]].apply(this, this.queue[i][1]); + } + this.queue = []; + return this; +}; + +/** + * Abstract method that drivers must implement. + */ + +Collection.prototype.ensureIndex = function(){ + throw new Error('Collection#ensureIndex unimplemented by driver'); +}; + +/** + * Abstract method that drivers must implement. + */ + +Collection.prototype.findAndModify = function(){ + throw new Error('Collection#findAndModify unimplemented by driver'); +}; + +/** + * Abstract method that drivers must implement. + */ + +Collection.prototype.findOne = function(){ + throw new Error('Collection#findOne unimplemented by driver'); +}; + +/** + * Abstract method that drivers must implement. + */ + +Collection.prototype.find = function(){ + throw new Error('Collection#find unimplemented by driver'); +}; + +/** + * Abstract method that drivers must implement. + */ + +Collection.prototype.insert = function(){ + throw new Error('Collection#insert unimplemented by driver'); +}; + +/** + * Abstract method that drivers must implement. + */ + +Collection.prototype.save = function(){ + throw new Error('Collection#save unimplemented by driver'); +}; + +/** + * Abstract method that drivers must implement. + */ + +Collection.prototype.update = function(){ + throw new Error('Collection#update unimplemented by driver'); +}; + +/** + * Abstract method that drivers must implement. + */ + +Collection.prototype.getIndexes = function(){ + throw new Error('Collection#getIndexes unimplemented by driver'); +}; + +/** + * Abstract method that drivers must implement. + */ + +Collection.prototype.mapReduce = function(){ + throw new Error('Collection#mapReduce unimplemented by driver'); +}; + +/*! + * Module exports. + */ + +module.exports = Collection; diff --git a/node_modules/mongoose/lib/connection.js b/node_modules/mongoose/lib/connection.js new file mode 100644 index 0000000..2766529 --- /dev/null +++ b/node_modules/mongoose/lib/connection.js @@ -0,0 +1,718 @@ +/*! + * Module dependencies. + */ + +var url = require('url') + , utils = require('./utils') + , EventEmitter = require('events').EventEmitter + , driver = global.MONGOOSE_DRIVER_PATH || './drivers/node-mongodb-native' + , Model = require('./model') + , Schema = require('./schema') + , Collection = require(driver + '/collection') + , STATES = require('./connectionstate') + , MongooseError = require('./error') + , assert =require('assert') + , muri = require('muri') + +/*! + * Protocol prefix regexp. + * + * @api private + */ + +var rgxProtocol = /^(?:.)+:\/\//; + +/** + * Connection constructor + * + * For practical reasons, a Connection equals a Db. + * + * @param {Mongoose} base a mongoose instance + * @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter + * @event `connecting`: Emitted when `connection.{open,openSet}()` is executed on this connection. + * @event `connected`: Emitted when this connection successfully connects to the db. May be emitted _multiple_ times in `reconnected` scenarios. + * @event `open`: Emitted after we `connected` and `onOpen` is executed on all of this connections models. + * @event `disconnecting`: Emitted when `connection.close()` was executed. + * @event `disconnected`: Emitted after getting disconnected from the db. + * @event `close`: Emitted after we `disconnected` and `onClose` executed on all of this connections models. + * @event `reconnected`: Emitted after we `connected` and subsequently `disconnected`, followed by successfully another successfull connection. + * @event `error`: Emitted when an error occurs on this connection. + * @event `fullsetup`: Emitted in a replica-set scenario, when all nodes specified in the connection string are connected. + * @api public + */ + +function Connection (base) { + this.base = base; + this.collections = {}; + this.models = {}; + this.replica = false; + this.hosts = null; + this.host = null; + this.port = null; + this.user = null; + this.pass = null; + this.name = null; + this.options = null; + this.otherDbs = []; + this._readyState = STATES.disconnected; + this._closeCalled = false; + this._hasOpened = false; +}; + +/*! + * Inherit from EventEmitter + */ + +Connection.prototype.__proto__ = EventEmitter.prototype; + +/** + * Connection ready state + * + * - 0 = disconnected + * - 1 = connected + * - 2 = connecting + * - 3 = disconnecting + * + * Each state change emits its associated event name. + * + * ####Example + * + * conn.on('connected', callback); + * conn.on('disconnected', callback); + * + * @property readyState + * @api public + */ + +Object.defineProperty(Connection.prototype, 'readyState', { + get: function(){ return this._readyState; } + , set: function (val) { + if (!(val in STATES)) { + throw new Error('Invalid connection state: ' + val); + } + + if (this._readyState !== val) { + this._readyState = val; + // loop over the otherDbs on this connection and change their state + for (var i=0; i < this.otherDbs.length; i++) { + this.otherDbs[i].readyState = val; + } + + if (STATES.connected === val) + this._hasOpened = true; + + this.emit(STATES[val]); + } + } +}); + +/** + * A hash of the collections associated with this connection + * + * @property collections + */ + +Connection.prototype.collections; + +/** + * The mongodb.Db instance, set when the connection is opened + * + * @property db + */ + +Connection.prototype.db; + +/** + * Opens the connection to MongoDB. + * + * `options` is a hash with the following possible properties: + * + * db - passed to the connection db instance + * server - passed to the connection server instance(s) + * replset - passed to the connection ReplSet instance + * user - username for authentication + * pass - password for authentication + * auth - options for authentication (see http://mongodb.github.com/node-mongodb-native/api-generated/db.html#authenticate) + * + * ####Notes: + * + * Mongoose forces the db option `forceServerObjectId` false and cannot be overridden. + * Mongoose defaults the server `auto_reconnect` options to true which can be overridden. + * See the node-mongodb-native driver instance for options that it understands. + * + * _Options passed take precedence over options included in connection strings._ + * + * @param {String} connection_string mongodb://uri or the host to which you are connecting + * @param {String} [database] database name + * @param {Number} [port] database port + * @param {Object} [options] options + * @param {Function} [callback] + * @see node-mongodb-native https://github.com/mongodb/node-mongodb-native + * @see http://mongodb.github.com/node-mongodb-native/api-generated/db.html#authenticate + * @api public + */ + +Connection.prototype.open = function (host, database, port, options, callback) { + var self = this + , parsed + , uri; + + if ('string' === typeof database) { + switch (arguments.length) { + case 2: + port = 27017; + case 3: + switch (typeof port) { + case 'function': + callback = port, port = 27017; + break; + case 'object': + options = port, port = 27017; + break; + } + break; + case 4: + if ('function' === typeof options) + callback = options, options = {}; + } + } else { + switch (typeof database) { + case 'function': + callback = database, database = undefined; + break; + case 'object': + options = database; + database = undefined; + callback = port; + break; + } + + if (!rgxProtocol.test(host)) { + host = 'mongodb://' + host; + } + + try { + parsed = muri(host); + } catch (err) { + this.error(err, callback); + return this; + } + + database = parsed.db; + host = parsed.hosts[0].host || parsed.hosts[0].ipc; + port = parsed.hosts[0].port || 27017; + } + + this.options = this.parseOptions(options, parsed && parsed.options); + + // make sure we can open + if (STATES.disconnected !== this.readyState) { + var err = new Error('Trying to open unclosed connection.'); + err.state = this.readyState; + this.error(err, callback); + return this; + } + + if (!host) { + this.error(new Error('Missing hostname.'), callback); + return this; + } + + if (!database) { + this.error(new Error('Missing database name.'), callback); + return this; + } + + // authentication + if (options && options.user && options.pass) { + this.user = options.user; + this.pass = options.pass; + + } else if (parsed && parsed.auth) { + this.user = parsed.auth.user; + this.pass = parsed.auth.pass; + + // Check hostname for user/pass + } else if (/@/.test(host) && /:/.test(host.split('@')[0])) { + host = host.split('@'); + var auth = host.shift().split(':'); + host = host.pop(); + this.user = auth[0]; + this.pass = auth[1]; + + } else { + this.user = this.pass = undefined; + } + + this.name = database; + this.host = host; + this.port = port; + + this._open(callback); + return this; +}; + +/** + * Opens the connection to a replica set. + * + * ####Example: + * + * var db = mongoose.createConnection(); + * db.openSet("mongodb://user:pwd@localhost:27020/testing,mongodb://example.com:27020,mongodb://localhost:27019"); + * + * The database name and/or auth need only be included in one URI. + * The `options` is a hash which is passed to the internal driver connection object. + * + * Valid `options` + * + * db - passed to the connection db instance + * server - passed to the connection server instance(s) + * replset - passed to the connection ReplSetServer instance + * user - username for authentication + * pass - password for authentication + * auth - options for authentication (see http://mongodb.github.com/node-mongodb-native/api-generated/db.html#authenticate) + * mongos - Boolean - if true, enables High Availability support for mongos + * + * _Options passed take precedence over options included in connection strings._ + * + * ####Notes: + * + * _If connecting to multiple mongos servers, set the `mongos` option to true._ + * + * conn.open('mongodb://mongosA:27501,mongosB:27501', { mongos: true }, cb); + * + * Mongoose forces the db option `forceServerObjectId` false and cannot be overridden. + * Mongoose defaults the server `auto_reconnect` options to true which can be overridden. + * See the node-mongodb-native driver instance for options that it understands. + * + * _Options passed take precedence over options included in connection strings._ + * + * @param {String} uris comma-separated mongodb:// `URI`s + * @param {String} [database] database name if not included in `uris` + * @param {Object} [options] passed to the internal driver + * @param {Function} [callback] + * @see node-mongodb-native https://github.com/mongodb/node-mongodb-native + * @see http://mongodb.github.com/node-mongodb-native/api-generated/db.html#authenticate + * @api public + */ + +Connection.prototype.openSet = function (uris, database, options, callback) { + if (!rgxProtocol.test(uris)) { + uris = 'mongodb://' + uris; + } + + var self = this; + + switch (arguments.length) { + case 3: + switch (typeof database) { + case 'string': + this.name = database; + break; + case 'object': + callback = options; + options = database; + database = null; + break; + } + + if ('function' === typeof options) { + callback = options; + options = {}; + } + break; + case 2: + switch (typeof database) { + case 'string': + this.name = database; + break; + case 'function': + callback = database, database = null; + break; + case 'object': + options = database, database = null; + break; + } + } + + var parsed; + try { + parsed = muri(uris); + } catch (err) { + this.error(err, callback); + return this; + } + + if (!this.name) { + this.name = parsed.db; + } + + this.hosts = parsed.hosts; + this.options = this.parseOptions(options, parsed && parsed.options); + this.replica = true; + + if (!this.name) { + this.error(new Error('No database name provided for replica set'), callback); + return this; + } + + // authentication + if (options && options.user && options.pass) { + this.user = options.user; + this.pass = options.pass; + + } else if (parsed && parsed.auth) { + this.user = parsed.auth.user; + this.pass = parsed.auth.pass; + + } else { + this.user = this.pass = undefined; + } + + this._open(callback); + return this; +}; + +/** + * error + * + * Graceful error handling, passes error to callback + * if available, else emits error on the connection. + * + * @param {Error} err + * @param {Function} callback optional + * @api private + */ + +Connection.prototype.error = function (err, callback) { + if (callback) return callback(err); + this.emit('error', err); +} + +/** + * Handles opening the connection with the appropriate method based on connection type. + * + * @param {Function} callback + * @api private + */ + +Connection.prototype._open = function (callback) { + this.readyState = STATES.connecting; + this._closeCalled = false; + + var self = this; + + var method = this.replica + ? 'doOpenSet' + : 'doOpen'; + + // open connection + this[method](function (err) { + if (err) { + self.readyState = STATES.disconnected; + if (self._hasOpened) { + if (callback) callback(err); + } else { + self.error(err, callback); + } + return; + } + + self.onOpen(callback); + }); +} + +/** + * Called when the connection is opened + * + * @api private + */ + +Connection.prototype.onOpen = function (callback) { + var self = this; + + function open (err) { + if (err) { + self.readyState = STATES.disconnected; + if (self._hasOpened) { + if (callback) callback(err); + } else { + self.error(err, callback); + } + return; + } + + self.readyState = STATES.connected; + + // avoid having the collection subscribe to our event emitter + // to prevent 0.3 warning + for (var i in self.collections) + self.collections[i].onOpen(); + + callback && callback(); + self.emit('open'); + }; + + // re-authenticate + if (self.user && self.pass) { + self.db.authenticate(self.user, self.pass, self.options.auth, open); + } + else + open(); +}; + +/** + * Closes the connection + * + * @param {Function} [callback] optional + * @return {Connection} self + * @api public + */ + +Connection.prototype.close = function (callback) { + var self = this; + this._closeCalled = true; + + switch (this.readyState){ + case 0: // disconnected + callback && callback(); + break; + + case 1: // connected + this.readyState = STATES.disconnecting; + this.doClose(function(err){ + if (err){ + self.error(err, callback); + } else { + self.onClose(); + callback && callback(); + } + }); + break; + + case 2: // connecting + this.once('open', function(){ + self.close(callback); + }); + break; + + case 3: // disconnecting + if (!callback) break; + this.once('close', function () { + callback(); + }); + break; + } + + return this; +}; + +/** + * Called when the connection closes + * + * @api private + */ + +Connection.prototype.onClose = function () { + this.readyState = STATES.disconnected; + + // avoid having the collection subscribe to our event emitter + // to prevent 0.3 warning + for (var i in this.collections) + this.collections[i].onClose(); + + this.emit('close'); +}; + +/** + * Retrieves a collection, creating it if not cached. + * + * Not typically needed by applications. Just talk to your collection through your model. + * + * @param {String} name of the collection + * @param {Object} [options] optional collection options + * @return {Collection} collection instance + * @api public + */ + +Connection.prototype.collection = function (name, options) { + if (!(name in this.collections)) + this.collections[name] = new Collection(name, this, options); + return this.collections[name]; +}; + +/** + * Defines or retrieves a model. + * + * var mongoose = require('mongoose'); + * var db = mongoose.createConnection(..); + * db.model('Venue', new Schema(..)); + * var Ticket = db.model('Ticket', new Schema(..)); + * var Venue = db.model('Venue'); + * + * _When no `collection` argument is passed, Mongoose produces a collection name by passing the model `name` to the [utils.toCollectionName](#utils_exports.toCollectionName) method. This method pluralizes the name. If you don't like this behavior, either pass a collection name or set your schemas collection name option._ + * + * ####Example: + * + * var schema = new Schema({ name: String }, { collection: 'actor' }); + * + * // or + * + * schema.set('collection', 'actor'); + * + * // or + * + * var collectionName = 'actor' + * var M = conn.model('Actor', schema, collectionName) + * + * @param {String} name the model name + * @param {Schema} [schema] a schema. necessary when defining a model + * @param {String} [collection] name of mongodb collection (optional) if not given it will be induced from model name + * @see Mongoose#model #index_Mongoose-model + * @return {Model} The compiled model + * @api public + */ + +Connection.prototype.model = function (name, schema, collection) { + // collection name discovery + if ('string' == typeof schema) { + collection = schema; + schema = false; + } + + if (utils.isObject(schema) && !(schema instanceof Schema)) { + schema = new Schema(schema); + } + + if (this.models[name] && !collection) { + // model exists but we are not subclassing with custom collection + if (schema instanceof Schema && schema != this.models[name].schema) { + throw new MongooseError.OverwriteModelError(name); + } + return this.models[name]; + } + + var opts = { cache: false, connection: this } + var model; + + if (schema instanceof Schema) { + // compile a model + model = this.base.model(name, schema, collection, opts) + + // only the first model with this name is cached to allow + // for one-offs with custom collection names etc. + if (!this.models[name]) { + this.models[name] = model; + } + + model.init(); + return model; + } + + if (this.models[name] && collection) { + // subclassing current model with alternate collection + model = this.models[name]; + schema = model.prototype.schema; + var sub = model.__subclass(this, schema, collection); + // do not cache the sub model + return sub; + } + + // lookup model in mongoose module + model = this.base.models[name]; + + if (!model) { + throw new MongooseError.MissingSchemaError(name); + } + + if (this == model.prototype.db + && (!collection || collection == model.collection.name)) { + // model already uses this connection. + + // only the first model with this name is cached to allow + // for one-offs with custom collection names etc. + if (!this.models[name]) { + this.models[name] = model; + } + + return model; + } + + return this.models[name] = model.__subclass(this, schema, collection); +} + +/** + * Returns an array of model names created on this connection. + * @api public + * @return {Array} + */ + +Connection.prototype.modelNames = function () { + return Object.keys(this.models); +} + +/** + * Set profiling level. + * + * @param {Number|String} level either off (0), slow (1), or all (2) + * @param {Number} [ms] the threshold in milliseconds above which queries will be logged when in `slow` mode. defaults to 100. + * @param {Function} callback + * @api public + */ + +Connection.prototype.setProfiling = function (level, ms, callback) { + if (STATES.connected !== this.readyState) { + return this.on('open', this.setProfiling.bind(this, level, ms, callback)); + } + + if (!callback) callback = ms, ms = 100; + + var cmd = {}; + + switch (level) { + case 0: + case 'off': + cmd.profile = 0; + break; + case 1: + case 'slow': + cmd.profile = 1; + if ('number' !== typeof ms) { + ms = parseInt(ms, 10); + if (isNaN(ms)) ms = 100; + } + cmd.slowms = ms; + break; + case 2: + case 'all': + cmd.profile = 2; + break; + default: + return callback(new Error('Invalid profiling level: '+ level)); + } + + this.db.executeDbCommand(cmd, function (err, resp) { + if (err) return callback(err); + + var doc = resp.documents[0]; + + err = 1 === doc.ok + ? null + : new Error('Could not set profiling level to: '+ level) + + callback(err, doc); + }); +}; + +/*! + * Noop. + */ + +function noop () {} + +/*! + * Module exports. + */ + +Connection.STATES = STATES; +module.exports = Connection; diff --git a/node_modules/mongoose/lib/connectionstate.js b/node_modules/mongoose/lib/connectionstate.js new file mode 100644 index 0000000..2d05ab0 --- /dev/null +++ b/node_modules/mongoose/lib/connectionstate.js @@ -0,0 +1,24 @@ + +/*! + * Connection states + */ + +var STATES = module.exports = exports = Object.create(null); + +var disconnected = 'disconnected'; +var connected = 'connected'; +var connecting = 'connecting'; +var disconnecting = 'disconnecting'; +var uninitialized = 'uninitialized'; + +STATES[0] = disconnected; +STATES[1] = connected; +STATES[2] = connecting; +STATES[3] = disconnecting; +STATES[99] = uninitialized; + +STATES[disconnected] = 0; +STATES[connected] = 1; +STATES[connecting] = 2; +STATES[disconnecting] = 3; +STATES[uninitialized] = 99; diff --git a/node_modules/mongoose/lib/document.js b/node_modules/mongoose/lib/document.js new file mode 100644 index 0000000..6aade29 --- /dev/null +++ b/node_modules/mongoose/lib/document.js @@ -0,0 +1,1777 @@ +/*! + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , setMaxListeners = EventEmitter.prototype.setMaxListeners + , MongooseError = require('./error') + , MixedSchema = require('./schema/mixed') + , Schema = require('./schema') + , ValidatorError = require('./schematype').ValidatorError + , utils = require('./utils') + , clone = utils.clone + , isMongooseObject = utils.isMongooseObject + , inspect = require('util').inspect + , ElemMatchError = MongooseError.ElemMatchError + , ValidationError = MongooseError.ValidationError + , InternalCache = require('./internal') + , deepEqual = utils.deepEqual + , hooks = require('hooks') + , DocumentArray + , MongooseArray + , Embedded + +/** + * Document constructor. + * + * @param {Object} obj the values to set + * @param {Object} [opts] optional object containing the fields which were selected in the query returning this document and any populated paths data + * @param {Boolean} [skipId] bool, should we auto create an ObjectId _id + * @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter + * @event `init`: Emitted on a document after it has was retreived from the db and fully hydrated by Mongoose. + * @event `save`: Emitted when the document is successfully saved + * @api private + */ + +function Document (obj, fields, skipId) { + this.$__ = new InternalCache; + this.isNew = true; + this.errors = undefined; + + var schema = this.schema; + + if ('boolean' === typeof fields) { + this.$__.strictMode = fields; + fields = undefined; + } else { + this.$__.strictMode = schema.options && schema.options.strict; + this.$__.selected = fields; + } + + var required = schema.requiredPaths(); + for (var i = 0; i < required.length; ++i) { + this.$__.activePaths.require(required[i]); + } + + setMaxListeners.call(this, 0); + this._doc = this.$__buildDoc(obj, fields, skipId); + + if (obj) { + this.set(obj, undefined, true); + } + + this.$__registerHooks(); +} + +/*! + * Inherit from EventEmitter. + */ + +Document.prototype.__proto__ = EventEmitter.prototype; + +/** + * The documents schema. + * + * @api public + * @property schema + */ + +Document.prototype.schema; + +/** + * Boolean flag specifying if the document is new. + * + * @api public + * @property isNew + */ + +Document.prototype.isNew; + +/** + * The string version of this documents _id. + * + * ####Note: + * + * This getter exists on all documents by default. The getter can be disabled by setting the `id` [option](/docs/guide.html#id) of its `Schema` to false at construction time. + * + * new Schema({ name: String }, { id: false }); + * + * @api public + * @see Schema options /docs/guide.html#options + * @property id + */ + +Document.prototype.id; + +/** + * Hash containing current validation errors. + * + * @api public + * @property errors + */ + +Document.prototype.errors; + +/** + * Builds the default doc structure + * + * @param {Object} obj + * @param {Object} [fields] + * @param {Boolean} [skipId] + * @return {Object} + * @api private + * @method $__buildDoc + * @memberOf Document + */ + +Document.prototype.$__buildDoc = function (obj, fields, skipId) { + var doc = {} + , self = this + , exclude + , keys + , key + , ki + + // determine if this doc is a result of a query with + // excluded fields + if (fields && 'Object' === fields.constructor.name) { + keys = Object.keys(fields); + ki = keys.length; + + while (ki--) { + if ('_id' !== keys[ki]) { + exclude = 0 === fields[keys[ki]]; + break; + } + } + } + + var paths = Object.keys(this.schema.paths) + , plen = paths.length + , ii = 0 + + for (; ii < plen; ++ii) { + var p = paths[ii]; + + if ('_id' == p) { + if (skipId) continue; + if (obj && '_id' in obj) continue; + } + + var type = this.schema.paths[p] + , path = p.split('.') + , len = path.length + , last = len-1 + , curPath = '' + , doc_ = doc + , i = 0 + + for (; i < len; ++i) { + var piece = path[i] + , def + + // support excluding intermediary levels + if (exclude) { + curPath += piece; + if (curPath in fields) break; + curPath += '.'; + } + + if (i === last) { + if (fields) { + if (exclude) { + // apply defaults to all non-excluded fields + if (p in fields) continue; + + def = type.getDefault(self, true); + if ('undefined' !== typeof def) { + doc_[piece] = def; + self.$__.activePaths.default(p); + } + + } else if (p in fields) { + // selected field + def = type.getDefault(self, true); + if ('undefined' !== typeof def) { + doc_[piece] = def; + self.$__.activePaths.default(p); + } + } + } else { + def = type.getDefault(self, true); + if ('undefined' !== typeof def) { + doc_[piece] = def; + self.$__.activePaths.default(p); + } + } + } else { + doc_ = doc_[piece] || (doc_[piece] = {}); + } + } + }; + + return doc; +}; + +/** + * Initializes the document without setters or marking anything modified. + * + * Called internally after a document is returned from mongodb. + * + * @param {Object} doc document returned by mongo + * @param {Function} fn callback + * @api private + */ + +Document.prototype.init = function (doc, opts, fn) { + // do not prefix this method with $__ since its + // used by public hooks + + if ('function' == typeof opts) { + fn = opts; + opts = null; + } + + this.isNew = false; + + // handle docs with populated paths + if (doc._id && opts && opts.populated && opts.populated.length) { + var id = String(doc._id); + for (var i = 0; i < opts.populated.length; ++i) { + var item = opts.populated[i]; + this.populated(item.path, item._docs[id], item); + } + } + + init(this, doc, this._doc); + this.$__storeShard(); + + this.emit('init', this); + if (fn) fn(null); + return this; +}; + +/*! + * Init helper. + * + * @param {Object} self document instance + * @param {Object} obj raw mongodb doc + * @param {Object} doc object we are initializing + * @api private + */ + +function init (self, obj, doc, prefix) { + prefix = prefix || ''; + + var keys = Object.keys(obj) + , len = keys.length + , schema + , path + , i; + + while (len--) { + i = keys[len]; + path = prefix + i; + schema = self.schema.path(path); + + if (!schema && utils.isObject(obj[i]) && + (!obj[i].constructor || 'Object' == obj[i].constructor.name)) { + // assume nested object + if (!doc[i]) doc[i] = {}; + init(self, obj[i], doc[i], path + '.'); + } else { + if (obj[i] === null) { + doc[i] = null; + } else if (obj[i] !== undefined) { + if (schema) { + self.$__try(function(){ + doc[i] = schema.cast(obj[i], self, true); + }); + } else { + doc[i] = obj[i]; + } + } + // mark as hydrated + self.$__.activePaths.init(path); + } + } +}; + +/** + * Stores the current values of the shard keys. + * + * ####Note: + * + * _Shard key values do not / are not allowed to change._ + * + * @api private + * @method $__storeShard + * @memberOf Document + */ + +Document.prototype.$__storeShard = function () { + // backwards compat + var key = this.schema.options.shardKey || this.schema.options.shardkey; + if (!(key && 'Object' == key.constructor.name)) return; + + var orig = this.$__.shardval = {} + , paths = Object.keys(key) + , len = paths.length + , val + + for (var i = 0; i < len; ++i) { + val = this.getValue(paths[i]); + if (isMongooseObject(val)) { + orig[paths[i]] = val.toObject({ depopulate: true }) + } else if (null != val && val.valueOf) { + orig[paths[i]] = val.valueOf(); + } else { + orig[paths[i]] = val; + } + } +} + +/*! + * Set up middleware support + */ + +for (var k in hooks) { + Document.prototype[k] = Document[k] = hooks[k]; +} + +/** + * Sends an update command with this document `_id` as the query selector. + * + * ####Example: + * + * weirdCar.update({$inc: {wheels:1}}, { w: 1 }, callback); + * + * ####Valid options: + * + * - same as in [Model.update](#model_Model.update) + * + * @see Model.update #model_Model.update + * @param {Object} doc + * @param {Object} options + * @param {Function} callback + * @return {Query} + * @api public + */ + +Document.prototype.update = function update () { + var args = utils.args(arguments); + args.unshift({_id: this._id}); + return this.constructor.update.apply(this.constructor, args); +} + +/** + * Sets the value of a path, or many paths. + * + * ####Example: + * + * // path, value + * doc.set(path, value) + * + * // object + * doc.set({ + * path : value + * , path2 : { + * path : value + * } + * }) + * + * // only-the-fly cast to number + * doc.set(path, value, Number) + * + * // only-the-fly cast to string + * doc.set(path, value, String) + * + * // changing strict mode behavior + * doc.set(path, value, { strict: false }); + * + * @param {String|Object} path path or object of key/vals to set + * @param {Any} val the value to set + * @param {Schema|String|Number|Buffer|etc..} [type] optionally specify a type for "on-the-fly" attributes + * @param {Object} [options] optionally specify options that modify the behavior of the set + * @api public + */ + +Document.prototype.set = function (path, val, type, options) { + if (type && 'Object' == type.constructor.name) { + options = type; + type = undefined; + } + + var merge = options && options.merge + , adhoc = type && true !== type + , constructing = true === type + , adhocs + + var strict = options && 'strict' in options + ? options.strict + : this.$__.strictMode; + + if (adhoc) { + adhocs = this.$__.adhocPaths || (this.$__.adhocPaths = {}); + adhocs[path] = Schema.interpretAsType(path, type); + } + + if ('string' !== typeof path) { + // new Document({ key: val }) + + if (null === path || undefined === path) { + var _ = path; + path = val; + val = _; + + } else { + var prefix = val + ? val + '.' + : ''; + + if (path instanceof Document) path = path._doc; + + var keys = Object.keys(path) + , i = keys.length + , pathtype + , key + + + while (i--) { + key = keys[i]; + pathtype = this.schema.pathType(prefix + key); + if (null != path[key] + // need to know if plain object - no Buffer, ObjectId, ref, etc + && utils.isObject(path[key]) + && (!path[key].constructor || 'Object' == path[key].constructor.name) + && 'virtual' != pathtype + && !(this.$__path(prefix + key) instanceof MixedSchema) + && !(this.schema.paths[key] && this.schema.paths[key].options.ref) + ) { + this.set(path[key], prefix + key, constructing); + } else if (strict) { + if ('real' === pathtype || 'virtual' === pathtype) { + this.set(prefix + key, path[key], constructing); + } else if ('throw' == strict) { + throw new Error("Field `" + key + "` is not in schema."); + } + } else if (undefined !== path[key]) { + this.set(prefix + key, path[key], constructing); + } + } + + return this; + } + } + + // ensure _strict is honored for obj props + // docschema = new Schema({ path: { nest: 'string' }}) + // doc.set('path', obj); + var pathType = this.schema.pathType(path); + if ('nested' == pathType && val && utils.isObject(val) && + (!val.constructor || 'Object' == val.constructor.name)) { + if (!merge) this.setValue(path, null); + this.set(val, path, constructing); + return this; + } + + var schema; + var parts = path.split('.'); + + if ('adhocOrUndefined' == pathType && strict) { + + // check for roots that are Mixed types + var mixed; + + for (var i = 0; i < parts.length; ++i) { + var subpath = parts.slice(0, i+1).join('.'); + schema = this.schema.path(subpath); + if (schema instanceof MixedSchema) { + // allow changes to sub paths of mixed types + mixed = true; + break; + } + } + + if (!mixed) { + if ('throw' == strict) { + throw new Error("Field `" + path + "` is not in schema."); + } + return this; + } + + } else if ('virtual' == pathType) { + schema = this.schema.virtualpath(path); + schema.applySetters(val, this); + return this; + } else { + schema = this.$__path(path); + } + + var pathToMark; + + // When using the $set operator the path to the field must already exist. + // Else mongodb throws: "LEFT_SUBFIELD only supports Object" + + if (parts.length <= 1) { + pathToMark = path; + } else { + for (var i = 0; i < parts.length; ++i) { + var subpath = parts.slice(0, i+1).join('.'); + if (this.isDirectModified(subpath) // earlier prefixes that are already + // marked as dirty have precedence + || this.get(subpath) === null) { + pathToMark = subpath; + break; + } + } + + if (!pathToMark) pathToMark = path; + } + + // if this doc is being constructed we should not trigger getters + var priorVal = constructing + ? undefined + : this.get(path); + + if (!schema || undefined === val) { + this.$__set(pathToMark, path, constructing, parts, schema, val, priorVal); + return this; + } + + var self = this; + var shouldSet = this.$__try(function(){ + val = schema.applySetters(val, self, false, priorVal); + }); + + if (shouldSet) { + this.$__set(pathToMark, path, constructing, parts, schema, val, priorVal); + } + + return this; +} + +/** + * Determine if we should mark this change as modified. + * + * @return {Boolean} + * @api private + * @method $__shouldModify + * @memberOf Document + */ + +Document.prototype.$__shouldModify = function ( + pathToMark, path, constructing, parts, schema, val, priorVal) { + + if (this.isNew) return true; + if (this.isDirectModified(pathToMark)) return false; + + if (undefined === val && !this.isSelected(path)) { + // when a path is not selected in a query, its initial + // value will be undefined. + return true; + } + + if (undefined === val && path in this.$__.activePaths.states.default) { + // we're just unsetting the default value which was never saved + return false; + } + + if (!deepEqual(val, priorVal || this.get(path))) { + return true; + } + + if (!constructing && + null != val && + path in this.$__.activePaths.states.default && + deepEqual(val, schema.getDefault(this, constructing))) { + // a path with a default was $unset on the server + // and the user is setting it to the same value again + return true; + } + + return false; +} + +/** + * Handles the actual setting of the value and marking the path modified if appropriate. + * + * @api private + * @method $__set + * @memberOf Document + */ + +Document.prototype.$__set = function ( + pathToMark, path, constructing, parts, schema, val, priorVal) { + + var shouldModify = this.$__shouldModify.apply(this, arguments); + + if (shouldModify) { + this.markModified(pathToMark, val); + + // handle directly setting arrays (gh-1126) + MongooseArray || (MongooseArray = require('./types/array')); + if (val instanceof MongooseArray) { + val._registerAtomic('$set', val); + } + } + + var obj = this._doc + , i = 0 + , l = parts.length + + for (; i < l; i++) { + var next = i + 1 + , last = next === l; + + if (last) { + obj[parts[i]] = val; + } else { + if (obj[parts[i]] && 'Object' === obj[parts[i]].constructor.name) { + obj = obj[parts[i]]; + } else if (obj[parts[i]] && Array.isArray(obj[parts[i]])) { + obj = obj[parts[i]]; + } else { + obj = obj[parts[i]] = {}; + } + } + } +} + +/** + * Gets a raw value from a path (no getters) + * + * @param {String} path + * @api private + */ + +Document.prototype.getValue = function (path) { + return utils.getValue(path, this._doc); +} + +/** + * Sets a raw value for a path (no casting, setters, transformations) + * + * @param {String} path + * @param {Object} value + * @api private + */ + +Document.prototype.setValue = function (path, val) { + utils.setValue(path, val, this._doc); + return this; +} + +/** + * Returns the value of a path. + * + * ####Example + * + * // path + * doc.get('age') // 47 + * + * // dynamic casting to a string + * doc.get('age', String) // "47" + * + * @param {String} path + * @param {Schema|String|Number|Buffer|etc..} [type] optionally specify a type for on-the-fly attributes + * @api public + */ + +Document.prototype.get = function (path, type) { + var adhocs; + if (type) { + adhocs = this.$__.adhocPaths || (this.$__.adhocPaths = {}); + adhocs[path] = Schema.interpretAsType(path, type); + } + + var schema = this.$__path(path) || this.schema.virtualpath(path) + , pieces = path.split('.') + , obj = this._doc; + + for (var i = 0, l = pieces.length; i < l; i++) { + obj = undefined === obj || null === obj + ? undefined + : obj[pieces[i]]; + } + + if (schema) { + obj = schema.applyGetters(obj, this); + } + + return obj; +}; + +/** + * Returns the schematype for the given `path`. + * + * @param {String} path + * @api private + * @method $__path + * @memberOf Document + */ + +Document.prototype.$__path = function (path) { + var adhocs = this.$__.adhocPaths + , adhocType = adhocs && adhocs[path]; + + if (adhocType) { + return adhocType; + } else { + return this.schema.path(path); + } +}; + +/** + * Marks the path as having pending changes to write to the db. + * + * _Very helpful when using [Mixed](./schematypes.html#mixed) types._ + * + * ####Example: + * + * doc.mixed.type = 'changed'; + * doc.markModified('mixed.type'); + * doc.save() // changes to mixed.type are now persisted + * + * @param {String} path the path to mark modified + * @api public + */ + +Document.prototype.markModified = function (path) { + this.$__.activePaths.modify(path); +} + +/** + * Catches errors that occur during execution of `fn` and stores them to later be passed when `save()` is executed. + * + * @param {Function} fn function to execute + * @param {Object} scope the scope with which to call fn + * @api private + * @method $__try + * @memberOf Document + */ + +Document.prototype.$__try = function (fn, scope) { + var res; + try { + fn.call(scope); + res = true; + } catch (e) { + this.$__error(e); + res = false; + } + return res; +}; + +/** + * Returns the list of paths that have been modified. + * + * @return {Array} + * @api public + */ + +Document.prototype.modifiedPaths = function () { + var directModifiedPaths = Object.keys(this.$__.activePaths.states.modify); + + return directModifiedPaths.reduce(function (list, path) { + var parts = path.split('.'); + return list.concat(parts.reduce(function (chains, part, i) { + return chains.concat(parts.slice(0, i).concat(part).join('.')); + }, [])); + }, []); +}; + +/** + * Returns true if this document was modified, else false. + * + * If `path` is given, checks if a path or any full path containing `path` as part of its path chain has been modified. + * + * ####Example + * + * doc.set('documents.0.title', 'changed'); + * doc.isModified() // true + * doc.isModified('documents') // true + * doc.isModified('documents.0.title') // true + * doc.isDirectModified('documents') // false + * + * @param {String} [path] optional + * @return {Boolean} + * @api public + */ + +Document.prototype.isModified = function (path) { + return path + ? !!~this.modifiedPaths().indexOf(path) + : this.$__.activePaths.some('modify'); +}; + +/** + * Returns true if `path` was directly set and modified, else false. + * + * ####Example + * + * doc.set('documents.0.title', 'changed'); + * doc.isDirectModified('documents.0.title') // true + * doc.isDirectModified('documents') // false + * + * @param {String} path + * @return {Boolean} + * @api public + */ + +Document.prototype.isDirectModified = function (path) { + return (path in this.$__.activePaths.states.modify); +}; + +/** + * Checks if `path` was initialized. + * + * @param {String} path + * @return {Boolean} + * @api public + */ + +Document.prototype.isInit = function (path) { + return (path in this.$__.activePaths.states.init); +}; + +/** + * Checks if `path` was selected in the source query which initialized this document. + * + * ####Example + * + * Thing.findOne().select('name').exec(function (err, doc) { + * doc.isSelected('name') // true + * doc.isSelected('age') // false + * }) + * + * @param {String} path + * @return {Boolean} + * @api public + */ + +Document.prototype.isSelected = function isSelected (path) { + if (this.$__.selected) { + + if ('_id' === path) { + return 0 !== this.$__.selected._id; + } + + var paths = Object.keys(this.$__.selected) + , i = paths.length + , inclusive = false + , cur + + if (1 === i && '_id' === paths[0]) { + // only _id was selected. + return 0 === this.$__.selected._id; + } + + while (i--) { + cur = paths[i]; + if ('_id' == cur) continue; + inclusive = !! this.$__.selected[cur]; + break; + } + + if (path in this.$__.selected) { + return inclusive; + } + + i = paths.length; + var pathDot = path + '.'; + + while (i--) { + cur = paths[i]; + if ('_id' == cur) continue; + + if (0 === cur.indexOf(pathDot)) { + return inclusive; + } + + if (0 === pathDot.indexOf(cur + '.')) { + return inclusive; + } + } + + return ! inclusive; + } + + return true; +} + +/** + * Executes registered validation rules for this document. + * + * ####Note: + * + * This method is called `pre` save and if a validation rule is violated, [save](#model_Model-save) is aborted and the error is returned to your `callback`. + * + * ####Example: + * + * doc.validate(function (err) { + * if (err) handleError(err); + * else // validation passed + * }); + * + * @param {Function} cb called after validation completes, passing an error if one occurred + * @api public + */ + +Document.prototype.validate = function (cb) { + var self = this + + // only validate required fields when necessary + var paths = Object.keys(this.$__.activePaths.states.require).filter(function (path) { + if (!self.isSelected(path) && !self.isModified(path)) return false; + return true; + }); + + paths = paths.concat(Object.keys(this.$__.activePaths.states.init)); + paths = paths.concat(Object.keys(this.$__.activePaths.states.modify)); + paths = paths.concat(Object.keys(this.$__.activePaths.states.default)); + + if (0 === paths.length) { + complete(); + return this; + } + + var validating = {} + , total = 0; + + paths.forEach(validatePath); + return this; + + function validatePath (path) { + if (validating[path]) return; + + validating[path] = true; + total++; + + process.nextTick(function(){ + var p = self.schema.path(path); + if (!p) return --total || complete(); + + var val = self.getValue(path); + p.doValidate(val, function (err) { + if (err) { + self.invalidate( + path + , err + , undefined + , true // embedded docs + ); + } + --total || complete(); + }, self); + }); + } + + function complete () { + var err = self.$__.validationError; + self.$__.validationError = undefined; + self.emit('validate', self); + cb(err); + } +}; + +/** + * Marks a path as invalid, causing validation to fail. + * + * The `errorMsg` argument will become the message of the `ValidationError`. + * + * The `value` argument (if passed) will be available through the `ValidationError.value` property. + * + * doc.invalidate('size', 'must be less than 20', 14); + + * doc.validate(function (err) { + * console.log(err) + * // prints + * { message: 'Validation failed', + * name: 'ValidationError', + * errors: + * { size: + * { message: 'must be less than 20', + * name: 'ValidatorError', + * path: 'size', + * type: 'user defined', + * value: 14 } } } + * }) + * + * @param {String} path the field to invalidate + * @param {String|Error} errorMsg the error which states the reason `path` was invalid + * @param {Object|String|Number|any} value optional invalid value + * @api public + */ + +Document.prototype.invalidate = function (path, err, val) { + if (!this.$__.validationError) { + this.$__.validationError = new ValidationError(this); + } + + if (!err || 'string' === typeof err) { + err = new ValidatorError(path, err, 'user defined', val) + } + + this.$__.validationError.errors[path] = err; +} + +/** + * Resets the internal modified state of this document. + * + * @api private + * @return {Document} + * @method $__reset + * @memberOf Document + */ + +Document.prototype.$__reset = function reset () { + var self = this; + DocumentArray || (DocumentArray = require('./types/documentarray')); + + this.$__.activePaths + .map('init', 'modify', function (i) { + return self.getValue(i); + }) + .filter(function (val) { + return val && val instanceof DocumentArray && val.length; + }) + .forEach(function (array) { + var i = array.length; + while (i--) { + var doc = array[i]; + if (!doc) continue; + doc.$__reset(); + } + }); + + // clear atomics + this.$__dirty().forEach(function (dirt) { + var type = dirt.value; + if (type && type._atomics) { + type._atomics = {}; + } + }); + + // Clear 'modify'('dirty') cache + this.$__.activePaths.clear('modify'); + this.$__.validationError = undefined; + this.errors = undefined; + var self = this; + this.schema.requiredPaths().forEach(function (path) { + self.$__.activePaths.require(path); + }); + + return this; +} + +/** + * Returns this documents dirty paths / vals. + * + * @api private + * @method $__dirty + * @memberOf Document + */ + +Document.prototype.$__dirty = function () { + var self = this; + + var all = this.$__.activePaths.map('modify', function (path) { + return { path: path + , value: self.getValue(path) + , schema: self.$__path(path) }; + }); + + // Sort dirty paths in a flat hierarchy. + all.sort(function (a, b) { + return (a.path < b.path ? -1 : (a.path > b.path ? 1 : 0)); + }); + + // Ignore "foo.a" if "foo" is dirty already. + var minimal = [] + , lastPath + , top; + + all.forEach(function (item, i) { + if (item.path.indexOf(lastPath) !== 0) { + lastPath = item.path + '.'; + minimal.push(item); + top = item; + } else { + // special case for top level MongooseArrays + if (top.value && top.value._atomics && top.value.hasAtomics()) { + // the `top` array itself and a sub path of `top` are being modified. + // the only way to honor all of both modifications is through a $set + // of entire array. + top.value._atomics = {}; + top.value._atomics.$set = top.value; + } + } + }); + + top = lastPath = null; + return minimal; +} + +/*! + * Compiles schemas. + */ + +function compile (tree, proto, prefix) { + var keys = Object.keys(tree) + , i = keys.length + , limb + , key; + + while (i--) { + key = keys[i]; + limb = tree[key]; + + define(key + , (('Object' === limb.constructor.name + && Object.keys(limb).length) + && (!limb.type || limb.type.type) + ? limb + : null) + , proto + , prefix + , keys); + } +}; + +/*! + * Defines the accessor named prop on the incoming prototype. + */ + +function define (prop, subprops, prototype, prefix, keys) { + var prefix = prefix || '' + , path = (prefix ? prefix + '.' : '') + prop; + + if (subprops) { + + Object.defineProperty(prototype, prop, { + enumerable: true + , get: function () { + if (!this.$__.getters) + this.$__.getters = {}; + + if (!this.$__.getters[path]) { + var nested = Object.create(this); + + // save scope for nested getters/setters + if (!prefix) nested.$__.scope = this; + + // shadow inherited getters from sub-objects so + // thing.nested.nested.nested... doesn't occur (gh-366) + var i = 0 + , len = keys.length; + + for (; i < len; ++i) { + // over-write the parents getter without triggering it + Object.defineProperty(nested, keys[i], { + enumerable: false // It doesn't show up. + , writable: true // We can set it later. + , configurable: true // We can Object.defineProperty again. + , value: undefined // It shadows its parent. + }); + } + + nested.toObject = function () { + return this.get(path); + }; + + compile(subprops, nested, path); + this.$__.getters[path] = nested; + } + + return this.$__.getters[path]; + } + , set: function (v) { + if (v instanceof Document) v = v.toObject(); + return (this.$__.scope || this).set(path, v); + } + }); + + } else { + + Object.defineProperty(prototype, prop, { + enumerable: true + , get: function ( ) { return this.get.call(this.$__.scope || this, path); } + , set: function (v) { return this.set.call(this.$__.scope || this, path, v); } + }); + } +}; + +/** + * Assigns/compiles `schema` into this documents prototype. + * + * @param {Schema} schema + * @api private + * @method $__setSchema + * @memberOf Document + */ + +Document.prototype.$__setSchema = function (schema) { + compile(schema.tree, this); + this.schema = schema; +} + +/** + * Register default hooks + * + * @api private + * @method $__registerHooks + * @memberOf Document + */ + +Document.prototype.$__registerHooks = function () { + if (!this.save) return; + + DocumentArray || (DocumentArray = require('./types/documentarray')); + + this.pre('save', function (next) { + // validate all document arrays. + // we keep the error semaphore to make sure we don't + // call `save` unnecessarily (we only need 1 error) + var subdocs = 0 + , error = false + , self = this; + + // check for DocumentArrays + var arrays = this.$__.activePaths + .map('init', 'modify', function (i) { + return self.getValue(i); + }) + .filter(function (val) { + return val && val instanceof DocumentArray && val.length; + }); + + if (!arrays.length) + return next(); + + arrays.forEach(function (array) { + if (error) return; + + // handle sparse arrays by using for loop vs array.forEach + // which skips the sparse elements + + var len = array.length + subdocs += len; + + for (var i = 0; i < len; ++i) { + if (error) break; + + var doc = array[i]; + if (!doc) { + --subdocs || next(); + continue; + } + + doc.save(handleSave); + } + }); + + function handleSave (err) { + if (error) return; + + if (err) { + self.$__.validationError = undefined; + return next(error = err); + } + + --subdocs || next(); + } + + }, function (err) { + // emit on the Model if listening + if (this.constructor.listeners('error').length) { + this.constructor.emit('error', err); + } else { + // emit on the connection + if (!this.db.listeners('error').length) { + err.stack = 'No listeners detected, throwing. ' + + 'Consider adding an error listener to your connection.\n' + + err.stack + } + this.db.emit('error', err); + } + }).pre('save', function checkForExistingErrors (next) { + // if any doc.set() calls failed + var err = this.$__.saveError; + if (err) { + this.$__.saveError = null; + next(err); + } else { + next(); + } + }).pre('save', function validation (next) { + return this.validate(next); + }); + + // add user defined queues + this.$__doQueue(); +}; + +/** + * Registers an error + * + * @param {Error} err + * @api private + * @method $__error + * @memberOf Document + */ + +Document.prototype.$__error = function (err) { + this.$__.saveError = err; + return this; +}; + +/** + * Executes methods queued from the Schema definition + * + * @api private + * @method $__doQueue + * @memberOf Document + */ + +Document.prototype.$__doQueue = function () { + var q = this.schema && this.schema.callQueue; + if (q) { + for (var i = 0, l = q.length; i < l; i++) { + this[q[i][0]].apply(this, q[i][1]); + } + } + return this; +}; + +/** + * Converts this document into a plain javascript object, ready for storage in MongoDB. + * + * Buffers are converted to instances of [mongodb.Binary](http://mongodb.github.com/node-mongodb-native/api-bson-generated/binary.html) for proper storage. + * + * ####Options: + * + * - `getters` apply all getters (path and virtual getters) + * - `virtuals` apply virtual getters (can override `getters` option) + * - `minimize` remove empty objects (defaults to true) + * - `transform` a transform function to apply to the resulting document before returning + * + * ####Getters/Virtuals + * + * Example of only applying path getters + * + * doc.toObject({ getters: true, virtuals: false }) + * + * Example of only applying virtual getters + * + * doc.toObject({ virtuals: true }) + * + * Example of applying both path and virtual getters + * + * doc.toObject({ getters: true }) + * + * To apply these options to every document of your schema by default, set your [schemas](#schema_Schema) `toObject` option to the same argument. + * + * schema.set('toObject', { virtuals: true }) + * + * ####Transform + * + * We may need to perform a transformation of the resulting object based on some criteria, say to remove some sensitive information or return a custom object. In this case we set the optional `transform` function. + * + * Transform functions receive three arguments + * + * function (doc, ret, options) {} + * + * - `doc` The mongoose document which is being converted + * - `ret` The plain object representation which has been converted + * - `options` The options in use (either schema options or the options passed inline) + * + * ####Example + * + * // specify the transform schema option + * if (!schema.options.toObject) schema.options.toObject = {}; + * schema.options.toObject.transform = function (doc, ret, options) { + * // remove the _id of every document before returning the result + * delete ret._id; + * } + * + * // without the transformation in the schema + * doc.toObject(); // { _id: 'anId', name: 'Wreck-it Ralph' } + * + * // with the transformation + * doc.toObject(); // { name: 'Wreck-it Ralph' } + * + * With transformations we can do a lot more than remove properties. We can even return completely new customized objects: + * + * if (!schema.options.toObject) schema.options.toObject = {}; + * schema.options.toObject.transform = function (doc, ret, options) { + * return { movie: ret.name } + * } + * + * // without the transformation in the schema + * doc.toObject(); // { _id: 'anId', name: 'Wreck-it Ralph' } + * + * // with the transformation + * doc.toObject(); // { movie: 'Wreck-it Ralph' } + * + * _Note: if a transform function returns `undefined`, the return value will be ignored._ + * + * Transformations may also be applied inline, overridding any transform set in the options: + * + * function xform (doc, ret, options) { + * return { inline: ret.name, custom: true } + * } + * + * // pass the transform as an inline option + * doc.toObject({ transform: xform }); // { inline: 'Wreck-it Ralph', custom: true } + * + * _Note: if you call `toObject` and pass any options, the transform declared in your schema options will __not__ be applied. To force its application pass `transform: true`_ + * + * if (!schema.options.toObject) schema.options.toObject = {}; + * schema.options.toObject.hide = '_id'; + * schema.options.toObject.transform = function (doc, ret, options) { + * if (options.hide) { + * options.hide.split(' ').forEach(function (prop) { + * delete ret[prop]; + * }); + * } + * } + * + * var doc = new Doc({ _id: 'anId', secret: 47, name: 'Wreck-it Ralph' }); + * doc.toObject(); // { secret: 47, name: 'Wreck-it Ralph' } + * doc.toObject({ hide: 'secret _id' }); // { _id: 'anId', secret: 47, name: 'Wreck-it Ralph' } + * doc.toObject({ hide: 'secret _id', transform: true }); // { name: 'Wreck-it Ralph' } + * + * Transforms are applied to the document _and each of its sub-documents_. To determine whether or not you are currently operating on a sub-document you might use the following guard: + * + * if ('function' == typeof doc.ownerDocument) { + * // working with a sub doc + * } + * + * Transforms, like all of these options, are also available for `toJSON`. + * + * See [schema options](/docs/guide.html#toObject) for some more details. + * + * _During save, no custom options are applied to the document before being sent to the database._ + * + * @param {Object} [options] + * @return {Object} js object + * @see mongodb.Binary http://mongodb.github.com/node-mongodb-native/api-bson-generated/binary.html + * @api public + */ + +Document.prototype.toObject = function (options) { + if (options && options.depopulate && this.$__.wasPopulated) { + // populated paths that we set to a document + return clone(this._id, options); + } + + // When internally saving this document we always pass options, + // bypassing the custom schema options. + if (!(options && 'Object' == options.constructor.name)) { + options = this.schema.options.toObject + ? clone(this.schema.options.toObject) + : {}; + } + + ;('minimize' in options) || (options.minimize = this.schema.options.minimize); + + var ret = clone(this._doc, options); + + if (options.virtuals || options.getters && false !== options.virtuals) { + applyGetters(this, ret, 'virtuals', options); + } + + if (options.getters) { + applyGetters(this, ret, 'paths', options); + // applyGetters for paths will add nested empty objects; + // if minimize is set, we need to remove them. + if (options.getters && options.minimize) { + ret = minimize(ret) || {}; + } + } + + // In the case where a subdocument has its own transform function, we need to + // check and see if the parent has a transform (options.transform) and if the + // child schema has a transform (this.schema.options.toObject) In this case, + // we need to adjust options.transform to be the child schema's transform and + // not the parent schema's + if (true === options.transform || + (this.schema.options.toObject && options.transform)) { + var opts = options.json + ? this.schema.options.toJSON + : this.schema.options.toObject; + if (opts) { + options.transform = opts.transform; + } + } + + if ('function' == typeof options.transform) { + var xformed = options.transform(this, ret, options); + if ('undefined' != typeof xformed) ret = xformed; + } + + return ret; +}; + +/*! + * Minimizes an object, removing undefined values and empty objects + * + * @param {Object} object to minimize + * @return {Object} + */ + +function minimize (obj) { + var keys = Object.keys(obj) + , i = keys.length + + while (i--) { + if (!Array.isArray(obj[keys[i]]) && obj[keys[i]] === Object(obj[keys[i]])) { + obj[keys[i]] = minimize(obj[keys[i]]); + } + if (obj[keys[i]] === undefined) { + delete obj[keys[i]]; + } + } + + return Object.keys(obj).length ? obj : undefined; +} + +/*! + * Applies virtuals properties to `json`. + * + * @param {Document} self + * @param {Object} json + * @param {String} type either `virtuals` or `paths` + * @return {Object} `json` + */ + +function applyGetters (self, json, type, options) { + var schema = self.schema + , paths = Object.keys(schema[type]) + , i = paths.length + , path + + while (i--) { + path = paths[i]; + + var parts = path.split('.') + , plen = parts.length + , last = plen - 1 + , branch = json + , part + + for (var ii = 0; ii < plen; ++ii) { + part = parts[ii]; + if (ii === last) { + branch[part] = clone(self.get(path), options); + } else { + branch = branch[part] || (branch[part] = {}); + } + } + } + + return json; +} + +/** + * The return value of this method is used in calls to JSON.stringify(doc). + * + * This method accepts the same options as [Document#toObject](#document_Document-toObject). To apply the options to every document of your schema by default, set your [schemas](#schema_Schema) `toJSON` option to the same argument. + * + * schema.set('toJSON', { virtuals: true }) + * + * See [schema options](/docs/guide.html#toJSON) for details. + * + * @param {Object} options + * @return {Object} + * @see Document#toObject #document_Document-toObject + * @api public + */ + +Document.prototype.toJSON = function (options) { + // check for object type since an array of documents + // being stringified passes array indexes instead + // of options objects. JSON.stringify([doc, doc]) + // The second check here is to make sure that populated documents (or + // subdocuments) use their own options for `.toJSON()` instead of their + // parent's + if (!(options && 'Object' == options.constructor.name) + || ((!options || options.json) && this.schema.options.toJSON)) { + options = this.schema.options.toJSON + ? clone(this.schema.options.toJSON) + : {}; + } + options.json = true; + + return this.toObject(options); +}; + +/** + * Helper for console.log + * + * @api public + */ + +Document.prototype.inspect = function (options) { + var opts = options && 'Object' == options.constructor.name ? options : + this.schema.options.toObject ? clone(this.schema.options.toObject) : + {}; + opts.minimize = false; + return inspect(this.toObject(opts)); +}; + +/** + * Helper for console.log + * + * @api public + * @method toString + */ + +Document.prototype.toString = Document.prototype.inspect; + +/** + * Returns true if the Document stores the same data as doc. + * + * Documents are considered equal when they have matching `_id`s. + * + * @param {Document} doc a document to compare + * @return {Boolean} + * @api public + */ + +Document.prototype.equals = function (doc) { + var tid = this.get('_id'); + var docid = doc.get('_id'); + return tid && tid.equals + ? tid.equals(docid) + : tid === docid; +} + +/** + * Populates document references, executing the `callback` when complete. + * + * ####Example: + * + * doc + * .populate('company') + * .populate({ + * path: 'notes', + * match: /airline/, + * select: 'text', + * model: 'modelName' + * options: opts + * }, function (err, user) { + * assert(doc._id == user._id) // the document itself is passed + * }) + * + * // summary + * doc.populate(path) // not executed + * doc.populate(options); // not executed + * doc.populate(path, callback) // executed + * doc.populate(options, callback); // executed + * doc.populate(callback); // executed + * + * + * ####NOTE: + * + * Population does not occur unless a `callback` is passed. + * Passing the same path a second time will overwrite the previous path options. + * See [Model.populate()](#model_Model.populate) for explaination of options. + * + * @see Model.populate #model_Model.populate + * @param {String|Object} [path] The path to populate or an options object + * @param {Function} [callback] When passed, population is invoked + * @api public + * @return {Document} this + */ + +Document.prototype.populate = function populate () { + if (0 === arguments.length) return this; + + var pop = this.$__.populate || (this.$__.populate = {}); + var args = utils.args(arguments); + var fn; + + if ('function' == typeof args[args.length-1]) { + fn = args.pop(); + } + + // allow `doc.populate(callback)` + if (args.length) { + // use hash to remove duplicate paths + var res = utils.populate.apply(null, args); + for (var i = 0; i < res.length; ++i) { + pop[res[i].path] = res[i]; + } + } + + if (fn) { + var paths = utils.object.vals(pop); + this.$__.populate = undefined; + this.constructor.populate(this, paths, fn); + } + + return this; +} + +/** + * Gets _id(s) used during population of the given `path`. + * + * ####Example: + * + * Model.findOne().populate('author').exec(function (err, doc) { + * console.log(doc.author.name) // Dr.Seuss + * console.log(doc.populated('author')) // '5144cf8050f071d979c118a7' + * }) + * + * If the path was not populated, undefined is returned. + * + * @param {String} path + * @return {Array|ObjectId|Number|Buffer|String|undefined} + * @api public + */ + +Document.prototype.populated = function (path, val, options) { + // val and options are internal + + if (null == val) { + if (!this.$__.populated) return undefined; + var v = this.$__.populated[path]; + if (v) return v.value; + return undefined; + } + + // internal + + if (true === val) { + if (!this.$__.populated) return undefined; + return this.$__.populated[path]; + } + + this.$__.populated || (this.$__.populated = {}); + this.$__.populated[path] = { value: val, options: options }; + return val; +} + +/** + * Returns the full path to this document. + * + * @param {String} [path] + * @return {String} + * @api private + * @method $__fullPath + * @memberOf Document + */ + +Document.prototype.$__fullPath = function (path) { + // overridden in SubDocuments + return path || ''; +} + +/*! + * Module exports. + */ + +Document.ValidationError = ValidationError; +module.exports = exports = Document; diff --git a/node_modules/mongoose/lib/drivers/SPEC.md b/node_modules/mongoose/lib/drivers/SPEC.md new file mode 100644 index 0000000..6464693 --- /dev/null +++ b/node_modules/mongoose/lib/drivers/SPEC.md @@ -0,0 +1,4 @@ + +# Driver Spec + +TODO diff --git a/node_modules/mongoose/lib/drivers/node-mongodb-native/binary.js b/node_modules/mongoose/lib/drivers/node-mongodb-native/binary.js new file mode 100644 index 0000000..0480d31 --- /dev/null +++ b/node_modules/mongoose/lib/drivers/node-mongodb-native/binary.js @@ -0,0 +1,8 @@ + +/*! + * Module dependencies. + */ + +var Binary = require('mongodb').BSONPure.Binary; + +module.exports = exports = Binary; diff --git a/node_modules/mongoose/lib/drivers/node-mongodb-native/collection.js b/node_modules/mongoose/lib/drivers/node-mongodb-native/collection.js new file mode 100644 index 0000000..4265021 --- /dev/null +++ b/node_modules/mongoose/lib/drivers/node-mongodb-native/collection.js @@ -0,0 +1,211 @@ + +/*! + * Module dependencies. + */ + +var MongooseCollection = require('../../collection') + , Collection = require('mongodb').Collection + , STATES = require('../../connectionstate') + , utils = require('../../utils') + +/** + * A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) collection implementation. + * + * All methods methods from the [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) driver are copied and wrapped in queue management. + * + * @inherits Collection + * @api private + */ + +function NativeCollection () { + this.collection = null; + MongooseCollection.apply(this, arguments); +} + +/*! + * Inherit from abstract Collection. + */ + +NativeCollection.prototype.__proto__ = MongooseCollection.prototype; + +/** + * Called when the connection opens. + * + * @api private + */ + +NativeCollection.prototype.onOpen = function () { + var self = this; + + // always get a new collection in case the user changed host:port + // of parent db instance when re-opening the connection. + + if (!self.opts.capped.size) { + // non-capped + return self.conn.db.collection(self.name, callback); + } + + // capped + return self.conn.db.collection(self.name, function (err, c) { + if (err) return callback(err); + + // discover if this collection exists and if it is capped + c.options(function (err, exists) { + if (err) return callback(err); + + if (exists) { + if (exists.capped) { + callback(null, c); + } else { + var msg = 'A non-capped collection exists with the name: '+ self.name +'\n\n' + + ' To use this collection as a capped collection, please ' + + 'first convert it.\n' + + ' http://www.mongodb.org/display/DOCS/Capped+Collections#CappedCollections-Convertingacollectiontocapped' + err = new Error(msg); + callback(err); + } + } else { + // create + var opts = utils.clone(self.opts.capped); + opts.capped = true; + self.conn.db.createCollection(self.name, opts, callback); + } + }); + }); + + function callback (err, collection) { + if (err) { + // likely a strict mode error + self.conn.emit('error', err); + } else { + self.collection = collection; + MongooseCollection.prototype.onOpen.call(self); + } + }; +}; + +/** + * Called when the connection closes + * + * @api private + */ + +NativeCollection.prototype.onClose = function () { + MongooseCollection.prototype.onClose.call(this); +}; + +/*! + * Copy the collection methods and make them subject to queues + */ + +for (var i in Collection.prototype) { + (function(i){ + NativeCollection.prototype[i] = function () { + if (this.buffer) { + this.addQueue(i, arguments); + return; + } + + var collection = this.collection + , args = arguments + , self = this + , debug = self.conn.base.options.debug; + + if (debug) { + if ('function' === typeof debug) { + debug.apply(debug + , [self.name, i].concat(utils.args(args, 0, args.length-1))); + } else { + console.error('\x1B[0;36mMongoose:\x1B[0m %s.%s(%s) %s %s %s' + , self.name + , i + , print(args[0]) + , print(args[1]) + , print(args[2]) + , print(args[3])) + } + } + + return collection[i].apply(collection, args); + }; + })(i); +} + +/*! + * Debug print helper + */ + +function print (arg) { + var type = typeof arg; + if ('function' === type || 'undefined' === type) return ''; + return format(arg); +} + +/*! + * Debug print helper + */ + +function format (obj, sub) { + var x = utils.clone(obj); + if (x) { + if ('Binary' === x.constructor.name) { + x = '[object Buffer]'; + } else if ('ObjectID' === x.constructor.name) { + var representation = 'ObjectId("' + x.toHexString() + '")'; + x = { inspect: function() { return representation; } }; + } else if ('Date' === x.constructor.name) { + var representation = 'new Date("' + x.toUTCString() + '")'; + x = { inspect: function() { return representation; } }; + } else if ('Object' === x.constructor.name) { + var keys = Object.keys(x) + , i = keys.length + , key + while (i--) { + key = keys[i]; + if (x[key]) { + if ('Binary' === x[key].constructor.name) { + x[key] = '[object Buffer]'; + } else if ('Object' === x[key].constructor.name) { + x[key] = format(x[key], true); + } else if ('ObjectID' === x[key].constructor.name) { + ;(function(x){ + var representation = 'ObjectId("' + x[key].toHexString() + '")'; + x[key] = { inspect: function() { return representation; } }; + })(x) + } else if ('Date' === x[key].constructor.name) { + ;(function(x){ + var representation = 'new Date("' + x[key].toUTCString() + '")'; + x[key] = { inspect: function() { return representation; } }; + })(x) + } else if (Array.isArray(x[key])) { + x[key] = x[key].map(function (o) { + return format(o, true) + }); + } + } + } + } + if (sub) return x; + } + + return require('util') + .inspect(x, false, 10, true) + .replace(/\n/g, '') + .replace(/\s{2,}/g, ' ') +} + +/** + * Retreives information about this collections indexes. + * + * @param {Function} callback + * @method getIndexes + * @api public + */ + +NativeCollection.prototype.getIndexes = NativeCollection.prototype.indexInformation; + +/*! + * Module exports. + */ + +module.exports = NativeCollection; diff --git a/node_modules/mongoose/lib/drivers/node-mongodb-native/connection.js b/node_modules/mongoose/lib/drivers/node-mongodb-native/connection.js new file mode 100644 index 0000000..b4f3520 --- /dev/null +++ b/node_modules/mongoose/lib/drivers/node-mongodb-native/connection.js @@ -0,0 +1,371 @@ +/*! + * Module dependencies. + */ + +var MongooseConnection = require('../../connection') + , mongo = require('mongodb') + , Db = mongo.Db + , Server = mongo.Server + , Mongos = mongo.Mongos + , STATES = require('../../connectionstate') + , ReplSetServers = mongo.ReplSetServers + , utils = require('../../utils'); + +/** + * A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) connection implementation. + * + * @inherits Connection + * @api private + */ + +function NativeConnection() { + MongooseConnection.apply(this, arguments); + this._listening = false; +}; + +/** + * Expose the possible connection states. + * @api public + */ + +NativeConnection.STATES = STATES; + +/*! + * Inherits from Connection. + */ + +NativeConnection.prototype.__proto__ = MongooseConnection.prototype; + +/** + * Opens the connection to MongoDB. + * + * @param {Function} fn + * @return {Connection} this + * @api private + */ + +NativeConnection.prototype.doOpen = function (fn) { + if (this.db) { + mute(this); + } + + var server = new Server(this.host, this.port, this.options.server); + this.db = new Db(this.name, server, this.options.db); + + var self = this; + this.db.open(function (err) { + if (err) return fn(err); + listen(self); + fn(); + }); + + return this; +}; + +/** + * Switches to a different database using the same connection pool. + * + * Returns a new connection object, with the new db. + * + * @param {String} name The database name + * @return {Connection} New Connection Object + * @api public + */ + +NativeConnection.prototype.useDb = function (name) { + // we have to manually copy all of the attributes... + var newConn = new this.constructor(); + newConn.name = name; + newConn.base = this.base; + newConn.collections = {}; + newConn.models = {}; + newConn.replica = this.replica; + newConn.hosts = this.hosts; + newConn.host = this.host; + newConn.port = this.port; + newConn.user = this.user; + newConn.pass = this.pass; + newConn.options = this.options; + newConn._readyState = this._readyState; + newConn._closeCalled = this._closeCalled; + newConn._hasOpened = this._hasOpened; + newConn._listening = false; + + // First, when we create another db object, we are not guaranteed to have a + // db object to work with. So, in the case where we have a db object and it + // is connected, we can just proceed with setting everything up. However, if + // we do not have a db or the state is not connected, then we need to wait on + // the 'open' event of the connection before doing the rest of the setup + // the 'connected' event is the first time we'll have access to the db object + + var self = this; + + if (this.db && this.db._state == 'connected') { + wireup(); + } else { + this.once('connected', wireup); + } + + function wireup () { + newConn.db = self.db.db(name); + newConn.onOpen(); + // setup the events appropriately + listen(newConn); + } + + newConn.name = name; + + // push onto the otherDbs stack, this is used when state changes + this.otherDbs.push(newConn); + newConn.otherDbs.push(this); + + return newConn; +}; + +/*! + * Register listeners for important events and bubble appropriately. + */ + +function listen (conn) { + if (conn._listening) return; + conn._listening = true; + + conn.db.on('close', function(){ + if (conn._closeCalled) return; + + // the driver never emits an `open` event. auto_reconnect still + // emits a `close` event but since we never get another + // `open` we can't emit close + if (conn.db.serverConfig.autoReconnect) { + conn.readyState = STATES.disconnected; + conn.emit('close'); + return; + } + conn.onClose(); + }); + conn.db.on('error', function(err){ + conn.emit('error', err); + }); + conn.db.on('timeout', function(err){ + var error = new Error(err && err.err || 'connection timeout'); + conn.emit('error', error); + }); + conn.db.on('open', function (err, db) { + if (STATES.disconnected === conn.readyState && db && db.databaseName) { + conn.readyState = STATES.connected; + conn.emit('reconnected') + } + }) +} + +/*! + * Remove listeners registered in `listen` + */ + +function mute (conn) { + if (!conn.db) throw new Error('missing db'); + conn.db.removeAllListeners("close"); + conn.db.removeAllListeners("error"); + conn.db.removeAllListeners("timeout"); + conn.db.removeAllListeners("open"); + conn.db.removeAllListeners("fullsetup"); + conn._listening = false; +} + +/** + * Opens a connection to a MongoDB ReplicaSet. + * + * See description of [doOpen](#NativeConnection-doOpen) for server options. In this case `options.replset` is also passed to ReplSetServers. + * + * @param {Function} fn + * @api private + * @return {Connection} this + */ + +NativeConnection.prototype.doOpenSet = function (fn) { + if (this.db) { + mute(this); + } + + var servers = [] + , self = this; + + this.hosts.forEach(function (server) { + var host = server.host || server.ipc; + var port = server.port || 27017; + servers.push(new Server(host, port, self.options.server)); + }) + + var server = this.options.mongos + ? new Mongos(servers, this.options.mongos) + : new ReplSetServers(servers, this.options.replset); + this.db = new Db(this.name, server, this.options.db); + + this.db.on('fullsetup', function () { + self.emit('fullsetup') + }); + + this.db.open(function (err) { + if (err) return fn(err); + fn(); + listen(self); + }); + + return this; +}; + +/** + * Closes the connection + * + * @param {Function} fn + * @return {Connection} this + * @api private + */ + +NativeConnection.prototype.doClose = function (fn) { + this.db.close(); + if (fn) fn(); + return this; +} + +/** + * Prepares default connection options for the node-mongodb-native driver. + * + * _NOTE: `passed` options take precedence over connection string options._ + * + * @param {Object} passed options that were passed directly during connection + * @param {Object} [connStrOptions] options that were passed in the connection string + * @api private + */ + +NativeConnection.prototype.parseOptions = function (passed, connStrOpts) { + var o = passed || {}; + o.db || (o.db = {}); + o.auth || (o.auth = {}); + o.server || (o.server = {}); + o.replset || (o.replset = {}); + o.server.socketOptions || (o.server.socketOptions = {}); + o.replset.socketOptions || (o.replset.socketOptions = {}); + + var opts = connStrOpts || {}; + Object.keys(opts).forEach(function (name) { + switch (name) { + case 'poolSize': + if ('undefined' == typeof o.server.poolSize) { + o.server.poolSize = o.replset.poolSize = opts[name]; + } + break; + case 'slaveOk': + if ('undefined' == typeof o.server.slave_ok) { + o.server.slave_ok = opts[name]; + } + break; + case 'autoReconnect': + if ('undefined' == typeof o.server.auto_reconnect) { + o.server.auto_reconnect = opts[name]; + } + break; + case 'ssl': + case 'socketTimeoutMS': + case 'connectTimeoutMS': + if ('undefined' == typeof o.server.socketOptions[name]) { + o.server.socketOptions[name] = o.replset.socketOptions[name] = opts[name]; + } + break; + case 'authdb': + if ('undefined' == typeof o.auth.authdb) { + o.auth.authdb = opts[name]; + } + break; + case 'authSource': + if ('undefined' == typeof o.auth.authSource) { + o.auth.authSource = opts[name]; + } + break; + case 'retries': + case 'reconnectWait': + case 'rs_name': + if ('undefined' == typeof o.replset[name]) { + o.replset[name] = opts[name]; + } + break; + case 'replicaSet': + if ('undefined' == typeof o.replset.rs_name) { + o.replset.rs_name = opts[name]; + } + break; + case 'readSecondary': + if ('undefined' == typeof o.replset.read_secondary) { + o.replset.read_secondary = opts[name]; + } + break; + case 'nativeParser': + if ('undefined' == typeof o.db.native_parser) { + o.db.native_parser = opts[name]; + } + break; + case 'w': + case 'safe': + case 'fsync': + case 'journal': + case 'wtimeoutMS': + if ('undefined' == typeof o.db[name]) { + o.db[name] = opts[name]; + } + break; + case 'readPreference': + if ('undefined' == typeof o.db.read_preference) { + o.db.read_preference = opts[name]; + } + break; + case 'readPreferenceTags': + if ('undefined' == typeof o.db.read_preference_tags) { + o.db.read_preference_tags = opts[name]; + } + break; + } + }) + + if (!('auto_reconnect' in o.server)) { + o.server.auto_reconnect = true; + } + + if (!o.db.read_preference) { + // read from primaries by default + o.db.read_preference = 'primary'; + } + + // mongoose creates its own ObjectIds + o.db.forceServerObjectId = false; + + // default safe using new nomenclature + if (!('journal' in o.db || 'j' in o.db || + 'fsync' in o.db || 'safe' in o.db || 'w' in o.db)) { + o.db.w = 1; + } + + validate(o); + return o; +} + +/*! + * Validates the driver db options. + * + * @param {Object} o + */ + +function validate (o) { + if (-1 === o.db.w || 0 === o.db.w) { + if (o.db.journal || o.db.fsync || o.db.safe) { + throw new Error( + 'Invalid writeConcern: ' + + 'w set to -1 or 0 cannot be combined with safe|fsync|journal'); + } + } +} + +/*! + * Module exports. + */ + +module.exports = NativeConnection; diff --git a/node_modules/mongoose/lib/drivers/node-mongodb-native/objectid.js b/node_modules/mongoose/lib/drivers/node-mongodb-native/objectid.js new file mode 100644 index 0000000..d00e007 --- /dev/null +++ b/node_modules/mongoose/lib/drivers/node-mongodb-native/objectid.js @@ -0,0 +1,15 @@ + +/*! + * [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) ObjectId + * @constructor NodeMongoDbObjectId + * @see ObjectId + */ + +var ObjectId = require('mongodb').BSONPure.ObjectID; + +/*! + * ignore + */ + +module.exports = exports = ObjectId; + diff --git a/node_modules/mongoose/lib/error.js b/node_modules/mongoose/lib/error.js new file mode 100644 index 0000000..f4e308c --- /dev/null +++ b/node_modules/mongoose/lib/error.js @@ -0,0 +1,63 @@ + +/** + * MongooseError constructor + * + * @param {String} msg Error message + * @inherits Error https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error + */ + +function MongooseError (msg) { + Error.call(this); + Error.captureStackTrace(this, arguments.callee); + this.message = msg; + this.name = 'MongooseError'; +}; + +/*! + * Formats error messages + */ + +MongooseError.prototype.formatMessage = function (msg, path, type, val) { + if (!msg) throw new TypeError('message is required'); + + return msg.replace(/{PATH}/, path) + .replace(/{VALUE}/, String(val||'')) + .replace(/{TYPE}/, type || 'declared type'); +} + +/*! + * Inherits from Error. + */ + +MongooseError.prototype.__proto__ = Error.prototype; + +/*! + * Module exports. + */ + +module.exports = exports = MongooseError; + +/** + * The default built-in validator error messages. + * + * @see Error.messages #error_messages_MongooseError-messages + * @api public + */ + +MongooseError.messages = require('./error/messages'); + +// backward compat +MongooseError.Messages = MongooseError.messages; + +/*! + * Expose subclasses + */ + +MongooseError.CastError = require('./error/cast'); +MongooseError.ValidationError = require('./error/validation') +MongooseError.ValidatorError = require('./error/validator') +MongooseError.VersionError =require('./error/version') +MongooseError.OverwriteModelError = require('./error/overwriteModel') +MongooseError.MissingSchemaError = require('./error/missingSchema') +MongooseError.DivergentArrayError = require('./error/divergentArray') + diff --git a/node_modules/mongoose/lib/error/cast.js b/node_modules/mongoose/lib/error/cast.js new file mode 100644 index 0000000..9e383fa --- /dev/null +++ b/node_modules/mongoose/lib/error/cast.js @@ -0,0 +1,35 @@ +/*! + * Module dependencies. + */ + +var MongooseError = require('../error.js'); + +/** + * Casting Error constructor. + * + * @param {String} type + * @param {String} value + * @inherits MongooseError + * @api private + */ + +function CastError (type, value, path) { + MongooseError.call(this, 'Cast to ' + type + ' failed for value "' + value + '" at path "' + path + '"'); + Error.captureStackTrace(this, arguments.callee); + this.name = 'CastError'; + this.type = type; + this.value = value; + this.path = path; +}; + +/*! + * Inherits from MongooseError. + */ + +CastError.prototype.__proto__ = MongooseError.prototype; + +/*! + * exports + */ + +module.exports = CastError; diff --git a/node_modules/mongoose/lib/error/divergentArray.js b/node_modules/mongoose/lib/error/divergentArray.js new file mode 100644 index 0000000..5fe0db6 --- /dev/null +++ b/node_modules/mongoose/lib/error/divergentArray.js @@ -0,0 +1,40 @@ + +/*! + * Module dependencies. + */ + +var MongooseError = require('../error.js'); + +/*! + * DivergentArrayError constructor. + * + * @inherits MongooseError + */ + +function DivergentArrayError (paths) { + var msg = 'For your own good, using `document.save()` to update an array ' + + 'which was selected using an $elemMatch projection OR ' + + 'populated using skip, limit, query conditions, or exclusion of ' + + 'the _id field when the operation results in a $pop or $set of ' + + 'the entire array is not supported. The following ' + + 'path(s) would have been modified unsafely:\n' + + ' ' + paths.join('\n ') + '\n' + + 'Use Model.update() to update these arrays instead.' + // TODO write up a docs page (FAQ) and link to it + + MongooseError.call(this, msg); + Error.captureStackTrace(this, arguments.callee); + this.name = 'DivergentArrayError'; +}; + +/*! + * Inherits from MongooseError. + */ + +DivergentArrayError.prototype.__proto__ = MongooseError.prototype; + +/*! + * exports + */ + +module.exports = DivergentArrayError; diff --git a/node_modules/mongoose/lib/error/messages.js b/node_modules/mongoose/lib/error/messages.js new file mode 100644 index 0000000..ccafb81 --- /dev/null +++ b/node_modules/mongoose/lib/error/messages.js @@ -0,0 +1,37 @@ + +/** + * The default built-in validator error messages. These may be customized. + * + * // customize within each schema or globally like so + * var mongoose = require('mongoose'); + * mongoose.Error.messages.String.enum = "Your custom message for {PATH}."; + * + * As you might have noticed, error messages support basic templating + * + * - `{PATH}` is replaced with the invalid document path + * - `{VALUE}` is replaced with the invalid value + * - `{TYPE}` is replaced with the validator type such as "regexp", "min", or "user defined" + * - `{MIN}` is replaced with the declared min value for the Number.min validator + * - `{MAX}` is replaced with the declared max value for the Number.max validator + * + * Click the "show code" link below to see all defaults. + * + * @property messages + * @receiver MongooseError + * @api public + */ + +var msg = module.exports = exports = {}; + +msg.general = {}; +msg.general.default = "Validator failed for path `{PATH}` with value `{VALUE}`"; +msg.general.required = "Path `{PATH}` is required."; + +msg.Number = {}; +msg.Number.min = "Path `{PATH}` ({VALUE}) is less than minimum allowed value ({MIN})."; +msg.Number.max = "Path `{PATH}` ({VALUE}) is more than maximum allowed value ({MAX})."; + +msg.String = {}; +msg.String.enum = "`{VALUE}` is not a valid enum value for path `{PATH}`."; +msg.String.match = "Path `{PATH}` is invalid ({VALUE})."; + diff --git a/node_modules/mongoose/lib/error/missingSchema.js b/node_modules/mongoose/lib/error/missingSchema.js new file mode 100644 index 0000000..7d80e2f --- /dev/null +++ b/node_modules/mongoose/lib/error/missingSchema.js @@ -0,0 +1,32 @@ + +/*! + * Module dependencies. + */ + +var MongooseError = require('../error.js'); + +/*! + * MissingSchema Error constructor. + * + * @inherits MongooseError + */ + +function MissingSchemaError (name) { + var msg = 'Schema hasn\'t been registered for model "' + name + '".\n' + + 'Use mongoose.model(name, schema)'; + MongooseError.call(this, msg); + Error.captureStackTrace(this, arguments.callee); + this.name = 'MissingSchemaError'; +}; + +/*! + * Inherits from MongooseError. + */ + +MissingSchemaError.prototype.__proto__ = MongooseError.prototype; + +/*! + * exports + */ + +module.exports = MissingSchemaError; diff --git a/node_modules/mongoose/lib/error/overwriteModel.js b/node_modules/mongoose/lib/error/overwriteModel.js new file mode 100644 index 0000000..ee13cb9 --- /dev/null +++ b/node_modules/mongoose/lib/error/overwriteModel.js @@ -0,0 +1,30 @@ + +/*! + * Module dependencies. + */ + +var MongooseError = require('../error.js'); + +/*! + * OverwriteModel Error constructor. + * + * @inherits MongooseError + */ + +function OverwriteModelError (name) { + MongooseError.call(this, 'Cannot overwrite `' + name + '` model once compiled.'); + Error.captureStackTrace(this, arguments.callee); + this.name = 'OverwriteModelError'; +}; + +/*! + * Inherits from MongooseError. + */ + +OverwriteModelError.prototype.__proto__ = MongooseError.prototype; + +/*! + * exports + */ + +module.exports = OverwriteModelError; diff --git a/node_modules/mongoose/lib/error/validation.js b/node_modules/mongoose/lib/error/validation.js new file mode 100644 index 0000000..b05706c --- /dev/null +++ b/node_modules/mongoose/lib/error/validation.js @@ -0,0 +1,49 @@ + +/*! + * Module requirements + */ + +var MongooseError = require('../error.js') + +/** + * Document Validation Error + * + * @api private + * @param {Document} instance + * @inherits MongooseError + */ + +function ValidationError (instance) { + MongooseError.call(this, "Validation failed"); + Error.captureStackTrace(this, arguments.callee); + this.name = 'ValidationError'; + this.errors = instance.errors = {}; +}; + +/** + * Console.log helper + */ + +ValidationError.prototype.toString = function () { + var ret = this.name + ': '; + var msgs = []; + + Object.keys(this.errors).forEach(function (key) { + if (this == this.errors[key]) return; + msgs.push(String(this.errors[key])); + }, this) + + return ret + msgs.join(', '); +}; + +/*! + * Inherits from MongooseError. + */ + +ValidationError.prototype.__proto__ = MongooseError.prototype; + +/*! + * Module exports + */ + +module.exports = exports = ValidationError; diff --git a/node_modules/mongoose/lib/error/validator.js b/node_modules/mongoose/lib/error/validator.js new file mode 100644 index 0000000..965c00c --- /dev/null +++ b/node_modules/mongoose/lib/error/validator.js @@ -0,0 +1,47 @@ +/*! + * Module dependencies. + */ + +var MongooseError = require('../error.js'); +var errorMessages = MongooseError.messages; + +/** + * Schema validator error + * + * @param {String} path + * @param {String} msg + * @param {String|Number|any} val + * @inherits MongooseError + * @api private + */ + +function ValidatorError (path, msg, type, val) { + if (!msg) msg = errorMessages.general.default; + var message = this.formatMessage(msg, path, type, val); + MongooseError.call(this, message); + Error.captureStackTrace(this, arguments.callee); + this.name = 'ValidatorError'; + this.path = path; + this.type = type; + this.value = val; +}; + +/*! + * toString helper + */ + +ValidatorError.prototype.toString = function () { + return this.message; +} + +/*! + * Inherits from MongooseError + */ + +ValidatorError.prototype.__proto__ = MongooseError.prototype; + +/*! + * exports + */ + +module.exports = ValidatorError; diff --git a/node_modules/mongoose/lib/error/version.js b/node_modules/mongoose/lib/error/version.js new file mode 100644 index 0000000..514e4dc --- /dev/null +++ b/node_modules/mongoose/lib/error/version.js @@ -0,0 +1,31 @@ + +/*! + * Module dependencies. + */ + +var MongooseError = require('../error.js'); + +/** + * Version Error constructor. + * + * @inherits MongooseError + * @api private + */ + +function VersionError () { + MongooseError.call(this, 'No matching document found.'); + Error.captureStackTrace(this, arguments.callee); + this.name = 'VersionError'; +}; + +/*! + * Inherits from MongooseError. + */ + +VersionError.prototype.__proto__ = MongooseError.prototype; + +/*! + * exports + */ + +module.exports = VersionError; diff --git a/node_modules/mongoose/lib/index.js b/node_modules/mongoose/lib/index.js new file mode 100644 index 0000000..c52ee0c --- /dev/null +++ b/node_modules/mongoose/lib/index.js @@ -0,0 +1,641 @@ +'use strict'; + +/*! + * Module dependencies. + */ + +var Schema = require('./schema') + , SchemaType = require('./schematype') + , VirtualType = require('./virtualtype') + , SchemaDefaults = require('./schemadefault') + , Types = require('./types') + , Query = require('./query') + , Promise = require('./promise') + , Model = require('./model') + , Document = require('./document') + , utils = require('./utils') + , format = utils.toCollectionName + , mongodb = require('mongodb') + , pkg = require('../package.json') + +/*! + * Warn users if they are running an unstable release. + * + * Disable the warning by setting the MONGOOSE_DISABLE_STABILITY_WARNING + * environment variable. + */ + +if (pkg.publishConfig && 'unstable' == pkg.publishConfig.tag) { + if (!process.env.MONGOOSE_DISABLE_STABILITY_WARNING) { + console.log('\u001b[33m'); + console.log('##############################################################'); + console.log('#'); + console.log('# !!! MONGOOSE WARNING !!!'); + console.log('#'); + console.log('# This is an UNSTABLE release of Mongoose.'); + console.log('# Unstable releases are available for preview/testing only.'); + console.log('# DO NOT run this in production.'); + console.log('#'); + console.log('##############################################################'); + console.log('\u001b[0m'); + } +} + +/** + * Mongoose constructor. + * + * The exports object of the `mongoose` module is an instance of this class. + * Most apps will only use this one instance. + * + * @api public + */ + +function Mongoose () { + this.connections = []; + this.plugins = []; + this.models = {}; + this.modelSchemas = {}; + // default global options + this.options = { + pluralization: true + }; + this.createConnection(); // default connection +}; + +/** + * Sets mongoose options + * + * ####Example: + * + * mongoose.set('test', value) // sets the 'test' option to `value` + * + * mongoose.set('debug', true) // enable logging collection methods + arguments to the console + * + * @param {String} key + * @param {String} value + * @api public + */ + +Mongoose.prototype.set = function (key, value) { + if (arguments.length == 1) { + return this.options[key]; + } + + this.options[key] = value; + return this; +}; + +/** + * Gets mongoose options + * + * ####Example: + * + * mongoose.get('test') // returns the 'test' value + * + * @param {String} key + * @method get + * @api public + */ + +Mongoose.prototype.get = Mongoose.prototype.set; + +/*! + * ReplSet connection string check. + */ + +var rgxReplSet = /^.+,.+$/; + +/** + * Creates a Connection instance. + * + * Each `connection` instance maps to a single database. This method is helpful when mangaging multiple db connections. + * + * If arguments are passed, they are proxied to either [Connection#open](#connection_Connection-open) or [Connection#openSet](#connection_Connection-openSet) appropriately. This means we can pass `db`, `server`, and `replset` options to the driver. _Note that the `safe` option specified in your schema will overwrite the `safe` db option specified here unless you set your schemas `safe` option to `undefined`. See [this](/docs/guide.html#safe) for more information._ + * + * _Options passed take precedence over options included in connection strings._ + * + * ####Example: + * + * // with mongodb:// URI + * db = mongoose.createConnection('mongodb://user:pass@localhost:port/database'); + * + * // and options + * var opts = { db: { native_parser: true }} + * db = mongoose.createConnection('mongodb://user:pass@localhost:port/database', opts); + * + * // replica sets + * db = mongoose.createConnection('mongodb://user:pass@localhost:port/database,mongodb://anotherhost:port,mongodb://yetanother:port'); + * + * // and options + * var opts = { replset: { strategy: 'ping', rs_name: 'testSet' }} + * db = mongoose.createConnection('mongodb://user:pass@localhost:port/database,mongodb://anotherhost:port,mongodb://yetanother:port', opts); + * + * // with [host, database_name[, port] signature + * db = mongoose.createConnection('localhost', 'database', port) + * + * // and options + * var opts = { server: { auto_reconnect: false }, user: 'username', pass: 'mypassword' } + * db = mongoose.createConnection('localhost', 'database', port, opts) + * + * // initialize now, connect later + * db = mongoose.createConnection(); + * db.open('localhost', 'database', port, [opts]); + * + * @param {String} [uri] a mongodb:// URI + * @param {Object} [options] options to pass to the driver + * @see Connection#open #connection_Connection-open + * @see Connection#openSet #connection_Connection-openSet + * @return {Connection} the created Connection object + * @api public + */ + +Mongoose.prototype.createConnection = function () { + var conn = new Connection(this); + this.connections.push(conn); + + if (arguments.length) { + if (rgxReplSet.test(arguments[0])) { + conn.openSet.apply(conn, arguments); + } else { + conn.open.apply(conn, arguments); + } + } + + return conn; +}; + +/** + * Opens the default mongoose connection. + * + * If arguments are passed, they are proxied to either [Connection#open](#connection_Connection-open) or [Connection#openSet](#connection_Connection-openSet) appropriately. + * + * _Options passed take precedence over options included in connection strings._ + * + * ####Example: + * + * mongoose.connect('mongodb://user:pass@localhost:port/database'); + * + * // replica sets + * var uri = 'mongodb://user:pass@localhost:port/database,mongodb://anotherhost:port,mongodb://yetanother:port'; + * mongoose.connect(uri); + * + * // with options + * mongoose.connect(uri, options); + * + * // connecting to multiple mongos + * var uri = 'mongodb://hostA:27501,hostB:27501'; + * var opts = { mongos: true }; + * mongoose.connect(uri, opts); + * + * @param {String} uri(s) + * @param {Object} [options] + * @param {Function} [callback] + * @see Mongoose#createConnection #index_Mongoose-createConnection + * @api public + * @return {Mongoose} this + */ + +Mongoose.prototype.connect = function () { + var conn = this.connection; + + if (rgxReplSet.test(arguments[0])) { + conn.openSet.apply(conn, arguments); + } else { + conn.open.apply(conn, arguments); + } + + return this; +}; + +/** + * Disconnects all connections. + * + * @param {Function} [fn] called after all connection close. + * @return {Mongoose} this + * @api public + */ + +Mongoose.prototype.disconnect = function (fn) { + var count = this.connections.length + , error + + this.connections.forEach(function(conn){ + conn.close(function(err){ + if (error) return; + + if (err) { + error = err; + if (fn) return fn(err); + throw err; + } + + if (fn) + --count || fn(); + }); + }); + return this; +}; + +/** + * Defines a model or retrieves it. + * + * Models defined on the `mongoose` instance are available to all connection created by the same `mongoose` instance. + * + * ####Example: + * + * var mongoose = require('mongoose'); + * + * // define an Actor model with this mongoose instance + * mongoose.model('Actor', new Schema({ name: String })); + * + * // create a new connection + * var conn = mongoose.createConnection(..); + * + * // retrieve the Actor model + * var Actor = conn.model('Actor'); + * + * _When no `collection` argument is passed, Mongoose produces a collection name by passing the model `name` to the [utils.toCollectionName](#utils_exports.toCollectionName) method. This method pluralizes the name. If you don't like this behavior, either pass a collection name or set your schemas collection name option._ + * + * ####Example: + * + * var schema = new Schema({ name: String }, { collection: 'actor' }); + * + * // or + * + * schema.set('collection', 'actor'); + * + * // or + * + * var collectionName = 'actor' + * var M = mongoose.model('Actor', schema, collectionName) + * + * @param {String} name model name + * @param {Schema} [schema] + * @param {String} [collection] name (optional, induced from model name) + * @param {Boolean} [skipInit] whether to skip initialization (defaults to false) + * @api public + */ + +Mongoose.prototype.model = function (name, schema, collection, skipInit) { + if ('string' == typeof schema) { + collection = schema; + schema = false; + } + + if (utils.isObject(schema) && !(schema instanceof Schema)) { + schema = new Schema(schema); + } + + if ('boolean' === typeof collection) { + skipInit = collection; + collection = null; + } + + // handle internal options from connection.model() + var options; + if (skipInit && utils.isObject(skipInit)) { + options = skipInit; + skipInit = true; + } else { + options = {}; + } + + // look up schema for the collection. this might be a + // default schema like system.indexes stored in SchemaDefaults. + if (!this.modelSchemas[name]) { + if (!schema && name in SchemaDefaults) { + schema = SchemaDefaults[name]; + } + + if (schema) { + // cache it so we only apply plugins once + this.modelSchemas[name] = schema; + this._applyPlugins(schema); + } else { + throw new mongoose.Error.MissingSchemaError(name); + } + } + + var model; + var sub; + + // connection.model() may be passing a different schema for + // an existing model name. in this case don't read from cache. + if (this.models[name] && false !== options.cache) { + if (schema instanceof Schema && schema != this.models[name].schema) { + throw new mongoose.Error.OverwriteModelError(name); + } + + if (collection) { + // subclass current model with alternate collection + model = this.models[name]; + schema = model.prototype.schema; + sub = model.__subclass(this.connection, schema, collection); + // do not cache the sub model + return sub; + } + + return this.models[name]; + } + + // ensure a schema exists + if (!schema) { + schema = this.modelSchemas[name]; + if (!schema) { + throw new mongoose.Error.MissingSchemaError(name); + } + } + + // Apply relevant "global" options to the schema + if (!('pluralization' in schema.options)) schema.options.pluralization = this.options.pluralization; + + + if (!collection) { + collection = schema.get('collection') || format(name, schema.options); + } + + var connection = options.connection || this.connection; + model = Model.compile(name, schema, collection, connection, this); + + if (!skipInit) { + model.init(); + } + + if (false === options.cache) { + return model; + } + + return this.models[name] = model; +} + +/** + * Returns an array of model names created on this instance of Mongoose. + * + * ####Note: + * + * _Does not include names of models created using `connection.model()`._ + * + * @api public + * @return {Array} + */ + +Mongoose.prototype.modelNames = function () { + var names = Object.keys(this.models); + return names; +} + +/** + * Applies global plugins to `schema`. + * + * @param {Schema} schema + * @api private + */ + +Mongoose.prototype._applyPlugins = function (schema) { + for (var i = 0, l = this.plugins.length; i < l; i++) { + schema.plugin(this.plugins[i][0], this.plugins[i][1]); + } +} + +/** + * Declares a global plugin executed on all Schemas. + * + * Equivalent to calling `.plugin(fn)` on each Schema you create. + * + * @param {Function} fn plugin callback + * @param {Object} [opts] optional options + * @return {Mongoose} this + * @see plugins ./plugins.html + * @api public + */ + +Mongoose.prototype.plugin = function (fn, opts) { + this.plugins.push([fn, opts]); + return this; +}; + +/** + * The default connection of the mongoose module. + * + * ####Example: + * + * var mongoose = require('mongoose'); + * mongoose.connect(...); + * mongoose.connection.on('error', cb); + * + * This is the connection used by default for every model created using [mongoose.model](#index_Mongoose-model). + * + * @property connection + * @return {Connection} + * @api public + */ + +Mongoose.prototype.__defineGetter__('connection', function(){ + return this.connections[0]; +}); + +/*! + * Driver depentend APIs + */ + +var driver = global.MONGOOSE_DRIVER_PATH || './drivers/node-mongodb-native'; + +/*! + * Connection + */ + +var Connection = require(driver + '/connection'); + +/*! + * Collection + */ + +var Collection = require(driver + '/collection'); + +/** + * The Mongoose Collection constructor + * + * @method Collection + * @api public + */ + +Mongoose.prototype.Collection = Collection; + +/** + * The Mongoose [Connection](#connection_Connection) constructor + * + * @method Connection + * @api public + */ + +Mongoose.prototype.Connection = Connection; + +/** + * The Mongoose version + * + * @property version + * @api public + */ + +Mongoose.prototype.version = pkg.version; + +/** + * The Mongoose constructor + * + * The exports of the mongoose module is an instance of this class. + * + * ####Example: + * + * var mongoose = require('mongoose'); + * var mongoose2 = new mongoose.Mongoose(); + * + * @method Mongoose + * @api public + */ + +Mongoose.prototype.Mongoose = Mongoose; + +/** + * The Mongoose [Schema](#schema_Schema) constructor + * + * ####Example: + * + * var mongoose = require('mongoose'); + * var Schema = mongoose.Schema; + * var CatSchema = new Schema(..); + * + * @method Schema + * @api public + */ + +Mongoose.prototype.Schema = Schema; + +/** + * The Mongoose [SchemaType](#schematype_SchemaType) constructor + * + * @method SchemaType + * @api public + */ + +Mongoose.prototype.SchemaType = SchemaType; + +/** + * The various Mongoose SchemaTypes. + * + * ####Note: + * + * _Alias of mongoose.Schema.Types for backwards compatibility._ + * + * @property SchemaTypes + * @see Schema.SchemaTypes #schema_Schema.Types + * @api public + */ + +Mongoose.prototype.SchemaTypes = Schema.Types; + +/** + * The Mongoose [VirtualType](#virtualtype_VirtualType) constructor + * + * @method VirtualType + * @api public + */ + +Mongoose.prototype.VirtualType = VirtualType; + +/** + * The various Mongoose Types. + * + * ####Example: + * + * var mongoose = require('mongoose'); + * var array = mongoose.Types.Array; + * + * ####Types: + * + * - [ObjectId](#types-objectid-js) + * - [Buffer](#types-buffer-js) + * - [SubDocument](#types-embedded-js) + * - [Array](#types-array-js) + * - [DocumentArray](#types-documentarray-js) + * + * Using this exposed access to the `ObjectId` type, we can construct ids on demand. + * + * var ObjectId = mongoose.Types.ObjectId; + * var id1 = new ObjectId; + * + * @property Types + * @api public + */ + +Mongoose.prototype.Types = Types; + +/** + * The Mongoose [Query](#query_Query) constructor. + * + * @method Query + * @api public + */ + +Mongoose.prototype.Query = Query; + +/** + * The Mongoose [Promise](#promise_Promise) constructor. + * + * @method Promise + * @api public + */ + +Mongoose.prototype.Promise = Promise; + +/** + * The Mongoose [Model](#model_Model) constructor. + * + * @method Model + * @api public + */ + +Mongoose.prototype.Model = Model; + +/** + * The Mongoose [Document](#document-js) constructor. + * + * @method Document + * @api public + */ + +Mongoose.prototype.Document = Document; + +/** + * The [MongooseError](#error_MongooseError) constructor. + * + * @method Error + * @api public + */ + +Mongoose.prototype.Error = require('./error'); + +/** + * The [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) driver Mongoose uses. + * + * @property mongo + * @api public + */ + +Mongoose.prototype.mongo = require('mongodb'); + +/** + * The [mquery](https://github.com/aheckmann/mquery) query builder Mongoose uses. + * + * @property mquery + * @api public + */ + +Mongoose.prototype.mquery = require('mquery'); + +/*! + * The exports object is an instance of Mongoose. + * + * @api public + */ + +var mongoose = module.exports = exports = new Mongoose; diff --git a/node_modules/mongoose/lib/internal.js b/node_modules/mongoose/lib/internal.js new file mode 100644 index 0000000..d5a3f12 --- /dev/null +++ b/node_modules/mongoose/lib/internal.js @@ -0,0 +1,31 @@ +/*! + * Dependencies + */ + +var StateMachine = require('./statemachine') +var ActiveRoster = StateMachine.ctor('require', 'modify', 'init', 'default') + +module.exports = exports = InternalCache; + +function InternalCache () { + this.strictMode = undefined; + this.selected = undefined; + this.shardval = undefined; + this.saveError = undefined; + this.validationError = undefined; + this.adhocPaths = undefined; + this.removing = undefined; + this.inserting = undefined; + this.version = undefined; + this.getters = {}; + this._id = undefined; + this.populate = undefined; // what we want to populate in this doc + this.populated = undefined;// the _ids that have been populated + this.wasPopulated = false; // if this doc was the result of a population + this.scope = undefined; + this.activePaths = new ActiveRoster; + + // embedded docs + this.ownerDocument = undefined; + this.fullPath = undefined; +} diff --git a/node_modules/mongoose/lib/model.js b/node_modules/mongoose/lib/model.js new file mode 100644 index 0000000..a4458ca --- /dev/null +++ b/node_modules/mongoose/lib/model.js @@ -0,0 +1,2579 @@ +/*! + * Module dependencies. + */ + +var Document = require('./document') + , MongooseArray = require('./types/array') + , MongooseBuffer = require('./types/buffer') + , MongooseError = require('./error') + , VersionError = MongooseError.VersionError + , DivergentArrayError = MongooseError.DivergentArrayError + , Query = require('./query') + , Aggregate = require('./aggregate') + , Schema = require('./schema') + , Types = require('./schema/index') + , utils = require('./utils') + , hasOwnProperty = utils.object.hasOwnProperty + , isMongooseObject = utils.isMongooseObject + , EventEmitter = require('events').EventEmitter + , merge = utils.merge + , Promise = require('./promise') + , assert = require('assert') + , util = require('util') + , tick = utils.tick + , Query = require('./query.js') + +var VERSION_WHERE = 1 + , VERSION_INC = 2 + , VERSION_ALL = VERSION_WHERE | VERSION_INC; + +/** + * Model constructor + * + * Provides the interface to MongoDB collections as well as creates document instances. + * + * @param {Object} doc values with which to create the document + * @inherits Document + * @event `error`: If listening to this event, it is emitted when a document was saved without passing a callback and an `error` occurred. If not listening, the event bubbles to the connection used to create this Model. + * @event `index`: Emitted after `Model#ensureIndexes` completes. If an error occurred it is passed with the event. + * @api public + */ + +function Model (doc, fields, skipId) { + Document.call(this, doc, fields, skipId); +}; + +/*! + * Inherits from Document. + * + * All Model.prototype features are available on + * top level (non-sub) documents. + */ + +Model.prototype.__proto__ = Document.prototype; + +/** + * Connection the model uses. + * + * @api public + * @property db + */ + +Model.prototype.db; + +/** + * Collection the model uses. + * + * @api public + * @property collection + */ + +Model.prototype.collection; + +/** + * The name of the model + * + * @api public + * @property modelName + */ + +Model.prototype.modelName; + +/*! + * Handles doc.save() callbacks + */ + +function handleSave (promise, self) { + return tick(function handleSave (err, result) { + if (err) { + // If the initial insert fails provide a second chance. + // (If we did this all the time we would break updates) + if (self.$__.inserting) { + self.isNew = true; + self.emit('isNew', true); + } + promise.error(err); + promise = self = null; + return; + } + + self.$__storeShard(); + + var numAffected; + if (result) { + // when inserting, the array of created docs is returned + numAffected = result.length + ? result.length + : result; + } else { + numAffected = 0; + } + + // was this an update that required a version bump? + if (self.$__.version && !self.$__.inserting) { + var doIncrement = VERSION_INC === (VERSION_INC & self.$__.version); + self.$__.version = undefined; + + // increment version if was successful + if (numAffected > 0) { + if (doIncrement) { + var key = self.schema.options.versionKey; + var version = self.getValue(key) | 0; + self.setValue(key, version + 1); + } + } else { + // the update failed. pass an error back + promise.error(new VersionError); + promise = self = null; + return; + } + } + + self.emit('save', self, numAffected); + promise.complete(self, numAffected); + promise = self = null; + }); +} + +/** + * Saves this document. + * + * ####Example: + * + * product.sold = Date.now(); + * product.save(function (err, product, numberAffected) { + * if (err) .. + * }) + * + * The callback will receive three parameters, `err` if an error occurred, `product` which is the saved `product`, and `numberAffected` which will be 1 when the document was found and updated in the database, otherwise 0. + * + * The `fn` callback is optional. If no `fn` is passed and validation fails, the validation error will be emitted on the connection used to create this model. + * + * var db = mongoose.createConnection(..); + * var schema = new Schema(..); + * var Product = db.model('Product', schema); + * + * db.on('error', handleError); + * + * However, if you desire more local error handling you can add an `error` listener to the model and handle errors there instead. + * + * Product.on('error', handleError); + * + * @param {Function} [fn] optional callback + * @api public + * @see middleware http://mongoosejs.com/docs/middleware.html + */ + +Model.prototype.save = function save (fn) { + var promise = new Promise(fn) + , complete = handleSave(promise, this) + , options = {} + + if (this.schema.options.safe) { + options.safe = this.schema.options.safe; + } + + if (this.isNew) { + // send entire doc + var obj = this.toObject({ depopulate: 1 }); + + if (!utils.object.hasOwnProperty(obj || {}, '_id')) { + // documents must have an _id else mongoose won't know + // what to update later if more changes are made. the user + // wouldn't know what _id was generated by mongodb either + // nor would the ObjectId generated my mongodb necessarily + // match the schema definition. + return complete(new Error('document must have an _id before saving')); + } + + this.$__version(true, obj); + this.collection.insert(obj, options, complete); + this.$__reset(); + this.isNew = false; + this.emit('isNew', false); + // Make it possible to retry the insert + this.$__.inserting = true; + + } else { + // Make sure we don't treat it as a new object on error, + // since it already exists + this.$__.inserting = false; + + var delta = this.$__delta(); + + if (delta) { + if (delta instanceof Error) return complete(delta); + var where = this.$__where(delta[0]); + this.$__reset(); + this.collection.update(where, delta[1], options, complete); + } else { + this.$__reset(); + complete(null); + } + + this.emit('isNew', false); + } +}; + +/*! + * Apply the operation to the delta (update) clause as + * well as track versioning for our where clause. + * + * @param {Document} self + * @param {Object} where + * @param {Object} delta + * @param {Object} data + * @param {Mixed} val + * @param {String} [operation] + */ + +function operand (self, where, delta, data, val, op) { + // delta + op || (op = '$set'); + if (!delta[op]) delta[op] = {}; + delta[op][data.path] = val; + + // disabled versioning? + if (false === self.schema.options.versionKey) return; + + // already marked for versioning? + if (VERSION_ALL === (VERSION_ALL & self.$__.version)) return; + + switch (op) { + case '$set': + case '$unset': + case '$pop': + case '$pull': + case '$pullAll': + case '$push': + case '$pushAll': + case '$addToSet': + break; + default: + // nothing to do + return; + } + + // ensure updates sent with positional notation are + // editing the correct array element. + // only increment the version if an array position changes. + // modifying elements of an array is ok if position does not change. + + if ('$push' == op || '$pushAll' == op || '$addToSet' == op) { + self.$__.version = VERSION_INC; + } + else if (/^\$p/.test(op)) { + // potentially changing array positions + self.increment(); + } + else if (Array.isArray(val)) { + // $set an array + self.increment(); + } + // now handling $set, $unset + else if (/\.\d+\.|\.\d+$/.test(data.path)) { + // subpath of array + self.$__.version = VERSION_WHERE; + } +} + +/*! + * Compiles an update and where clause for a `val` with _atomics. + * + * @param {Document} self + * @param {Object} where + * @param {Object} delta + * @param {Object} data + * @param {Array} value + */ + +function handleAtomics (self, where, delta, data, value) { + if (delta.$set && delta.$set[data.path]) { + // $set has precedence over other atomics + return; + } + + if ('function' == typeof value.$__getAtomics) { + value.$__getAtomics().forEach(function (atomic) { + var op = atomic[0]; + var val = atomic[1]; + operand(self, where, delta, data, val, op); + }) + return; + } + + // legacy support for plugins + + var atomics = value._atomics + , ops = Object.keys(atomics) + , i = ops.length + , val + , op; + + if (0 === i) { + // $set + + if (isMongooseObject(value)) { + value = value.toObject({ depopulate: 1 }); + } else if (value.valueOf) { + value = value.valueOf(); + } + + return operand(self, where, delta, data, value); + } + + while (i--) { + op = ops[i]; + val = atomics[op]; + + if (isMongooseObject(val)) { + val = val.toObject({ depopulate: 1 }) + } else if (Array.isArray(val)) { + val = val.map(function (mem) { + return isMongooseObject(mem) + ? mem.toObject({ depopulate: 1 }) + : mem; + }) + } else if (val.valueOf) { + val = val.valueOf() + } + + if ('$addToSet' === op) + val = { $each: val }; + + operand(self, where, delta, data, val, op); + } +} + +/** + * Produces a special query document of the modified properties used in updates. + * + * @api private + * @method $__delta + * @memberOf Model + */ + +Model.prototype.$__delta = function () { + var dirty = this.$__dirty(); + if (!dirty.length && VERSION_ALL != this.$__.version) return; + + var where = {} + , delta = {} + , len = dirty.length + , divergent = [] + , d = 0 + , val + , obj + + for (; d < len; ++d) { + var data = dirty[d] + var value = data.value + var schema = data.schema + + var match = checkDivergentArray(this, data.path, value); + if (match) { + divergent.push(match); + continue; + } + + if (divergent.length) continue; + + if (undefined === value) { + operand(this, where, delta, data, 1, '$unset'); + + } else if (null === value) { + operand(this, where, delta, data, null); + + } else if (value._path && value._atomics) { + // arrays and other custom types (support plugins etc) + handleAtomics(this, where, delta, data, value); + + } else if (value._path && Buffer.isBuffer(value)) { + // MongooseBuffer + value = value.toObject(); + operand(this, where, delta, data, value); + + } else { + value = utils.clone(value, { depopulate: 1 }); + operand(this, where, delta, data, value); + } + } + + if (divergent.length) { + return new DivergentArrayError(divergent); + } + + if (this.$__.version) { + this.$__version(where, delta); + } + + return [where, delta]; +} + +/*! + * Determine if array was populated with some form of filter and is now + * being updated in a manner which could overwrite data unintentionally. + * + * @see https://github.com/LearnBoost/mongoose/issues/1334 + * @param {Document} doc + * @param {String} path + * @return {String|undefined} + */ + +function checkDivergentArray (doc, path, array) { + // see if we populated this path + var pop = doc.populated(path, true); + + if (!pop && doc.$__.selected) { + // If any array was selected using an $elemMatch projection, we deny the update. + // NOTE: MongoDB only supports projected $elemMatch on top level array. + var top = path.split('.')[0]; + if (doc.$__.selected[top] && doc.$__.selected[top].$elemMatch) { + return top; + } + } + + if (!(pop && array instanceof MongooseArray)) return; + + // If the array was populated using options that prevented all + // documents from being returned (match, skip, limit) or they + // deselected the _id field, $pop and $set of the array are + // not safe operations. If _id was deselected, we do not know + // how to remove elements. $pop will pop off the _id from the end + // of the array in the db which is not guaranteed to be the + // same as the last element we have here. $set of the entire array + // would be similarily destructive as we never received all + // elements of the array and potentially would overwrite data. + var check = pop.options.match || + pop.options.options && hasOwnProperty(pop.options.options, 'limit') || // 0 is not permitted + pop.options.options && pop.options.options.skip || // 0 is permitted + pop.options.select && // deselected _id? + (0 === pop.options.select._id || + /\s?-_id\s?/.test(pop.options.select)) + + if (check) { + var atomics = array._atomics; + if (0 === Object.keys(atomics).length || atomics.$set || atomics.$pop) { + return path; + } + } +} + +/** + * Appends versioning to the where and update clauses. + * + * @api private + * @method $__version + * @memberOf Model + */ + +Model.prototype.$__version = function (where, delta) { + var key = this.schema.options.versionKey; + + if (true === where) { + // this is an insert + if (key) this.setValue(key, delta[key] = 0); + return; + } + + // updates + + // only apply versioning if our versionKey was selected. else + // there is no way to select the correct version. we could fail + // fast here and force them to include the versionKey but + // thats a bit intrusive. can we do this automatically? + if (!this.isSelected(key)) { + return; + } + + // $push $addToSet don't need the where clause set + if (VERSION_WHERE === (VERSION_WHERE & this.$__.version)) { + where[key] = this.getValue(key); + } + + if (VERSION_INC === (VERSION_INC & this.$__.version)) { + delta.$inc || (delta.$inc = {}); + delta.$inc[key] = 1; + } +} + +/** + * Signal that we desire an increment of this documents version. + * + * ####Example: + * + * Model.findById(id, function (err, doc) { + * doc.increment(); + * doc.save(function (err) { .. }) + * }) + * + * @see versionKeys http://mongoosejs.com/docs/guide.html#versionKey + * @api public + */ + +Model.prototype.increment = function increment () { + this.$__.version = VERSION_ALL; + return this; +} + +/** + * Returns a query object which applies shardkeys if they exist. + * + * @api private + * @method $__where + * @memberOf Model + */ + +Model.prototype.$__where = function _where (where) { + where || (where = {}); + + var paths + , len + + if (this.$__.shardval) { + paths = Object.keys(this.$__.shardval) + len = paths.length + + for (var i = 0; i < len; ++i) { + where[paths[i]] = this.$__.shardval[paths[i]]; + } + } + + where._id = this._doc._id; + return where; +} + +/** + * Removes this document from the db. + * + * ####Example: + * + * product.remove(function (err, product) { + * if (err) return handleError(err); + * Product.findById(product._id, function (err, product) { + * console.log(product) // null + * }) + * }) + * + * @param {Function} [fn] optional callback + * @api public + */ + +Model.prototype.remove = function remove (fn) { + if (this.$__.removing) { + this.$__.removing.addBack(fn); + return this; + } + + var promise = this.$__.removing = new Promise(fn) + , where = this.$__where() + , self = this + , options = {} + + if (this.schema.options.safe) { + options.safe = this.schema.options.safe; + } + + this.collection.remove(where, options, tick(function (err) { + if (err) { + promise.error(err); + promise = self = self.$__.removing = where = options = null; + return; + } + self.emit('remove', self); + promise.complete(self); + promise = self = where = options = null; + })); + + return this; +}; + +/** + * Returns another Model instance. + * + * ####Example: + * + * var doc = new Tank; + * doc.model('User').findById(id, callback); + * + * @param {String} name model name + * @api public + */ + +Model.prototype.model = function model (name) { + return this.db.model(name); +}; + +/** + * Adds a discriminator type. + * + * ####Example: + * + * function BaseSchema() { + * Schema.apply(this, arguments); + * + * this.add({ + * name: String, + * createdAt: Date + * }); + * } + * util.inherits(BaseSchema, Schema); + * + * var PersonSchema = new BaseSchema(); + * var BossSchema = new BaseSchema({ department: String }); + * + * var Person = mongoose.model('Person', PersonSchema); + * var Boss = Person.discriminator('Boss', BossSchema); + * + * @param {String} name discriminator model name + * @param {Schema} schema discriminator model schema + * @api public + */ + +Model.discriminator = function discriminator (name, schema) { + if (!(schema instanceof Schema)) { + throw new Error("You must pass a valid discriminator Schema"); + } + + if (this.schema.discriminatorMapping && !this.schema.discriminatorMapping.isRoot) { + throw new Error("Discriminator \"" + name + "\" can only be a discriminator of the root model"); + } + + var key = this.schema.options.discriminatorKey; + if (schema.path(key)) { + throw new Error("Discriminator \"" + name + "\" cannot have field with name \"" + key + "\""); + } + + // merges base schema into new discriminator schema and sets new type field. + (function mergeSchemas(schema, baseSchema) { + utils.merge(schema, baseSchema); + + var obj = {}; + obj[key] = { type: String, default: name }; + schema.add(obj); + schema.discriminatorMapping = { key: key, value: name, isRoot: false }; + + if (baseSchema.options.collection) { + schema.options.collection = baseSchema.options.collection; + } + + // throws error if options are invalid + (function validateOptions(a, b) { + a = utils.clone(a); + b = utils.clone(b); + delete a.toJSON; + delete a.toObject; + delete b.toJSON; + delete b.toObject; + + if (!utils.deepEqual(a, b)) { + throw new Error("Discriminator options are not customizable (except toJSON & toObject)"); + } + })(schema.options, baseSchema.options); + + var toJSON = schema.options.toJSON + , toObject = schema.options.toObject; + + schema.options = utils.clone(baseSchema.options); + if (toJSON) schema.options.toJSON = toJSON; + if (toObject) schema.options.toObject = toObject; + + schema.callQueue = baseSchema.callQueue.concat(schema.callQueue); + schema._requiredpaths = undefined; // reset just in case Schema#requiredPaths() was called on either schema + })(schema, this.schema); + + if (!this.discriminators) { + this.discriminators = {}; + } + + if (!this.schema.discriminatorMapping) { + this.schema.discriminatorMapping = { key: key, value: null, isRoot: true }; + } + + if (this.discriminators[name]) { + throw new Error("Discriminator with name \"" + name + "\" already exists"); + } + + this.discriminators[name] = this.db.model(name, schema, this.collection.name); + this.discriminators[name].prototype.__proto__ = this.prototype; + + return this.discriminators[name]; +}; + +// Model (class) features + +/*! + * Give the constructor the ability to emit events. + */ + +for (var i in EventEmitter.prototype) + Model[i] = EventEmitter.prototype[i]; + +/** + * Called when the model compiles. + * + * @api private + */ + +Model.init = function init () { + if (this.schema.options.autoIndex) { + this.ensureIndexes(); + } + + this.schema.emit('init', this); +}; + +/** + * Sends `ensureIndex` commands to mongo for each index declared in the schema. + * + * ####Example: + * + * Event.ensureIndexes(function (err) { + * if (err) return handleError(err); + * }); + * + * After completion, an `index` event is emitted on this `Model` passing an error if one occurred. + * + * ####Example: + * + * var eventSchema = new Schema({ thing: { type: 'string', unique: true }}) + * var Event = mongoose.model('Event', eventSchema); + * + * Event.on('index', function (err) { + * if (err) console.error(err); // error occurred during index creation + * }) + * + * _NOTE: It is not recommended that you run this in production. Index creation may impact database performance depending on your load. Use with caution._ + * + * The `ensureIndex` commands are not sent in parallel. This is to avoid the `MongoError: cannot add index with a background operation in progress` error. See [this ticket](https://github.com/LearnBoost/mongoose/issues/1365) for more information. + * + * @param {Function} [cb] optional callback + * @return {Promise} + * @api public + */ + +Model.ensureIndexes = function ensureIndexes (cb) { + var promise = new Promise(cb); + + var indexes = this.schema.indexes(); + if (!indexes.length) { + process.nextTick(promise.fulfill.bind(promise)); + return promise; + } + + // Indexes are created one-by-one to support how MongoDB < 2.4 deals + // with background indexes. + + var self = this + , safe = self.schema.options.safe + + function done (err) { + self.emit('index', err); + promise.resolve(err); + } + + function create () { + var index = indexes.shift(); + if (!index) return done(); + + var options = index[1]; + options.safe = safe; + self.collection.ensureIndex(index[0], options, tick(function (err) { + if (err) return done(err); + create(); + })); + } + + create(); + return promise; +} + +/** + * Schema the model uses. + * + * @property schema + * @receiver Model + * @api public + */ + +Model.schema; + +/*! + * Connection instance the model uses. + * + * @property db + * @receiver Model + * @api public + */ + +Model.db; + +/*! + * Collection the model uses. + * + * @property collection + * @receiver Model + * @api public + */ + +Model.collection; + +/** + * Base Mongoose instance the model uses. + * + * @property base + * @receiver Model + * @api public + */ + +Model.base; + +/** + * Registered discriminators for this model. + * + * @property discriminators + * @receiver Model + * @api public + */ + +Model.discriminators; + +/** + * Removes documents from the collection. + * + * ####Example: + * + * Comment.remove({ title: 'baby born from alien father' }, function (err) { + * + * }); + * + * ####Note: + * + * To remove documents without waiting for a response from MongoDB, do not pass a `callback`, then call `exec` on the returned [Query](#query-js): + * + * var query = Comment.remove({ _id: id }); + * query.exec(); + * + * ####Note: + * + * This method sends a remove command directly to MongoDB, no Mongoose documents are involved. Because no Mongoose documents are involved, _no middleware (hooks) are executed_. + * + * @param {Object} conditions + * @param {Function} [callback] + * @return {Query} + * @api public + */ + +Model.remove = function remove (conditions, callback) { + if ('function' === typeof conditions) { + callback = conditions; + conditions = {}; + } + + // get the mongodb collection object + var mq = new Query(conditions, {}, this, this.collection); + + return mq.remove(callback); +}; + +/** + * Finds documents + * + * The `conditions` are cast to their respective SchemaTypes before the command is sent. + * + * ####Examples: + * + * // named john and at least 18 + * MyModel.find({ name: 'john', age: { $gte: 18 }}); + * + * // executes immediately, passing results to callback + * MyModel.find({ name: 'john', age: { $gte: 18 }}, function (err, docs) {}); + * + * // name LIKE john and only selecting the "name" and "friends" fields, executing immediately + * MyModel.find({ name: /john/i }, 'name friends', function (err, docs) { }) + * + * // passing options + * MyModel.find({ name: /john/i }, null, { skip: 10 }) + * + * // passing options and executing immediately + * MyModel.find({ name: /john/i }, null, { skip: 10 }, function (err, docs) {}); + * + * // executing a query explicitly + * var query = MyModel.find({ name: /john/i }, null, { skip: 10 }) + * query.exec(function (err, docs) {}); + * + * // using the promise returned from executing a query + * var query = MyModel.find({ name: /john/i }, null, { skip: 10 }); + * var promise = query.exec(); + * promise.addBack(function (err, docs) {}); + * + * @param {Object} conditions + * @param {Object} [fields] optional fields to select + * @param {Object} [options] optional + * @param {Function} [callback] + * @return {Query} + * @see field selection #query_Query-select + * @see promise #promise-js + * @api public + */ + +Model.find = function find (conditions, fields, options, callback) { + if ('function' == typeof conditions) { + callback = conditions; + conditions = {}; + fields = null; + options = null; + } else if ('function' == typeof fields) { + callback = fields; + fields = null; + options = null; + } else if ('function' == typeof options) { + callback = options; + options = null; + } + + // get the raw mongodb collection object + var mq = new Query({}, options, this, this.collection); + mq.select(fields); + + return mq.find(conditions, callback); +}; + +/** + * Finds a single document by id. + * + * The `id` is cast based on the Schema before sending the command. + * + * ####Example: + * + * // find adventure by id and execute immediately + * Adventure.findById(id, function (err, adventure) {}); + * + * // same as above + * Adventure.findById(id).exec(callback); + * + * // select only the adventures name and length + * Adventure.findById(id, 'name length', function (err, adventure) {}); + * + * // same as above + * Adventure.findById(id, 'name length').exec(callback); + * + * // include all properties except for `length` + * Adventure.findById(id, '-length').exec(function (err, adventure) {}); + * + * // passing options (in this case return the raw js objects, not mongoose documents by passing `lean` + * Adventure.findById(id, 'name', { lean: true }, function (err, doc) {}); + * + * // same as above + * Adventure.findById(id, 'name').lean().exec(function (err, doc) {}); + * + * @param {ObjectId|HexId} id objectid, or a value that can be casted to one + * @param {Object} [fields] optional fields to select + * @param {Object} [options] optional + * @param {Function} [callback] + * @return {Query} + * @see field selection #query_Query-select + * @see lean queries #query_Query-lean + * @api public + */ + +Model.findById = function findById (id, fields, options, callback) { + return this.findOne({ _id: id }, fields, options, callback); +}; + +/** + * Finds one document. + * + * The `conditions` are cast to their respective SchemaTypes before the command is sent. + * + * ####Example: + * + * // find one iphone adventures - iphone adventures?? + * Adventure.findOne({ type: 'iphone' }, function (err, adventure) {}); + * + * // same as above + * Adventure.findOne({ type: 'iphone' }).exec(function (err, adventure) {}); + * + * // select only the adventures name + * Adventure.findOne({ type: 'iphone' }, 'name', function (err, adventure) {}); + * + * // same as above + * Adventure.findOne({ type: 'iphone' }, 'name').exec(function (err, adventure) {}); + * + * // specify options, in this case lean + * Adventure.findOne({ type: 'iphone' }, 'name', { lean: true }, callback); + * + * // same as above + * Adventure.findOne({ type: 'iphone' }, 'name', { lean: true }).exec(callback); + * + * // chaining findOne queries (same as above) + * Adventure.findOne({ type: 'iphone' }).select('name').lean().exec(callback); + * + * @param {Object} conditions + * @param {Object} [fields] optional fields to select + * @param {Object} [options] optional + * @param {Function} [callback] + * @return {Query} + * @see field selection #query_Query-select + * @see lean queries #query_Query-lean + * @api public + */ + +Model.findOne = function findOne (conditions, fields, options, callback) { + if ('function' == typeof options) { + callback = options; + options = null; + } else if ('function' == typeof fields) { + callback = fields; + fields = null; + options = null; + } else if ('function' == typeof conditions) { + callback = conditions; + conditions = {}; + fields = null; + options = null; + } + + // get the mongodb collection object + var mq = new Query({}, options, this, this.collection); + mq.select(fields); + + return mq.findOne(conditions, callback); +}; + +/** + * Counts number of matching documents in a database collection. + * + * ####Example: + * + * Adventure.count({ type: 'jungle' }, function (err, count) { + * if (err) .. + * console.log('there are %d jungle adventures', count); + * }); + * + * @param {Object} conditions + * @param {Function} [callback] + * @return {Query} + * @api public + */ + +Model.count = function count (conditions, callback) { + if ('function' === typeof conditions) + callback = conditions, conditions = {}; + + // get the mongodb collection object + var mq = new Query({}, {}, this, this.collection); + + return mq.count(conditions, callback); +}; + +/** + * Creates a Query for a `distinct` operation. + * + * Passing a `callback` immediately executes the query. + * + * ####Example + * + * Link.distinct('url', { clicks: {$gt: 100}}, function (err, result) { + * if (err) return handleError(err); + * + * assert(Array.isArray(result)); + * console.log('unique urls with more than 100 clicks', result); + * }) + * + * var query = Link.distinct('url'); + * query.exec(callback); + * + * @param {String} field + * @param {Object} [conditions] optional + * @param {Function} [callback] + * @return {Query} + * @api public + */ + +Model.distinct = function distinct (field, conditions, callback) { + // get the mongodb collection object + var mq = new Query({}, {}, this, this.collection); + + if ('function' == typeof conditions) { + callback = conditions; + conditions = {}; + } + + return mq.distinct(conditions, field, callback); +}; + +/** + * Creates a Query, applies the passed conditions, and returns the Query. + * + * For example, instead of writing: + * + * User.find({age: {$gte: 21, $lte: 65}}, callback); + * + * we can instead write: + * + * User.where('age').gte(21).lte(65).exec(callback); + * + * Since the Query class also supports `where` you can continue chaining + * + * User + * .where('age').gte(21).lte(65) + * .where('name', /^b/i) + * ... etc + * + * @param {String} path + * @param {Object} [val] optional value + * @return {Query} + * @api public + */ + +Model.where = function where (path, val) { + // get the mongodb collection object + var mq = new Query({}, {}, this, this.collection).find({}); + return mq.where.apply(mq, arguments); +}; + +/** + * Creates a `Query` and specifies a `$where` condition. + * + * Sometimes you need to query for things in mongodb using a JavaScript expression. You can do so via `find({ $where: javascript })`, or you can use the mongoose shortcut method $where via a Query chain or from your mongoose Model. + * + * Blog.$where('this.comments.length > 5').exec(function (err, docs) {}); + * + * @param {String|Function} argument is a javascript string or anonymous function + * @method $where + * @memberOf Model + * @return {Query} + * @see Query.$where #query_Query-%24where + * @api public + */ + +Model.$where = function $where () { + var mq = new Query({}, {}, this, this.collection).find({}); + return mq.$where.apply(mq, arguments); +}; + +/** + * Issues a mongodb findAndModify update command. + * + * Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes immediately if `callback` is passed else a Query object is returned. + * + * ####Options: + * + * - `new`: bool - true to return the modified document rather than the original. defaults to true + * - `upsert`: bool - creates the object if it doesn't exist. defaults to false. + * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update + * - `select`: sets the document fields to return + * + * ####Examples: + * + * A.findOneAndUpdate(conditions, update, options, callback) // executes + * A.findOneAndUpdate(conditions, update, options) // returns Query + * A.findOneAndUpdate(conditions, update, callback) // executes + * A.findOneAndUpdate(conditions, update) // returns Query + * A.findOneAndUpdate() // returns Query + * + * ####Note: + * + * All top level update keys which are not `atomic` operation names are treated as set operations: + * + * ####Example: + * + * var query = { name: 'borne' }; + * Model.findOneAndUpdate(query, { name: 'jason borne' }, options, callback) + * + * // is sent as + * Model.findOneAndUpdate(query, { $set: { name: 'jason borne' }}, options, callback) + * + * This helps prevent accidentally overwriting your document with `{ name: 'jason borne' }`. + * + * ####Note: + * + * Although values are cast to their appropriate types when using the findAndModify helpers, the following are *not* applied: + * + * - defaults + * - setters + * - validators + * - middleware + * + * If you need those features, use the traditional approach of first retrieving the document. + * + * Model.findOne({ name: 'borne' }, function (err, doc) { + * if (err) .. + * doc.name = 'jason borne'; + * doc.save(callback); + * }) + * + * @param {Object} [conditions] + * @param {Object} [update] + * @param {Object} [options] + * @param {Function} [callback] + * @return {Query} + * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command + * @api public + */ + +Model.findOneAndUpdate = function (conditions, update, options, callback) { + if ('function' == typeof options) { + callback = options; + options = null; + } + else if (1 === arguments.length) { + if ('function' == typeof conditions) { + var msg = 'Model.findOneAndUpdate(): First argument must not be a function.\n\n' + + ' ' + this.modelName + '.findOneAndUpdate(conditions, update, options, callback)\n' + + ' ' + this.modelName + '.findOneAndUpdate(conditions, update, options)\n' + + ' ' + this.modelName + '.findOneAndUpdate(conditions, update)\n' + + ' ' + this.modelName + '.findOneAndUpdate(update)\n' + + ' ' + this.modelName + '.findOneAndUpdate()\n'; + throw new TypeError(msg) + } + update = conditions; + conditions = undefined; + } + + var fields; + if (options && options.fields) { + fields = options.fields; + options.fields = undefined; + } + + var mq = new Query({}, {}, this, this.collection); + mq.select(fields); + + return mq.findOneAndUpdate(conditions, update, options, callback); +} + +/** + * Issues a mongodb findAndModify update command by a documents id. + * + * Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes immediately if `callback` is passed else a Query object is returned. + * + * ####Options: + * + * - `new`: bool - true to return the modified document rather than the original. defaults to true + * - `upsert`: bool - creates the object if it doesn't exist. defaults to false. + * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update + * - `select`: sets the document fields to return + * + * ####Examples: + * + * A.findByIdAndUpdate(id, update, options, callback) // executes + * A.findByIdAndUpdate(id, update, options) // returns Query + * A.findByIdAndUpdate(id, update, callback) // executes + * A.findByIdAndUpdate(id, update) // returns Query + * A.findByIdAndUpdate() // returns Query + * + * Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes immediately if `callback` is passed else a Query object is returned. + * + * ####Options: + * + * - `new`: bool - true to return the modified document rather than the original. defaults to true + * - `upsert`: bool - creates the object if it doesn't exist. defaults to false. + * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update + * + * ####Note: + * + * All top level update keys which are not `atomic` operation names are treated as set operations: + * + * ####Example: + * + * Model.findByIdAndUpdate(id, { name: 'jason borne' }, options, callback) + * + * // is sent as + * Model.findByIdAndUpdate(id, { $set: { name: 'jason borne' }}, options, callback) + * + * This helps prevent accidentally overwriting your document with `{ name: 'jason borne' }`. + * + * ####Note: + * + * Although values are cast to their appropriate types when using the findAndModify helpers, the following are *not* applied: + * + * - defaults + * - setters + * - validators + * - middleware + * + * If you need those features, use the traditional approach of first retrieving the document. + * + * Model.findById(id, function (err, doc) { + * if (err) .. + * doc.name = 'jason borne'; + * doc.save(callback); + * }) + * + * @param {ObjectId|HexId} id an ObjectId or string that can be cast to one. + * @param {Object} [update] + * @param {Object} [options] + * @param {Function} [callback] + * @return {Query} + * @see Model.findOneAndUpdate #model_Model.findOneAndUpdate + * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command + * @api public + */ + +Model.findByIdAndUpdate = function (id, update, options, callback) { + var args; + + if (1 === arguments.length) { + if ('function' == typeof id) { + var msg = 'Model.findByIdAndUpdate(): First argument must not be a function.\n\n' + + ' ' + this.modelName + '.findByIdAndUpdate(id, callback)\n' + + ' ' + this.modelName + '.findByIdAndUpdate(id)\n' + + ' ' + this.modelName + '.findByIdAndUpdate()\n'; + throw new TypeError(msg) + } + return this.findOneAndUpdate({_id: id }, undefined); + } + + args = utils.args(arguments, 1); + + // if a model is passed in instead of an id + if (id && id._id) { + id = id._id; + } + if (id) { + args.unshift({ _id: id }); + } + return this.findOneAndUpdate.apply(this, args); +} + +/** + * Issue a mongodb findAndModify remove command. + * + * Finds a matching document, removes it, passing the found document (if any) to the callback. + * + * Executes immediately if `callback` is passed else a Query object is returned. + * + * ####Options: + * + * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update + * - `select`: sets the document fields to return + * + * ####Examples: + * + * A.findOneAndRemove(conditions, options, callback) // executes + * A.findOneAndRemove(conditions, options) // return Query + * A.findOneAndRemove(conditions, callback) // executes + * A.findOneAndRemove(conditions) // returns Query + * A.findOneAndRemove() // returns Query + * + * Although values are cast to their appropriate types when using the findAndModify helpers, the following are *not* applied: + * + * - defaults + * - setters + * - validators + * - middleware + * + * If you need those features, use the traditional approach of first retrieving the document. + * + * Model.findById(id, function (err, doc) { + * if (err) .. + * doc.remove(callback); + * }) + * + * @param {Object} conditions + * @param {Object} [options] + * @param {Function} [callback] + * @return {Query} + * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command + * @api public + */ + +Model.findOneAndRemove = function (conditions, options, callback) { + if (1 === arguments.length && 'function' == typeof conditions) { + var msg = 'Model.findOneAndRemove(): First argument must not be a function.\n\n' + + ' ' + this.modelName + '.findOneAndRemove(conditions, callback)\n' + + ' ' + this.modelName + '.findOneAndRemove(conditions)\n' + + ' ' + this.modelName + '.findOneAndRemove()\n'; + throw new TypeError(msg) + } + + if ('function' == typeof options) { + callback = options; + options = undefined; + } + + var fields; + if (options) { + fields = options.select; + options.select = undefined; + } + + var mq = new Query({}, {}, this, this.collection); + mq.select(fields); + + return mq.findOneAndRemove(conditions, options, callback); +} + +/** + * Issue a mongodb findAndModify remove command by a documents id. + * + * Finds a matching document, removes it, passing the found document (if any) to the callback. + * + * Executes immediately if `callback` is passed, else a `Query` object is returned. + * + * ####Options: + * + * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update + * - `select`: sets the document fields to return + * + * ####Examples: + * + * A.findByIdAndRemove(id, options, callback) // executes + * A.findByIdAndRemove(id, options) // return Query + * A.findByIdAndRemove(id, callback) // executes + * A.findByIdAndRemove(id) // returns Query + * A.findByIdAndRemove() // returns Query + * + * @param {ObjectId|HexString} id ObjectId or string that can be cast to one + * @param {Object} [options] + * @param {Function} [callback] + * @return {Query} + * @see Model.findOneAndRemove #model_Model.findOneAndRemove + * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command + */ + +Model.findByIdAndRemove = function (id, options, callback) { + if (1 === arguments.length && 'function' == typeof id) { + var msg = 'Model.findByIdAndRemove(): First argument must not be a function.\n\n' + + ' ' + this.modelName + '.findByIdAndRemove(id, callback)\n' + + ' ' + this.modelName + '.findByIdAndRemove(id)\n' + + ' ' + this.modelName + '.findByIdAndRemove()\n'; + throw new TypeError(msg) + } + + return this.findOneAndRemove({ _id: id }, options, callback); +} + +/** + * Shortcut for creating a new Document that is automatically saved to the db if valid. + * + * ####Example: + * + * // pass individual docs + * Candy.create({ type: 'jelly bean' }, { type: 'snickers' }, function (err, jellybean, snickers) { + * if (err) // ... + * }); + * + * // pass an array + * var array = [{ type: 'jelly bean' }, { type: 'snickers' }]; + * Candy.create(array, function (err, jellybean, snickers) { + * if (err) // ... + * }); + * + * // callback is optional; use the returned promise if you like: + * var promise = Candy.create({ type: 'jawbreaker' }); + * promise.then(function (jawbreaker) { + * // ... + * }) + * + * @param {Array|Object...} doc(s) + * @param {Function} [fn] callback + * @return {Promise} + * @api public + */ + +Model.create = function create (doc, fn) { + var promise = new Promise + , args + + if (Array.isArray(doc)) { + args = doc; + + if ('function' == typeof fn) { + promise.onResolve(fn); + } + + } else { + var last = arguments[arguments.length - 1]; + + if ('function' == typeof last) { + promise.onResolve(last); + args = utils.args(arguments, 0, arguments.length - 1); + } else { + args = utils.args(arguments); + } + } + + var count = args.length; + + if (0 === count) { + promise.complete(); + return promise; + } + + var self = this; + var docs = []; + + args.forEach(function (arg, i) { + var doc = new self(arg); + docs[i] = doc; + doc.save(function (err) { + if (err) return promise.error(err); + --count || promise.complete.apply(promise, docs); + }); + }); + + return promise; +}; + +/** + * Updates documents in the database without returning them. + * + * ####Examples: + * + * MyModel.update({ age: { $gt: 18 } }, { oldEnough: true }, fn); + * MyModel.update({ name: 'Tobi' }, { ferret: true }, { multi: true }, function (err, numberAffected, raw) { + * if (err) return handleError(err); + * console.log('The number of updated documents was %d', numberAffected); + * console.log('The raw response from Mongo was ', raw); + * }); + * + * ####Valid options: + * + * - `safe` (boolean) safe mode (defaults to value set in schema (true)) + * - `upsert` (boolean) whether to create the doc if it doesn't match (false) + * - `multi` (boolean) whether multiple documents should be updated (false) + * - `strict` (boolean) overrides the `strict` option for this update + * + * All `update` values are cast to their appropriate SchemaTypes before being sent. + * + * The `callback` function receives `(err, numberAffected, rawResponse)`. + * + * - `err` is the error if any occurred + * - `numberAffected` is the count of updated documents Mongo reported + * - `rawResponse` is the full response from Mongo + * + * ####Note: + * + * All top level keys which are not `atomic` operation names are treated as set operations: + * + * ####Example: + * + * var query = { name: 'borne' }; + * Model.update(query, { name: 'jason borne' }, options, callback) + * + * // is sent as + * Model.update(query, { $set: { name: 'jason borne' }}, options, callback) + * + * This helps prevent accidentally overwriting all documents in your collection with `{ name: 'jason borne' }`. + * + * ####Note: + * + * Be careful to not use an existing model instance for the update clause (this won't work and can cause weird behavior like infinite loops). Also, ensure that the update clause does not have an _id property, which causes Mongo to return a "Mod on _id not allowed" error. + * + * ####Note: + * + * To update documents without waiting for a response from MongoDB, do not pass a `callback`, then call `exec` on the returned [Query](#query-js): + * + * Comment.update({ _id: id }, { $set: { text: 'changed' }}).exec(); + * + * ####Note: + * + * Although values are casted to their appropriate types when using update, the following are *not* applied: + * + * - defaults + * - setters + * - validators + * - middleware + * + * If you need those features, use the traditional approach of first retrieving the document. + * + * Model.findOne({ name: 'borne' }, function (err, doc) { + * if (err) .. + * doc.name = 'jason borne'; + * doc.save(callback); + * }) + * + * @see strict schemas http://mongoosejs.com/docs/guide.html#strict + * @param {Object} conditions + * @param {Object} update + * @param {Object} [options] + * @param {Function} [callback] + * @return {Query} + * @api public + */ + +Model.update = function update (conditions, doc, options, callback) { + var mq = new Query({}, {}, this, this.collection); + return mq.update(conditions, doc, options, callback); +}; + +/** + * Executes a mapReduce command. + * + * `o` is an object specifying all mapReduce options as well as the map and reduce functions. All options are delegated to the driver implementation. + * + * ####Example: + * + * var o = {}; + * o.map = function () { emit(this.name, 1) } + * o.reduce = function (k, vals) { return vals.length } + * User.mapReduce(o, function (err, results) { + * console.log(results) + * }) + * + * ####Other options: + * + * - `query` {Object} query filter object. + * - `limit` {Number} max number of documents + * - `keeptemp` {Boolean, default:false} keep temporary data + * - `finalize` {Function} finalize function + * - `scope` {Object} scope variables exposed to map/reduce/finalize during execution + * - `jsMode` {Boolean, default:false} it is possible to make the execution stay in JS. Provided in MongoDB > 2.0.X + * - `verbose` {Boolean, default:false} provide statistics on job execution time. + * - `out*` {Object, default: {inline:1}} sets the output target for the map reduce job. + * + * ####* out options: + * + * - `{inline:1}` the results are returned in an array + * - `{replace: 'collectionName'}` add the results to collectionName: the results replace the collection + * - `{reduce: 'collectionName'}` add the results to collectionName: if dups are detected, uses the reducer / finalize functions + * - `{merge: 'collectionName'}` add the results to collectionName: if dups exist the new docs overwrite the old + * + * If `options.out` is set to `replace`, `merge`, or `reduce`, a Model instance is returned that can be used for further querying. Queries run against this model are all executed with the `lean` option; meaning only the js object is returned and no Mongoose magic is applied (getters, setters, etc). + * + * ####Example: + * + * var o = {}; + * o.map = function () { emit(this.name, 1) } + * o.reduce = function (k, vals) { return vals.length } + * o.out = { replace: 'createdCollectionNameForResults' } + * o.verbose = true; + * + * User.mapReduce(o, function (err, model, stats) { + * console.log('map reduce took %d ms', stats.processtime) + * model.find().where('value').gt(10).exec(function (err, docs) { + * console.log(docs); + * }); + * }) + * + * // a promise is returned so you may instead write + * var promise = User.mapReduce(o); + * promise.then(function (model, stats) { + * console.log('map reduce took %d ms', stats.processtime) + * return model.find().where('value').gt(10).exec(); + * }).then(function (docs) { + * console.log(docs); + * }).then(null, handleError).end() + * + * @param {Object} o an object specifying map-reduce options + * @param {Function} [callback] optional callback + * @see http://www.mongodb.org/display/DOCS/MapReduce + * @return {Promise} + * @api public + */ + +Model.mapReduce = function mapReduce (o, callback) { + var promise = new Promise(callback); + var self = this; + + if (!Model.mapReduce.schema) { + var opts = { noId: true, noVirtualId: true, strict: false } + Model.mapReduce.schema = new Schema({}, opts); + } + + if (!o.out) o.out = { inline: 1 }; + + o.map = String(o.map); + o.reduce = String(o.reduce); + + if (o.query) { + var q = new Query(o.query); + q.cast(this); + o.query = q._conditions; + q = undefined; + } + + this.collection.mapReduce(null, null, o, function (err, ret, stats) { + if (err) return promise.error(err); + + if (ret.findOne && ret.mapReduce) { + // returned a collection, convert to Model + var model = Model.compile( + '_mapreduce_' + ret.collectionName + , Model.mapReduce.schema + , ret.collectionName + , self.db + , self.base); + + model._mapreduce = true; + + return promise.fulfill(model, stats); + } + + promise.fulfill(ret, stats); + }); + + return promise; +} + +/** + * geoNear support for Mongoose + * + * ####Options: + * - `lean` {Boolean} return the raw object + * - All options supported by the driver are also supported + * + * ####Example: + * + * // Legacy point + * Model.geoNear([1,3], { maxDistance : 5, spherical : true }, function(err, results, stats) { + * console.log(results); + * }); + * + * // geoJson + * var point = { type : "Point", coordinates : [9,9] }; + * Model.geoNear(point, { maxDistance : 5, spherical : true }, function(err, results, stats) { + * console.log(results); + * }); + * + * @param {Object/Array} GeoJSON point or legacy coordinate pair [x,y] to search near + * @param {Object} options for the qurery + * @param {Function} [callback] optional callback for the query + * @return {Promise} + * @see http://docs.mongodb.org/manual/core/2dsphere/ + * @see http://mongodb.github.io/node-mongodb-native/api-generated/collection.html?highlight=geonear#geoNear + * @api public + */ + +Model.geoNear = function (near, options, callback) { + if ('function' == typeof options) { + callback = options; + options = {}; + } + + var promise = new Promise(callback); + if (!near) { + promise.error(new Error("Must pass a near option to geoNear")); + return promise; + } + + var x,y; + + if (Array.isArray(near)) { + if (near.length != 2) { + promise.error(new Error("If using legacy coordinates, must be an array of size 2 for geoNear")); + return promise; + } + x = near[0]; + y = near[1]; + } else { + if (near.type != "Point" || !Array.isArray(near.coordinates)) { + promise.error(new Error("Must pass either a legacy coordinate array or GeoJSON Point to geoNear")); + return promise; + } + + x = near.coordinates[0]; + y = near.coordinates[1]; + } + + var self = this; + this.collection.geoNear(x, y, options, function (err, res) { + if (err) return promise.error(err); + if (options.lean) return promise.fulfill(res.results, res.stats); + + var count = res.results.length; + // if there are no results, fulfill the promise now + if (count == 0) { + return promise.fulfill(res.results, res.stats); + } + + var errSeen = false; + for (var i=0; i < res.results.length; i++) { + var temp = res.results[i].obj; + res.results[i].obj = new self(); + res.results[i].obj.init(temp, function (err) { + if (err && !errSeen) { + errSeen = true; + return promise.error(err); + } + --count || promise.fulfill(res.results, res.stats); + }); + } + }); + return promise; +}; + +/** + * Performs [aggregations](http://docs.mongodb.org/manual/applications/aggregation/) on the models collection. + * + * If a `callback` is passed, the `aggregate` is executed and a `Promise` is returned. If a callback is not passed, the `aggregate` itself is returned. + * + * ####Example: + * + * // Find the max balance of all accounts + * Users.aggregate( + * { $group: { _id: null, maxBalance: { $max: '$balance' }}} + * , { $project: { _id: 0, maxBalance: 1 }} + * , function (err, res) { + * if (err) return handleError(err); + * console.log(res); // [ { maxBalance: 98000 } ] + * }); + * + * // Or use the aggregation pipeline builder. + * Users.aggregate() + * .group({ _id: null, maxBalance: { $max: '$balance' } }) + * .select('-id maxBalance') + * .exec(function (err, res) { + * if (err) return handleError(err); + * console.log(res); // [ { maxBalance: 98 } ] + * }); + * + * ####NOTE: + * + * - Arguments are not cast to the model's schema because `$project` operators allow redefining the "shape" of the documents at any stage of the pipeline, which may leave documents in an incompatible format. + * - The documents returned are plain javascript objects, not mongoose documents (since any shape of document can be returned). + * - Requires MongoDB >= 2.1 + * + * @see Aggregate #aggregate_Aggregate + * @see MongoDB http://docs.mongodb.org/manual/applications/aggregation/ + * @param {Object|Array} [...] aggregation pipeline operator(s) or operator array + * @param {Function} [callback] + * @return {Aggregate|Promise} + * @api public + */ + +Model.aggregate = function aggregate () { + var args = [].slice.call(arguments) + , aggregate + , callback; + + if ('function' === typeof args[args.length - 1]) { + callback = args.pop(); + } + + if (1 === args.length && util.isArray(args[0])) { + aggregate = new Aggregate(args[0]); + } else { + aggregate = new Aggregate(args); + } + + aggregate.bind(this); + + if ('undefined' === typeof callback) { + return aggregate; + } + + return aggregate.exec(callback); +} + +/** + * Implements `$geoSearch` functionality for Mongoose + * + * ####Example: + * + * var options = { near: [10, 10], maxDistance: 5 }; + * Locations.geoSearch({ type : "house" }, options, function(err, res) { + * console.log(res); + * }); + * + * ####Options: + * - `near` {Array} x,y point to search for + * - `maxDistance` {Number} the maximum distance from the point near that a result can be + * - `limit` {Number} The maximum number of results to return + * - `lean` {Boolean} return the raw object instead of the Mongoose Model + * + * @param {Object} condition an object that specifies the match condition (required) + * @param {Object} options for the geoSearch, some (near, maxDistance) are required + * @param {Function} [callback] optional callback + * @return {Promise} + * @see http://docs.mongodb.org/manual/reference/command/geoSearch/ + * @see http://docs.mongodb.org/manual/core/geohaystack/ + * @api public + */ + +Model.geoSearch = function (conditions, options, callback) { + if ('function' == typeof options) { + callback = options; + options = {}; + } + + var promise = new Promise(callback); + + if (conditions == undefined || !utils.isObject(conditions)) { + return promise.error(new Error("Must pass conditions to geoSearch")); + } + + if (!options.near) { + return promise.error(new Error("Must specify the near option in geoSearch")); + } + + if (!Array.isArray(options.near)) { + return promise.error(new Error("near option must be an array [x, y]")); + } + + + // send the conditions in the options object + options.search = conditions; + var self = this; + + this.collection.geoHaystackSearch(options.near[0], options.near[1], options, function (err, res) { + // have to deal with driver problem. Should be fixed in a soon-ish release + // (7/8/2013) + if (err || res.errmsg) { + if (!err) err = new Error(res.errmsg); + if (res && res.code !== undefined) err.code = res.code; + return promise.error(err); + } + + if (options.lean) return promise.fulfill(res.results, res.stats); + + var count = res.results.length; + var errSeen = false; + for (var i=0; i < res.results.length; i++) { + var temp = res.results[i]; + res.results[i] = new self(); + res.results[i].init(temp, {}, function (err) { + if (err && !errSeen) { + errSeen = true; + return promise.error(err); + } + + --count || (!errSeen && promise.fulfill(res.results, res.stats)); + }); + } + }); + + return promise; +}; + +/** + * Populates document references. + * + * ####Available options: + * + * - path: space delimited path(s) to populate + * - select: optional fields to select + * - match: optional query conditions to match + * - model: optional name of the model to use for population + * - options: optional query options like sort, limit, etc + * + * ####Examples: + * + * // populates a single object + * User.findById(id, function (err, user) { + * var opts = [ + * { path: 'company', match: { x: 1 }, select: 'name' } + * , { path: 'notes', options: { limit: 10 }, model: 'override' } + * ] + * + * User.populate(user, opts, function (err, user) { + * console.log(user); + * }) + * }) + * + * // populates an array of objects + * User.find(match, function (err, users) { + * var opts = [{ path: 'company', match: { x: 1 }, select: 'name' }] + * + * var promise = User.populate(users, opts); + * promise.then(console.log).end(); + * }) + * + * // imagine a Weapon model exists with two saved documents: + * // { _id: 389, name: 'whip' } + * // { _id: 8921, name: 'boomerang' } + * + * var user = { name: 'Indiana Jones', weapon: 389 } + * Weapon.populate(user, { path: 'weapon', model: 'Weapon' }, function (err, user) { + * console.log(user.weapon.name) // whip + * }) + * + * // populate many plain objects + * var users = [{ name: 'Indiana Jones', weapon: 389 }] + * users.push({ name: 'Batman', weapon: 8921 }) + * Weapon.populate(users, { path: 'weapon' }, function (err, users) { + * users.forEach(function (user) { + * console.log('%s uses a %s', users.name, user.weapon.name) + * // Indiana Jones uses a whip + * // Batman uses a boomerang + * }) + * }) + * // Note that we didn't need to specify the Weapon model because + * // we were already using it's populate() method. + * + * @param {Document|Array} docs Either a single document or array of documents to populate. + * @param {Object} options A hash of key/val (path, options) used for population. + * @param {Function} [cb(err,doc)] Optional callback, executed upon completion. Receives `err` and the `doc(s)`. + * @return {Promise} + * @api public + */ + +Model.populate = function (docs, paths, cb) { + var promise = new Promise(cb); + + // always resolve on nextTick for consistent async behavior + function resolve () { + var args = utils.args(arguments); + process.nextTick(function () { + promise.resolve.apply(promise, args); + }); + } + + // normalized paths + var paths = utils.populate(paths); + var pending = paths.length; + + if (0 === pending) { + resolve(null, docs); + return promise; + } + + // each path has its own query options and must be executed separately + var i = pending; + var path; + while (i--) { + path = paths[i]; + populate(this, docs, path, next); + } + + return promise; + + function next (err) { + if (err) return resolve(err); + if (--pending) return; + resolve(null, docs); + } +} + +/*! + * Populates `docs` + */ + +function populate (model, docs, options, cb) { + var select = options.select + , match = options.match + , path = options.path + + var schema = model._getSchema(path); + var subpath; + + // handle document arrays + if (schema && schema.caster) { + schema = schema.caster; + } + + // model name for the populate query + var modelName = options.model && options.model.modelName + || options.model // query options + || schema && schema.options.ref // declared in schema + || model.modelName // an ad-hoc structure + + var Model = model.db.model(modelName); + + // expose the model used + options.model = Model; + + // normalize single / multiple docs passed + if (!Array.isArray(docs)) { + docs = [docs]; + } + + if (0 === docs.length || docs.every(utils.isNullOrUndefined)) { + return cb(); + } + + var rawIds = []; + var i, doc, id; + var len = docs.length; + var ret; + var found = 0; + var isDocument; + + for (i = 0; i < len; i++) { + ret = undefined; + doc = docs[i]; + id = String(utils.getValue("_id", doc)); + isDocument = !! doc.$__; + + if (isDocument && !doc.isModified(path)) { + // it is possible a previously populated path is being + // populated again. Because users can specify matcher + // clauses in their populate arguments we use the cached + // _ids from the original populate call to ensure all _ids + // are looked up, but only if the path wasn't modified which + // signifies the users intent of the state of the path. + ret = doc.populated(path); + } + + if (!ret || Array.isArray(ret) && 0 === ret.length) { + ret = utils.getValue(path, doc); + } + + if (ret) { + ret = convertTo_id(ret); + + // previously we always assigned this even if the document had no _id + options._docs[id] = Array.isArray(ret) + ? ret.slice() + : ret; + } + + // always retain original values, even empty values. these are + // used to map the query results back to the correct position. + rawIds.push(ret); + + if (isDocument) { + // cache original populated _ids and model used + doc.populated(path, options._docs[id], options); + } + } + + var ids = utils.array.flatten(rawIds, function (item) { + // no need to include undefined values in our query + return undefined !== item; + }); + + if (0 === ids.length || ids.every(utils.isNullOrUndefined)) { + return cb(); + } + + // preserve original match conditions by copying + if (match) { + match = utils.object.shallowCopy(match); + } else { + match = {}; + } + + match._id || (match._id = { $in: ids }); + + var assignmentOpts = {}; + assignmentOpts.sort = options.options && options.options.sort || undefined; + assignmentOpts.excludeId = /\s?-_id\s?/.test(select) || (select && 0 === select._id); + + if (assignmentOpts.excludeId) { + // override the exclusion from the query so we can use the _id + // for document matching during assignment. we'll delete the + // _id back off before returning the result. + if ('string' == typeof select) { + select = select.replace(/\s?-_id\s?/g, ' '); + } else { + // preserve original select conditions by copying + select = utils.object.shallowCopy(select); + delete select._id; + } + } + + // if a limit option is passed, we should have the limit apply to *each* + // document, not apply in the aggregate + if (options.options && options.options.limit) { + options.options.limit = options.options.limit * len; + } + + Model.find(match, select, options.options, function (err, vals) { + if (err) return cb(err); + + var lean = options.options && options.options.lean; + var len = vals.length; + var rawOrder = {}; + var rawDocs = {} + var key; + var val; + + // optimization: + // record the document positions as returned by + // the query result. + for (var i = 0; i < len; i++) { + val = vals[i]; + key = String(utils.getValue('_id', val)); + rawDocs[key] = val; + rawOrder[key] = i; + + // flag each as result of population + if (!lean) val.$__.wasPopulated = true; + } + + assignVals({ + rawIds: rawIds, + rawDocs: rawDocs, + rawOrder: rawOrder, + docs: docs, + path: path, + options: assignmentOpts + }); + + cb(); + }); +} + +/*! + * Retrieve the _id of `val` if a Document or Array of Documents. + * + * @param {Array|Document|Any} val + * @return {Array|Document|Any} + */ + +function convertTo_id (val) { + if (val instanceof Model) return val._id; + + if (Array.isArray(val)) { + for (var i = 0; i < val.length; ++i) { + if (val[i] instanceof Model) { + val[i] = val[i]._id; + } + } + return val; + } + + return val; +} + +/*! + * Assigns documents returned from a population query back + * to the original document path. + */ + +function assignVals (o) { + // replace the original ids in our intermediate _ids structure + // with the documents found by query + + assignRawDocsToIdStructure(o.rawIds, o.rawDocs, o.rawOrder, o.options); + + // now update the original documents being populated using the + // result structure that contains real documents. + + var docs = o.docs; + var path = o.path; + var rawIds = o.rawIds; + var options = o.options; + + for (var i = 0; i < docs.length; ++i) { + utils.setValue(path, rawIds[i], docs[i], function (val) { + return valueFilter(val, options); + }); + } +} + +/*! + * 1) Apply backwards compatible find/findOne behavior to sub documents + * + * find logic: + * a) filter out non-documents + * b) remove _id from sub docs when user specified + * + * findOne + * a) if no doc found, set to null + * b) remove _id from sub docs when user specified + * + * 2) Remove _ids when specified by users query. + * + * background: + * _ids are left in the query even when user excludes them so + * that population mapping can occur. + */ + +function valueFilter (val, assignmentOpts) { + if (Array.isArray(val)) { + // find logic + var ret = []; + for (var i = 0; i < val.length; ++i) { + var subdoc = val[i]; + if (!isDoc(subdoc)) continue; + maybeRemoveId(subdoc, assignmentOpts); + ret.push(subdoc); + } + return ret; + } + + // findOne + if (isDoc(val)) { + maybeRemoveId(val, assignmentOpts); + return val; + } + + return null; +} + +/*! + * Remove _id from `subdoc` if user specified "lean" query option + */ + +function maybeRemoveId (subdoc, assignmentOpts) { + if (assignmentOpts.excludeId) { + if ('function' == typeof subdoc.setValue) { + subdoc.setValue('_id', undefined); + } else { + delete subdoc._id; + } + } +} + +/*! + * Determine if `doc` is a document returned + * by a populate query. + */ + +function isDoc (doc) { + if (null == doc) + return false; + + var type = typeof doc; + if ('string' == type) + return false; + + if ('number' == type) + return false; + + if (Buffer.isBuffer(doc)) + return false; + + if ('ObjectID' == doc.constructor.name) + return false; + + // only docs + return true; +} + +/*! + * Assign `vals` returned by mongo query to the `rawIds` + * structure returned from utils.getVals() honoring + * query sort order if specified by user. + * + * This can be optimized. + * + * Rules: + * + * if the value of the path is not an array, use findOne rules, else find. + * for findOne the results are assigned directly to doc path (including null results). + * for find, if user specified sort order, results are assigned directly + * else documents are put back in original order of array if found in results + * + * @param {Array} rawIds + * @param {Array} vals + * @param {Boolean} sort + * @api private + */ + +function assignRawDocsToIdStructure (rawIds, resultDocs, resultOrder, options, recursed) { + // honor user specified sort order + var newOrder = []; + var sorting = options.sort && rawIds.length > 1; + var found; + var doc; + var sid; + var id; + + for (var i = 0; i < rawIds.length; ++i) { + id = rawIds[i]; + + if (Array.isArray(id)) { + // handle [ [id0, id2], [id3] ] + assignRawDocsToIdStructure(id, resultDocs, resultOrder, options, true); + newOrder.push(id); + continue; + } + + if (null === id && !sorting) { + // keep nulls for findOne unless sorting, which always + // removes them (backward compat) + newOrder.push(id); + continue; + } + + sid = String(id); + found = false; + + if (recursed) { + // apply find behavior + + // assign matching documents in original order unless sorting + doc = resultDocs[sid]; + if (doc) { + if (sorting) { + newOrder[resultOrder[sid]] = doc; + } else { + newOrder.push(doc); + } + } else { + newOrder.push(id); + } + } else { + // apply findOne behavior - if document in results, assign, else assign null + newOrder[i] = doc = resultDocs[sid] || null; + } + } + + rawIds.length = 0; + if (newOrder.length) { + // reassign the documents based on corrected order + + // forEach skips over sparse entries in arrays so we + // can safely use this to our advantage dealing with sorted + // result sets too. + newOrder.forEach(function (doc, i) { + rawIds[i] = doc; + }); + } +} + +/** + * Finds the schema for `path`. This is different than + * calling `schema.path` as it also resolves paths with + * positional selectors (something.$.another.$.path). + * + * @param {String} path + * @return {Schema} + * @api private + */ + +Model._getSchema = function _getSchema (path) { + var schema = this.schema + , pathschema = schema.path(path); + + if (pathschema) + return pathschema; + + // look for arrays + return (function search (parts, schema) { + var p = parts.length + 1 + , foundschema + , trypath + + while (p--) { + trypath = parts.slice(0, p).join('.'); + foundschema = schema.path(trypath); + if (foundschema) { + if (foundschema.caster) { + + // array of Mixed? + if (foundschema.caster instanceof Types.Mixed) { + return foundschema.caster; + } + + // Now that we found the array, we need to check if there + // are remaining document paths to look up for casting. + // Also we need to handle array.$.path since schema.path + // doesn't work for that. + // If there is no foundschema.schema we are dealing with + // a path like array.$ + if (p !== parts.length && foundschema.schema) { + if ('$' === parts[p]) { + // comments.$.comments.$.title + return search(parts.slice(p+1), foundschema.schema); + } else { + // this is the last path of the selector + return search(parts.slice(p), foundschema.schema); + } + } + } + return foundschema; + } + } + })(path.split('.'), schema) +} + +/*! + * Compiler utility. + * + * @param {String} name model name + * @param {Schema} schema + * @param {String} collectionName + * @param {Connection} connection + * @param {Mongoose} base mongoose instance + */ + +Model.compile = function compile (name, schema, collectionName, connection, base) { + var versioningEnabled = false !== schema.options.versionKey; + + if (versioningEnabled && !schema.paths[schema.options.versionKey]) { + // add versioning to top level documents only + var o = {}; + o[schema.options.versionKey] = Number; + schema.add(o); + } + + // generate new class + function model (doc, fields, skipId) { + if (!(this instanceof model)) + return new model(doc, fields, skipId); + Model.call(this, doc, fields, skipId); + }; + + model.base = base; + model.modelName = name; + model.__proto__ = Model; + model.prototype.__proto__ = Model.prototype; + model.model = Model.prototype.model; + model.db = model.prototype.db = connection; + model.discriminators = model.prototype.discriminators = undefined; + + model.prototype.$__setSchema(schema); + + var collectionOptions = { + bufferCommands: schema.options.bufferCommands + , capped: schema.options.capped + }; + + model.prototype.collection = connection.collection( + collectionName + , collectionOptions + ); + + // apply methods + for (var i in schema.methods) + model.prototype[i] = schema.methods[i]; + + // apply statics + for (var i in schema.statics) + model[i] = schema.statics[i]; + + model.schema = model.prototype.schema; + model.options = model.prototype.options; + model.collection = model.prototype.collection; + + return model; +}; + +/*! + * Subclass this model with `conn`, `schema`, and `collection` settings. + * + * @param {Connection} conn + * @param {Schema} [schema] + * @param {String} [collection] + * @return {Model} + */ + +Model.__subclass = function subclass (conn, schema, collection) { + // subclass model using this connection and collection name + var model = this; + + var Model = function Model (doc, fields, skipId) { + if (!(this instanceof Model)) { + return new Model(doc, fields, skipId); + } + model.call(this, doc, fields, skipId); + } + + Model.__proto__ = model; + Model.prototype.__proto__ = model.prototype; + Model.db = Model.prototype.db = conn; + + var s = schema && 'string' != typeof schema + ? schema + : model.prototype.schema; + + var options = s.options || {}; + + if (!collection) { + collection = model.prototype.schema.get('collection') + || utils.toCollectionName(model.modelName, options); + } + + var collectionOptions = { + bufferCommands: s ? options.bufferCommands : true + , capped: s && options.capped + }; + + Model.prototype.collection = conn.collection(collection, collectionOptions); + Model.collection = Model.prototype.collection; + Model.init(); + return Model; +} + +/*! + * Module exports. + */ + +module.exports = exports = Model; diff --git a/node_modules/mongoose/lib/promise.js b/node_modules/mongoose/lib/promise.js new file mode 100644 index 0000000..ba0f026 --- /dev/null +++ b/node_modules/mongoose/lib/promise.js @@ -0,0 +1,261 @@ + +/*! + * Module dependencies + */ + +var MPromise = require('mpromise'); + +/** + * Promise constructor. + * + * Promises are returned from executed queries. Example: + * + * var query = Candy.find({ bar: true }); + * var promise = query.exec(); + * + * @param {Function} fn a function which will be called when the promise is resolved that accepts `fn(err, ...){}` as signature + * @inherits mpromise https://github.com/aheckmann/mpromise + * @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter + * @event `err`: Emits when the promise is rejected + * @event `complete`: Emits when the promise is fulfilled + * @api public + */ + +function Promise (fn) { + MPromise.call(this, fn); +} + +/*! + * Inherit from mpromise + */ + +Promise.prototype = Object.create(MPromise.prototype, { + constructor: { + value: Promise + , enumerable: false + , writable: true + , configurable: true + } +}); + +/*! + * Override event names for backward compatibility. + */ + +Promise.SUCCESS = 'complete'; +Promise.FAILURE = 'err'; + +/** + * Adds `listener` to the `event`. + * + * If `event` is either the success or failure event and the event has already been emitted, the`listener` is called immediately and passed the results of the original emitted event. + * + * @see mpromise#on https://github.com/aheckmann/mpromise#on + * @method on + * @memberOf Promise + * @param {String} event + * @param {Function} listener + * @return {Promise} this + * @api public + */ + +/** + * Rejects this promise with `reason`. + * + * If the promise has already been fulfilled or rejected, not action is taken. + * + * @see mpromise#reject https://github.com/aheckmann/mpromise#reject + * @method reject + * @memberOf Promise + * @param {Object|String|Error} reason + * @return {Promise} this + * @api public + */ + +/** + * Rejects this promise with `err`. + * + * If the promise has already been fulfilled or rejected, not action is taken. + * + * Differs from [#reject](#promise_Promise-reject) by first casting `err` to an `Error` if it is not `instanceof Error`. + * + * @api public + * @param {Error|String} err + * @return {Promise} this + */ + +Promise.prototype.error = function (err) { + if (!(err instanceof Error)) err = new Error(err); + return this.reject(err); +} + +/** + * Resolves this promise to a rejected state if `err` is passed or a fulfilled state if no `err` is passed. + * + * If the promise has already been fulfilled or rejected, not action is taken. + * + * `err` will be cast to an Error if not already instanceof Error. + * + * _NOTE: overrides [mpromise#resolve](https://github.com/aheckmann/mpromise#resolve) to provide error casting._ + * + * @param {Error} [err] error or null + * @param {Object} [val] value to fulfill the promise with + * @api public + */ + +Promise.prototype.resolve = function (err, val) { + if (err) return this.error(err); + return this.fulfill(val); +} + +/** + * Adds a single function as a listener to both err and complete. + * + * It will be executed with traditional node.js argument position when the promise is resolved. + * + * promise.addBack(function (err, args...) { + * if (err) return handleError(err); + * console.log('success'); + * }) + * + * Alias of [mpromise#onResolve](https://github.com/aheckmann/mpromise#onresolve). + * + * _Deprecated. Use `onResolve` instead._ + * + * @method addBack + * @param {Function} listener + * @return {Promise} this + * @deprecated + */ + +Promise.prototype.addBack = Promise.prototype.onResolve; + +/** + * Fulfills this promise with passed arguments. + * + * @method fulfill + * @see https://github.com/aheckmann/mpromise#fulfill + * @param {any} args + * @api public + */ + +/** + * Fulfills this promise with passed arguments. + * + * @method fulfill + * @see https://github.com/aheckmann/mpromise#fulfill + * @param {any} args + * @api public + */ + +/** + * Fulfills this promise with passed arguments. + * + * Alias of [mpromise#fulfill](https://github.com/aheckmann/mpromise#fulfill). + * + * _Deprecated. Use `fulfill` instead._ + * + * @method complete + * @param {any} args + * @api public + * @deprecated + */ + +Promise.prototype.complete = MPromise.prototype.fulfill; + +/** + * Adds a listener to the `complete` (success) event. + * + * Alias of [mpromise#onFulfill](https://github.com/aheckmann/mpromise#onfulfill). + * + * _Deprecated. Use `onFulfill` instead._ + * + * @method addCallback + * @param {Function} listener + * @return {Promise} this + * @api public + * @deprecated + */ + +Promise.prototype.addCallback = Promise.prototype.onFulfill; + +/** + * Adds a listener to the `err` (rejected) event. + * + * Alias of [mpromise#onReject](https://github.com/aheckmann/mpromise#onreject). + * + * _Deprecated. Use `onReject` instead._ + * + * @method addErrback + * @param {Function} listener + * @return {Promise} this + * @api public + * @deprecated + */ + +Promise.prototype.addErrback = Promise.prototype.onReject; + +/** + * Creates a new promise and returns it. If `onFulfill` or `onReject` are passed, they are added as SUCCESS/ERROR callbacks to this promise after the nextTick. + * + * Conforms to [promises/A+](https://github.com/promises-aplus/promises-spec) specification. + * + * ####Example: + * + * var promise = Meetups.find({ tags: 'javascript' }).select('_id').exec(); + * promise.then(function (meetups) { + * var ids = meetups.map(function (m) { + * return m._id; + * }); + * return People.find({ meetups: { $in: ids }).exec(); + * }).then(function (people) { + * if (people.length < 10000) { + * throw new Error('Too few people!!!'); + * } else { + * throw new Error('Still need more people!!!'); + * } + * }).then(null, function (err) { + * assert.ok(err instanceof Error); + * }); + * + * @see promises-A+ https://github.com/promises-aplus/promises-spec + * @see mpromise#then https://github.com/aheckmann/mpromise#then + * @method then + * @memberOf Promise + * @param {Function} onFulFill + * @param {Function} onReject + * @return {Promise} newPromise + */ + +/** + * Signifies that this promise was the last in a chain of `then()s`: if a handler passed to the call to `then` which produced this promise throws, the exception will go uncaught. + * + * ####Example: + * + * var p = new Promise; + * p.then(function(){ throw new Error('shucks') }); + * setTimeout(function () { + * p.fulfill(); + * // error was caught and swallowed by the promise returned from + * // p.then(). we either have to always register handlers on + * // the returned promises or we can do the following... + * }, 10); + * + * // this time we use .end() which prevents catching thrown errors + * var p = new Promise; + * var p2 = p.then(function(){ throw new Error('shucks') }).end(); // <-- + * setTimeout(function () { + * p.fulfill(); // throws "shucks" + * }, 10); + * + * @api public + * @see mpromise#end https://github.com/aheckmann/mpromise#end + * @method end + * @memberOf Promise + */ + +/*! + * expose + */ + +module.exports = Promise; diff --git a/node_modules/mongoose/lib/query.js b/node_modules/mongoose/lib/query.js new file mode 100644 index 0000000..fc13404 --- /dev/null +++ b/node_modules/mongoose/lib/query.js @@ -0,0 +1,2898 @@ +/*! + * Module dependencies. + */ + +var mquery = require('mquery'); +var util = require('util'); +var events = require('events'); + +var utils = require('./utils'); +var Promise = require('./promise'); +var helpers = require('./queryhelpers'); +var Types = require('./schema/index'); +var Document = require('./document'); +var QueryStream = require('./querystream'); + +/** + * Query constructor used for building queries. + * + * ####Example: + * + * var query = new Query(); + * query.setOptions({ lean : true }); + * query.collection(model.collection); + * query.where('age').gte(21).exec(callback); + * + * @param {Object} [options] + * @param {Object} [model] + * @param {Object} [conditions] + * @param {Object} [collection] Mongoose collection + * @api public + */ + +function Query(conditions, options, model, collection) { + // this stuff is for dealing with custom queries created by #toConstructor + if (!this._mongooseOptions) { + this._mongooseOptions = options || {}; + } else { + // this is the case where we have a CustomQuery, we need to check if we got + // options passed in, and if we did, merge them in + + if (options) { + var keys = Object.keys(options); + for (var i=0; i < keys.length; i++) { + var k = keys[i]; + this._mongooseOptions[k] = options[k]; + } + } + } + + if (collection) { + this.mongooseCollection = collection; + } + + if (model) { + this.model = model; + } + + // this is needed because map reduce returns a model that can be queried, but + // all of the queries on said model should be lean + if (this.model && this.model._mapreduce) { + this.lean(); + } + + // inherit mquery + mquery.call(this, this.mongooseCollection, options); + + if (conditions) { + this.find(conditions); + } +} + +/*! + * inherit mquery + */ + +Query.prototype = new mquery; +Query.prototype.constructor = Query; +Query.base = mquery.prototype; + +/** + * Flag to opt out of using `$geoWithin`. + * + * mongoose.Query.use$geoWithin = false; + * + * MongoDB 2.4 deprecated the use of `$within`, replacing it with `$geoWithin`. Mongoose uses `$geoWithin` by default (which is 100% backward compatible with $within). If you are running an older version of MongoDB, set this flag to `false` so your `within()` queries continue to work. + * + * @see http://docs.mongodb.org/manual/reference/operator/geoWithin/ + * @default true + * @property use$geoWithin + * @memberOf Query + * @receiver Query + * @api public + */ + +Query.use$geoWithin = mquery.use$geoWithin; + +/** + * Converts this query to a customized, reusable query constructor with all arguments and options retained. + * + * ####Example + * + * // Create a query for adventure movies and read from the primary + * // node in the replica-set unless it is down, in which case we'll + * // read from a secondary node. + * var query = Movie.find({ tags: 'adventure' }).read('primaryPreferred'); + * + * // create a custom Query constructor based off these settings + * var Adventure = query.toConstructor(); + * + * // Adventure is now a subclass of mongoose.Query and works the same way but with the + * // default query parameters and options set. + * Adventure().exec(callback) + * + * // further narrow down our query results while still using the previous settings + * Adventure().where({ name: /^Life/ }).exec(callback); + * + * // since Adventure is a stand-alone constructor we can also add our own + * // helper methods and getters without impacting global queries + * Adventure.prototype.startsWith = function (prefix) { + * this.where({ name: new RegExp('^' + prefix) }) + * return this; + * } + * Object.defineProperty(Adventure.prototype, 'highlyRated', { + * get: function () { + * this.where({ rating: { $gt: 4.5 }}); + * return this; + * } + * }) + * Adventure().highlyRated.startsWith('Life').exec(callback) + * + * New in 3.7.3 + * + * @return {Query} subclass-of-Query + * @api public + */ + +Query.prototype.toConstructor = function toConstructor () { + function CustomQuery (criteria, options) { + if (!(this instanceof CustomQuery)) + return new CustomQuery(criteria, options); + Query.call(this, criteria, options || null); + } + + util.inherits(CustomQuery, Query); + + // set inherited defaults + var p = CustomQuery.prototype; + + p.options = {}; + + p.setOptions(this.options); + + p.op = this.op; + p._conditions = utils.clone(this._conditions); + p._fields = utils.clone(this._fields); + p._update = utils.clone(this._update); + p._path = this._path; + p._distict = this._distinct; + p._collection = this._collection; + p.model = this.model; + p.mongooseCollection = this.mongooseCollection; + p._mongooseOptions = this._mongooseOptions; + + return CustomQuery; +} + +/** + * Specifies a javascript function or expression to pass to MongoDBs query system. + * + * ####Example + * + * query.$where('this.comments.length > 10 || this.name.length > 5') + * + * // or + * + * query.$where(function () { + * return this.comments.length > 10 || this.name.length > 5; + * }) + * + * ####NOTE: + * + * Only use `$where` when you have a condition that cannot be met using other MongoDB operators like `$lt`. + * **Be sure to read about all of [its caveats](http://docs.mongodb.org/manual/reference/operator/where/) before using.** + * + * @see $where http://docs.mongodb.org/manual/reference/operator/where/ + * @method $where + * @param {String|Function} js javascript string or function + * @return {Query} this + * @memberOf Query + * @method $where + * @api public + */ + +/** + * Specifies a `path` for use with chaining. + * + * ####Example + * + * // instead of writing: + * User.find({age: {$gte: 21, $lte: 65}}, callback); + * + * // we can instead write: + * User.where('age').gte(21).lte(65); + * + * // passing query conditions is permitted + * User.find().where({ name: 'vonderful' }) + * + * // chaining + * User + * .where('age').gte(21).lte(65) + * .where('name', /^vonderful/i) + * .where('friends').slice(10) + * .exec(callback) + * + * @method where + * @memberOf Query + * @param {String|Object} [path] + * @param {any} [val] + * @return {Query} this + * @api public + */ + +/** + * Specifies the complementary comparison value for paths specified with `where()` + * + * ####Example + * + * User.where('age').equals(49); + * + * // is the same as + * + * User.where('age', 49); + * + * @method equals + * @memberOf Query + * @param {Object} val + * @return {Query} this + * @api public + */ + +/** + * Specifies arguments for an `$or` condition. + * + * ####Example + * + * query.or([{ color: 'red' }, { status: 'emergency' }]) + * + * @see $or http://docs.mongodb.org/manual/reference/operator/or/ + * @method or + * @memberOf Query + * @param {Array} array array of conditions + * @return {Query} this + * @api public + */ + +/** + * Specifies arguments for a `$nor` condition. + * + * ####Example + * + * query.nor([{ color: 'green' }, { status: 'ok' }]) + * + * @see $nor http://docs.mongodb.org/manual/reference/operator/nor/ + * @method nor + * @memberOf Query + * @param {Array} array array of conditions + * @return {Query} this + * @api public + */ + +/** + * Specifies arguments for a `$and` condition. + * + * ####Example + * + * query.and([{ color: 'green' }, { status: 'ok' }]) + * + * @method and + * @memberOf Query + * @see $and http://docs.mongodb.org/manual/reference/operator/and/ + * @param {Array} array array of conditions + * @return {Query} this + * @api public + */ + +/** + * Specifies a $gt query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * ####Example + * + * Thing.find().where('age').gt(21) + * + * // or + * Thing.find().gt('age', 21) + * + * @method gt + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @see $gt http://docs.mongodb.org/manual/reference/operator/gt/ + * @api public + */ + +/** + * Specifies a $gte query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @method gte + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @see $gte http://docs.mongodb.org/manual/reference/operator/gte/ + * @api public + */ + +/** + * Specifies a $lt query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @method lt + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @see $lt http://docs.mongodb.org/manual/reference/operator/lt/ + * @api public + */ + +/** + * Specifies a $lte query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @method lte + * @see $lte http://docs.mongodb.org/manual/reference/operator/lte/ + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies a $ne query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @see $ne http://docs.mongodb.org/manual/reference/operator/ne/ + * @method ne + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies an $in query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @see $in http://docs.mongodb.org/manual/reference/operator/in/ + * @method in + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies an $nin query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @see $nin http://docs.mongodb.org/manual/reference/operator/nin/ + * @method nin + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies an $all query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @see $all http://docs.mongodb.org/manual/reference/operator/all/ + * @method all + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies a $size query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * ####Example + * + * MyModel.where('tags').size(0).exec(function (err, docs) { + * if (err) return handleError(err); + * + * assert(Array.isArray(docs)); + * console.log('documents with 0 tags', docs); + * }) + * + * @see $size http://docs.mongodb.org/manual/reference/operator/size/ + * @method size + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies a $regex query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @see $regex http://docs.mongodb.org/manual/reference/operator/regex/ + * @method regex + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies a $maxDistance query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @see $maxDistance http://docs.mongodb.org/manual/reference/operator/maxDistance/ + * @method maxDistance + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies a `$mod` condition + * + * @method mod + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @return {Query} this + * @see $mod http://docs.mongodb.org/manual/reference/operator/mod/ + * @api public + */ + +/** + * Specifies an `$exists` condition + * + * ####Example + * + * // { name: { $exists: true }} + * Thing.where('name').exists() + * Thing.where('name').exists(true) + * Thing.find().exists('name') + * + * // { name: { $exists: false }} + * Thing.where('name').exists(false); + * Thing.find().exists('name', false); + * + * @method exists + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @return {Query} this + * @see $exists http://docs.mongodb.org/manual/reference/operator/exists/ + * @api public + */ + +/** + * Specifies an `$elemMatch` condition + * + * ####Example + * + * query.elemMatch('comment', { author: 'autobot', votes: {$gte: 5}}) + * + * query.where('comment').elemMatch({ author: 'autobot', votes: {$gte: 5}}) + * + * query.elemMatch('comment', function (elem) { + * elem.where('author').equals('autobot'); + * elem.where('votes').gte(5); + * }) + * + * query.where('comment').elemMatch(function (elem) { + * elem.where({ author: 'autobot' }); + * elem.where('votes').gte(5); + * }) + * + * @method elemMatch + * @memberOf Query + * @param {String|Object|Function} path + * @param {Object|Function} criteria + * @return {Query} this + * @see $elemMatch http://docs.mongodb.org/manual/reference/operator/elemMatch/ + * @api public + */ + +/** + * Defines a `$within` or `$geoWithin` argument for geo-spatial queries. + * + * ####Example + * + * query.where(path).within().box() + * query.where(path).within().circle() + * query.where(path).within().geometry() + * + * query.where('loc').within({ center: [50,50], radius: 10, unique: true, spherical: true }); + * query.where('loc').within({ box: [[40.73, -73.9], [40.7, -73.988]] }); + * query.where('loc').within({ polygon: [[],[],[],[]] }); + * + * query.where('loc').within([], [], []) // polygon + * query.where('loc').within([], []) // box + * query.where('loc').within({ type: 'LineString', coordinates: [...] }); // geometry + * + * **MUST** be used after `where()`. + * + * ####NOTE: + * + * As of Mongoose 3.7, `$geoWithin` is always used for queries. To change this behavior, see [Query.use$geoWithin](#query_Query-use%2524geoWithin). + * + * ####NOTE: + * + * In Mongoose 3.7, `within` changed from a getter to a function. If you need the old syntax, use [this](https://github.com/ebensing/mongoose-within). + * + * @method within + * @see $polygon http://docs.mongodb.org/manual/reference/operator/polygon/ + * @see $box http://docs.mongodb.org/manual/reference/operator/box/ + * @see $geometry http://docs.mongodb.org/manual/reference/operator/geometry/ + * @see $center http://docs.mongodb.org/manual/reference/operator/center/ + * @see $centerSphere http://docs.mongodb.org/manual/reference/operator/centerSphere/ + * @memberOf Query + * @return {Query} this + * @api public + */ + +/** + * Specifies a $slice projection for an array. + * + * ####Example + * + * query.slice('comments', 5) + * query.slice('comments', -5) + * query.slice('comments', [10, 5]) + * query.where('comments').slice(5) + * query.where('comments').slice([-10, 5]) + * + * @method slice + * @memberOf Query + * @param {String} [path] + * @param {Number} val number/range of elements to slice + * @return {Query} this + * @see mongodb http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields#RetrievingaSubsetofFields-RetrievingaSubrangeofArrayElements + * @see $slice http://docs.mongodb.org/manual/reference/projection/slice/#prj._S_slice + * @api public + */ + +/** + * Specifies the maximum number of documents the query will return. + * + * ####Example + * + * query.limit(20) + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @method limit + * @memberOf Query + * @param {Number} val + * @api public + */ + +/** + * Specifies the number of documents to skip. + * + * ####Example + * + * query.skip(100).limit(20) + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @method skip + * @memberOf Query + * @param {Number} val + * @see cursor.skip http://docs.mongodb.org/manual/reference/method/cursor.skip/ + * @api public + */ + +/** + * Specifies the maxScan option. + * + * ####Example + * + * query.maxScan(100) + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @method maxScan + * @memberOf Query + * @param {Number} val + * @see maxScan http://docs.mongodb.org/manual/reference/operator/maxScan/ + * @api public + */ + +/** + * Specifies the batchSize option. + * + * ####Example + * + * query.batchSize(100) + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @method batchSize + * @memberOf Query + * @param {Number} val + * @see batchSize http://docs.mongodb.org/manual/reference/method/cursor.batchSize/ + * @api public + */ + +/** + * Specifies the `comment` option. + * + * ####Example + * + * query.comment('login query') + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @method comment + * @memberOf Query + * @param {Number} val + * @see comment http://docs.mongodb.org/manual/reference/operator/comment/ + * @api public + */ + +/** + * Specifies this query as a `snapshot` query. + * + * ####Example + * + * query.snapshot() // true + * query.snapshot(true) + * query.snapshot(false) + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @method snapshot + * @memberOf Query + * @see snapshot http://docs.mongodb.org/manual/reference/operator/snapshot/ + * @return {Query} this + * @api public + */ + +/** + * Sets query hints. + * + * ####Example + * + * query.hint({ indexA: 1, indexB: -1}) + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @method hint + * @memberOf Query + * @param {Object} val a hint object + * @return {Query} this + * @see $hint http://docs.mongodb.org/manual/reference/operator/hint/ + * @api public + */ + +/** + * Specifies which document fields to include or exclude + * + * When using string syntax, prefixing a path with `-` will flag that path as excluded. When a path does not have the `-` prefix, it is included. Lastly, if a path is prefixed with `+`, it forces inclusion of the path, which is useful for paths excluded at the [schema level](/docs/api.html#schematype_SchemaType-select). + * + * ####Example + * + * // include a and b, exclude c + * query.select('a b -c'); + * + * // or you may use object notation, useful when + * // you have keys already prefixed with a "-" + * query.select({a: 1, b: 1, c: 0}); + * + * // force inclusion of field excluded at schema level + * query.select('+path') + * + * ####NOTE: + * + * Cannot be used with `distinct()`. + * + * _v2 had slightly different syntax such as allowing arrays of field names. This support was removed in v3._ + * + * @method select + * @memberOf Query + * @param {Object|String} arg + * @return {Query} this + * @see SchemaType + * @api public + */ + +/** + * _DEPRECATED_ Sets the slaveOk option. + * + * **Deprecated** in MongoDB 2.2 in favor of [read preferences](#query_Query-read). + * + * ####Example: + * + * query.slaveOk() // true + * query.slaveOk(true) + * query.slaveOk(false) + * + * @method slaveOk + * @memberOf Query + * @deprecated use read() preferences instead if on mongodb >= 2.2 + * @param {Boolean} v defaults to true + * @see mongodb http://docs.mongodb.org/manual/applications/replication/#read-preference + * @see slaveOk http://docs.mongodb.org/manual/reference/method/rs.slaveOk/ + * @see read() #query_Query-read + * @return {Query} this + * @api public + */ + +/** + * Determines the MongoDB nodes from which to read. + * + * ####Preferences: + * + * primary - (default) Read from primary only. Operations will produce an error if primary is unavailable. Cannot be combined with tags. + * secondary Read from secondary if available, otherwise error. + * primaryPreferred Read from primary if available, otherwise a secondary. + * secondaryPreferred Read from a secondary if available, otherwise read from the primary. + * nearest All operations read from among the nearest candidates, but unlike other modes, this option will include both the primary and all secondaries in the random selection. + * + * Aliases + * + * p primary + * pp primaryPreferred + * s secondary + * sp secondaryPreferred + * n nearest + * + * ####Example: + * + * new Query().read('primary') + * new Query().read('p') // same as primary + * + * new Query().read('primaryPreferred') + * new Query().read('pp') // same as primaryPreferred + * + * new Query().read('secondary') + * new Query().read('s') // same as secondary + * + * new Query().read('secondaryPreferred') + * new Query().read('sp') // same as secondaryPreferred + * + * new Query().read('nearest') + * new Query().read('n') // same as nearest + * + * // read from secondaries with matching tags + * new Query().read('s', [{ dc:'sf', s: 1 },{ dc:'ma', s: 2 }]) + * + * Read more about how to use read preferrences [here](http://docs.mongodb.org/manual/applications/replication/#read-preference) and [here](http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences). + * + * @method read + * @memberOf Query + * @param {String} pref one of the listed preference options or aliases + * @param {Array} [tags] optional tags for this query + * @see mongodb http://docs.mongodb.org/manual/applications/replication/#read-preference + * @see driver http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences + * @return {Query} this + * @api public + */ + +/** + * Merges another Query or conditions object into this one. + * + * When a Query is passed, conditions, field selection and options are merged. + * + * New in 3.7.0 + * + * @method merge + * @memberOf Query + * @param {Query|Object} source + * @return {Query} this + */ + +/** + * Sets query options. + * + * ####Options: + * + * - [tailable](http://www.mongodb.org/display/DOCS/Tailable+Cursors) * + * - [sort](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bsort(\)%7D%7D) * + * - [limit](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Blimit%28%29%7D%7D) * + * - [skip](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bskip%28%29%7D%7D) * + * - [maxscan](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24maxScan) * + * - [batchSize](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7BbatchSize%28%29%7D%7D) * + * - [comment](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24comment) * + * - [snapshot](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bsnapshot%28%29%7D%7D) * + * - [hint](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24hint) * + * - [slaveOk](http://docs.mongodb.org/manual/applications/replication/#read-preference) * + * - [lean](./api.html#query_Query-lean) * + * - [safe](http://www.mongodb.org/display/DOCS/getLastError+Command) + * + * _* denotes a query helper method is also available_ + * + * @param {Object} options + * @api public + */ + +Query.prototype.setOptions = function (options, overwrite) { + // overwrite is only for internal use + if (overwrite) { + // ensure that _mongooseOptions & options are two different objects + this._mongooseOptions = (options && utils.clone(options)) || {}; + this.options = options || {}; + + if('populate' in options) { + this.populate(this._mongooseOptions); + } + return this; + } + + if (!(options && 'Object' == options.constructor.name)) { + return this; + } + + return Query.base.setOptions.call(this, options); +} + +/** + * Returns fields selection for this query. + * + * @method _fieldsForExec + * @return {Object} + * @api private + */ + +/** + * Return an update document with corrected $set operations. + * + * @method _updateForExec + * @api private + */ + +/** + * Makes sure _path is set. + * + * @method _ensurePath + * @param {String} method + * @api private + */ + +/** + * Determines if `conds` can be merged using `mquery().merge()` + * + * @method canMerge + * @memberOf Query + * @param {Object} conds + * @return {Boolean} + * @api private + */ + +/** + * Returns default options for this query. + * + * @param {Model} model + * @api private + */ + +Query.prototype._optionsForExec = function (model) { + var options = Query.base._optionsForExec.call(this); + + delete options.populate; + + if (!model) { + return options; + } else { + if (!('safe' in options) && model.schema.options.safe) { + options.safe = model.schema.options.safe; + } + + if(!('readPreference' in options) && model.schema.options.read) { + options.readPreference = model.schema.options.read; + } + + return options; + } +}; + +/** + * Sets the lean option. + * + * Documents returned from queries with the `lean` option enabled are plain javascript objects, not [MongooseDocuments](#document-js). They have no `save` method, getters/setters or other Mongoose magic applied. + * + * ####Example: + * + * new Query().lean() // true + * new Query().lean(true) + * new Query().lean(false) + * + * Model.find().lean().exec(function (err, docs) { + * docs[0] instanceof mongoose.Document // false + * }); + * + * This is a [great](https://groups.google.com/forum/#!topic/mongoose-orm/u2_DzDydcnA/discussion) option in high-performance read-only scenarios, especially when combined with [stream](#query_Query-stream). + * + * @param {Boolean} bool defaults to true + * @return {Query} this + * @api public + */ + +Query.prototype.lean = function (v) { + this._mongooseOptions.lean = arguments.length ? !!v : true; + return this; +} + +/** + * Finds documents. + * + * When no `callback` is passed, the query is not executed. + * + * ####Example + * + * query.find({ name: 'Los Pollos Hermanos' }).find(callback) + * + * @param {Object} [criteria] mongodb selector + * @param {Function} [callback] + * @return {Query} this + * @api public + */ + +Query.prototype.find = function (conditions, callback) { + if ('function' == typeof conditions) { + callback = conditions; + conditions = {}; + } else if (conditions instanceof Document) { + conditions = conditions.toObject(); + } + + if (mquery.canMerge(conditions)) { + this.merge(conditions); + } + + prepareDiscriminatorCriteria(this); + + try { + this.cast(this.model); + this._castError = null; + } catch (err) { + this._castError = err; + } + + // if we don't have a callback, then just return the query object + if (!callback) { + return Query.base.find.call(this); + } + + var promise = new Promise(callback); + if (this._castError) { + promise.error(this._castError); + return this; + } + + this._applyPaths(); + this._fields = this._castFields(this._fields); + + var fields = this._fieldsForExec(); + var options = this._mongooseOptions; + var self = this; + + return Query.base.find.call(this, {}, cb); + + function cb(err, docs) { + if (err) return promise.error(err); + + if (0 === docs.length) { + return promise.complete(docs); + } + + if (!options.populate) { + return true === options.lean + ? promise.complete(docs) + : completeMany(self.model, docs, fields, self, null, promise); + } + + var pop = helpers.preparePopulationOptionsMQ(self, options); + self.model.populate(docs, pop, function (err, docs) { + if(err) return promise.error(err); + return true === options.lean + ? promise.complete(docs) + : completeMany(self.model, docs, fields, self, pop, promise); + }); + } +} + +/*! + * hydrates many documents + * + * @param {Model} model + * @param {Array} docs + * @param {Object} fields + * @param {Query} self + * @param {Array} [pop] array of paths used in population + * @param {Promise} promise + */ + +function completeMany (model, docs, fields, self, pop, promise) { + var arr = []; + var count = docs.length; + var len = count; + var opts = pop ? + { populated: pop } + : undefined; + for (var i=0; i < len; ++i) { + arr[i] = createModel(model, docs[i], fields); + arr[i].init(docs[i], opts, function (err) { + if (err) return promise.error(err); + --count || promise.complete(arr); + }); + } +} + +/*! + * If the document is a mapped discriminator type, it returns a model instance for that type, otherwise, + * it returns an instance of the given model. + * + * @param {Model} model + * @param {Object} doc + * @param {Object} fields + * + * @return {Model} + */ +function createModel(model, doc, fields) { + var discriminatorMapping = model.schema + ? model.schema.discriminatorMapping + : null; + + var key = discriminatorMapping && discriminatorMapping.isRoot + ? discriminatorMapping.key + : null; + + if (key && doc[key] && model.discriminators && model.discriminators[doc[key]]) { + return new model.discriminators[doc[key]](undefined, fields, true); + } + + return new model(undefined, fields, true); +} + +/** + * Declares the query a findOne operation. When executed, the first found document is passed to the callback. + * + * Passing a `callback` executes the query. + * + * ####Example + * + * var query = Kitten.where({ color: 'white' }); + * query.findOne(function (err, kitten) { + * if (err) return handleError(err); + * if (kitten) { + * // doc may be null if no document matched + * } + * }); + * + * @param {Object|Query} [criteria] mongodb selector + * @param {Function} [callback] + * @return {Query} this + * @see findOne http://docs.mongodb.org/manual/reference/method/db.collection.findOne/ + * @api public + */ + +Query.prototype.findOne = function (conditions, fields, options, callback) { + if ('function' == typeof conditions) { + callback = conditions; + conditions = null; + fields = null; + options = null; + } + + if ('function' == typeof fields) { + callback = fields; + options = null; + fields = null; + } + + if ('function' == typeof options) { + callback = options; + options = null; + } + + // make sure we don't send in the whole Document to merge() + if (conditions instanceof Document) { + conditions = conditions.toObject(); + } + + if (options) { + this.setOptions(options); + } + + if (fields) { + this.select(fields); + } + + if (mquery.canMerge(conditions)) { + this.merge(conditions); + } + + prepareDiscriminatorCriteria(this); + + try { + this.cast(this.model); + this._castError = null; + } catch (err) { + this._castError = err; + } + + if (!callback) { + // already merged in the conditions, don't need to send them in. + return Query.base.findOne.call(this); + } + + var promise = new Promise(callback); + + if (this._castError) { + promise.error(this._castError); + return this; + } + + this._applyPaths(); + this._fields = this._castFields(this._fields); + + var options = this._mongooseOptions; + var fields = this._fieldsForExec(); + var self = this; + + // don't pass in the conditions because we already merged them in + Query.base.findOne.call(this, {}, function cb (err, doc) { + if (err) return promise.error(err); + if (!doc) return promise.complete(null); + + if (!options.populate) { + return true === options.lean + ? promise.complete(doc) + : completeOne(self.model, doc, fields, self, null, promise); + } + + var pop = helpers.preparePopulationOptionsMQ(self, options); + self.model.populate(doc, pop, function (err, doc) { + if (err) return promise.error(err); + + return true === options.lean + ? promise.complete(doc) + : completeOne(self.model, doc, fields, self, pop, promise); + }); + }) + + return this; +} + +/** + * Specifying this query as a `count` query. + * + * Passing a `callback` executes the query. + * + * ####Example: + * + * var countQuery = model.where({ 'color': 'black' }).count(); + * + * query.count({ color: 'black' }).count(callback) + * + * query.count({ color: 'black' }, callback) + * + * query.where('color', 'black').count(function (err, count) { + * if (err) return handleError(err); + * console.log('there are %d kittens', count); + * }) + * + * @param {Object} [criteria] mongodb selector + * @param {Function} [callback] + * @return {Query} this + * @see count http://docs.mongodb.org/manual/reference/method/db.collection.count/ + * @api public + */ + +Query.prototype.count = function (conditions, callback) { + if ('function' == typeof conditions) { + callback = conditions; + conditions = undefined; + } + + if (mquery.canMerge(conditions)) { + this.merge(conditions); + } + + try { + this.cast(this.model); + } catch (err) { + callback(err); + return this; + } + + return Query.base.count.call(this, {}, callback); +} + +/** + * Declares or executes a distict() operation. + * + * Passing a `callback` executes the query. + * + * ####Example + * + * distinct(criteria, field, fn) + * distinct(criteria, field) + * distinct(field, fn) + * distinct(field) + * distinct(fn) + * distinct() + * + * @param {Object|Query} [criteria] + * @param {String} [field] + * @param {Function} [callback] + * @return {Query} this + * @see distinct http://docs.mongodb.org/manual/reference/method/db.collection.distinct/ + * @api public + */ + +Query.prototype.distinct = function (conditions, field, callback) { + if (!callback) { + if('function' == typeof field) { + callback = field; + if ('string' == typeof conditions) { + field = conditions; + conditions = undefined; + } + } + + switch (typeof conditions) { + case 'string': + field = conditions; + conditions = undefined; + break; + case 'function': + callback = conditions; + field = undefined; + conditions = undefined; + break; + } + } + + if (conditions instanceof Document) { + conditions = conditions.toObject(); + } + + if (mquery.canMerge(conditions)) { + this.merge(conditions) + } + + try { + this.cast(this.model); + } catch (err) { + callback(err); + return this; + } + + return Query.base.distinct.call(this, {}, field, callback); +} + +/** + * Sets the sort order + * + * If an object is passed, values allowed are `asc`, `desc`, `ascending`, `descending`, `1`, and `-1`. + * + * If a string is passed, it must be a space delimited list of path names. The + * sort order of each path is ascending unless the path name is prefixed with `-` + * which will be treated as descending. + * + * ####Example + * + * // sort by "field" ascending and "test" descending + * query.sort({ field: 'asc', test: -1 }); + * + * // equivalent + * query.sort('field -test'); + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @param {Object|String} arg + * @return {Query} this + * @see cursor.sort http://docs.mongodb.org/manual/reference/method/cursor.sort/ + * @api public + */ + +Query.prototype.sort = function (arg) { + var nArg = {}; + + if (arguments.length > 1) { + throw new Error("sort() only takes 1 Argument"); + } + + if (Array.isArray(arg)) { + // time to deal with the terrible syntax + for (var i=0; i < arg.length; i++) { + if (!Array.isArray(arg[i])) throw new Error("Invalid sort() argument."); + nArg[arg[i][0]] = arg[i][1]; + } + + } else { + nArg = arg; + } + + return Query.base.sort.call(this, nArg); +} + +/** + * Declare and/or execute this query as a remove() operation. + * + * ####Example + * + * Model.remove({ artist: 'Anne Murray' }, callback) + * + * ####Note + * + * The operation is only executed when a callback is passed. To force execution without a callback (which would be an unsafe write), we must first call remove() and then execute it by using the `exec()` method. + * + * // not executed + * var query = Model.find().remove({ name: 'Anne Murray' }) + * + * // executed + * query.remove({ name: 'Anne Murray' }, callback) + * query.remove({ name: 'Anne Murray' }).remove(callback) + * + * // executed without a callback (unsafe write) + * query.exec() + * + * // summary + * query.remove(conds, fn); // executes + * query.remove(conds) + * query.remove(fn) // executes + * query.remove() + * + * @param {Object|Query} [criteria] mongodb selector + * @param {Function} [callback] + * @return {Query} this + * @see remove http://docs.mongodb.org/manual/reference/method/db.collection.remove/ + * @api public + */ + +Query.prototype.remove = function (cond, callback) { + if ('function' == typeof cond) { + callback = cond; + cond = null; + } + + var cb = 'function' == typeof callback; + + try { + this.cast(this.model); + } catch (err) { + if (cb) return process.nextTick(callback.bind(null, err)); + return this; + } + + return Query.base.remove.call(this, cond, callback); +} + +/*! + * hydrates a document + * + * @param {Model} model + * @param {Document} doc + * @param {Object} fields + * @param {Query} self + * @param {Array} [pop] array of paths used in population + * @param {Promise} promise + */ + +function completeOne (model, doc, fields, self, pop, promise) { + var opts = pop ? + { populated: pop } + : undefined; + + var casted = createModel(model, doc, fields) + casted.init(doc, opts, function (err) { + if (err) return promise.error(err); + promise.complete(casted); + }); +} + +/*! + * If the model is a discriminator type and not root, then add the key & value to the criteria. + */ + +function prepareDiscriminatorCriteria(query) { + if (!query || !query.model || !query.model.schema) { + return; + } + + var schema = query.model.schema; + + if (schema && schema.discriminatorMapping && !schema.discriminatorMapping.isRoot) { + query._conditions[schema.discriminatorMapping.key] = schema.discriminatorMapping.value; + } +} + +/** + * Issues a mongodb [findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) update command. + * + * Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes immediately if `callback` is passed. + * + * ####Available options + * + * - `new`: bool - true to return the modified document rather than the original. defaults to true + * - `upsert`: bool - creates the object if it doesn't exist. defaults to false. + * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update + * + * ####Examples + * + * query.findOneAndUpdate(conditions, update, options, callback) // executes + * query.findOneAndUpdate(conditions, update, options) // returns Query + * query.findOneAndUpdate(conditions, update, callback) // executes + * query.findOneAndUpdate(conditions, update) // returns Query + * query.findOneAndUpdate(update, callback) // returns Query + * query.findOneAndUpdate(update) // returns Query + * query.findOneAndUpdate(callback) // executes + * query.findOneAndUpdate() // returns Query + * + * @method findOneAndUpdate + * @memberOf Query + * @param {Object|Query} [query] + * @param {Object} [doc] + * @param {Object} [options] + * @param {Function} [callback] + * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command + * @return {Query} this + * @api public + */ + +/** + * Issues a mongodb [findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) remove command. + * + * Finds a matching document, removes it, passing the found document (if any) to the callback. Executes immediately if `callback` is passed. + * + * ####Available options + * + * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update + * + * ####Examples + * + * A.where().findOneAndRemove(conditions, options, callback) // executes + * A.where().findOneAndRemove(conditions, options) // return Query + * A.where().findOneAndRemove(conditions, callback) // executes + * A.where().findOneAndRemove(conditions) // returns Query + * A.where().findOneAndRemove(callback) // executes + * A.where().findOneAndRemove() // returns Query + * + * @method findOneAndRemove + * @memberOf Query + * @param {Object} [conditions] + * @param {Object} [options] + * @param {Function} [callback] + * @return {Query} this + * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command + * @api public + */ + +/** + * Override mquery.prototype._findAndModify to provide casting etc. + * + * @param {String} type - either "remove" or "update" + * @param {Function} callback + * @api private + */ + +Query.prototype._findAndModify = function (type, callback) { + if ('function' != typeof callback) { + throw new Error("Expected callback in _findAndModify"); + } + + var model = this.model + , promise = new Promise(callback) + , self = this + , castedQuery + , castedDoc + , fields + , opts; + + castedQuery = castQuery(this); + if (castedQuery instanceof Error) { + process.nextTick(promise.error.bind(promise, castedQuery)); + return promise; + } + + opts = this._optionsForExec(model); + + if ('remove' == type) { + opts.remove = true; + } else { + if (!('new' in opts)) opts.new = true; + if (!('upsert' in opts)) opts.upsert = false; + + castedDoc = castDoc(this); + if (!castedDoc) { + if (opts.upsert) { + // still need to do the upsert to empty doc + castedDoc = { $set: {} }; + } else { + return this.findOne(callback); + } + } else if (castedDoc instanceof Error) { + process.nextTick(promise.error.bind(promise, castedDoc)); + return promise; + } + } + + this._applyPaths(); + + var self = this; + var options = this._mongooseOptions; + + if (this._fields) { + fields = utils.clone(this._fields); + opts.fields = this._castFields(fields); + if (opts.fields instanceof Error) { + process.nextTick(promise.error.bind(promise, opts.fields)); + return promise; + } + } + + this._collection.findAndModify(castedQuery, castedDoc, opts, utils.tick(cb)); + function cb (err, doc) { + if (err) return promise.error(err); + + if (!doc || (utils.isObject(doc) && Object.keys(doc).length === 0)) { + return promise.complete(null); + } + + if (!options.populate) { + return true === options.lean + ? promise.complete(doc) + : completeOne(self.model, doc, fields, self, null, promise); + } + + var pop = helpers.preparePopulationOptionsMQ(self, options); + self.model.populate(doc, pop, function (err, doc) { + if (err) return promise.error(err); + + return true === options.lean + ? promise.complete(doc) + : completeOne(self.model, doc, fields, self, pop, promise); + }); + } + + return promise; +} + +/** + * Declare and/or execute this query as an update() operation. + * + * _All paths passed that are not $atomic operations will become $set ops._ + * + * ####Example + * + * Model.where({ _id: id }).update({ title: 'words' }) + * + * // becomes + * + * Model.where({ _id: id }).update({ $set: { title: 'words' }}) + * + * ####Note + * + * Passing an empty object `{}` as the doc will result in a no-op unless the `overwrite` option is passed. Without the `overwrite` option set, the update operation will be ignored and the callback executed without sending the command to MongoDB so as to prevent accidently overwritting documents in the collection. + * + * ####Note + * + * The operation is only executed when a callback is passed. To force execution without a callback (which would be an unsafe write), we must first call update() and then execute it by using the `exec()` method. + * + * var q = Model.where({ _id: id }); + * q.update({ $set: { name: 'bob' }}).update(); // not executed + * + * q.update({ $set: { name: 'bob' }}).exec(); // executed as unsafe + * + * // keys that are not $atomic ops become $set. + * // this executes the same command as the previous example. + * q.update({ name: 'bob' }).exec(); + * + * // overwriting with empty docs + * var q = Model.where({ _id: id }).setOptions({ overwrite: true }) + * q.update({ }, callback); // executes + * + * // multi update with overwrite to empty doc + * var q = Model.where({ _id: id }); + * q.setOptions({ multi: true, overwrite: true }) + * q.update({ }); + * q.update(callback); // executed + * + * // multi updates + * Model.where() + * .update({ name: /^match/ }, { $set: { arr: [] }}, { multi: true }, callback) + * + * // more multi updates + * Model.where() + * .setOptions({ multi: true }) + * .update({ $set: { arr: [] }}, callback) + * + * // single update by default + * Model.where({ email: 'address@example.com' }) + * .update({ $inc: { counter: 1 }}, callback) + * + * API summary + * + * update(criteria, doc, options, cb) // executes + * update(criteria, doc, options) + * update(criteria, doc, cb) // executes + * update(criteria, doc) + * update(doc, cb) // executes + * update(doc) + * update(cb) // executes + * update(true) // executes (unsafe write) + * update() + * + * @param {Object} [criteria] + * @param {Object} [doc] the update command + * @param {Object} [options] + * @param {Function} [callback] + * @return {Query} this + * @see Model.update http://localhost:8088/docs/api.html#model_Model.update + * @see update http://docs.mongodb.org/manual/reference/method/db.collection.update/ + * @api public + */ + +Query.prototype.update = function (conditions, doc, options, callback) { + if ('function' === typeof options) { + // Scenario: update(conditions, doc, callback) + callback = options; + options = null; + } else if ('function' === typeof doc) { + // Scenario: update(doc, callback); + callback = doc; + doc = conditions; + conditions = {}; + options = null; + } else if ('function' === typeof conditions) { + callback = conditions; + conditions = undefined; + doc = undefined; + options = undefined; + } + + // make sure we don't send in the whole Document to merge() + if (conditions instanceof Document) { + conditions = conditions.toObject(); + } + + // strict is an option used in the update checking, make sure it gets set + if (options) { + if ('strict' in options) { + this._mongooseOptions.strict = options.strict; + } + } + + // if doc is undefined at this point, this means this function is being + // executed by exec(not always see below). Grab the update doc from here in + // order to validate + // This could also be somebody calling update() or update({}). Probably not a + // common use case, check for _update to make sure we don't do anything bad + if (!doc && this._update) { + doc = this._updateForExec(); + } + + if (conditions) { + this._conditions = conditions; + } + + // validate the selector part of the query + var castedQuery = castQuery(this); + if (castedQuery instanceof Error) { + if(callback) { + callback(castedQuery); + return this; + } else { + throw castedQuery; + } + } + + // validate the update part of the query + var castedDoc; + try { + castedDoc = this._castUpdate(doc, options && options.overwrite); + } catch (err) { + if (callback) { + callback(err); + return this; + } else { + throw err; + } + } + + if (!castedDoc) { + callback && callback(null, 0); + return this; + } + + return Query.base.update.call(this, castedQuery, castedDoc, options, callback); +} + +/** + * Executes the query + * + * ####Examples: + * + * var promise = query.exec(); + * var promise = query.exec('update'); + * + * query.exec(callback); + * query.exec('find', callback); + * + * @param {String|Function} [operation] + * @param {Function} [callback] + * @return {Promise} + * @api public + */ + +Query.prototype.exec = function exec (op, callback) { + var promise = new Promise(); + + if ('function' == typeof op) { + callback = op; + op = null; + } else if ('string' == typeof op) { + this.op = op; + } + + if (callback) promise.addBack(callback); + + if (!this.op) { + promise.complete(); + return promise; + } + + Query.base.exec.call(this, op, promise.resolve.bind(promise)); + + return promise; +} + +/** + * Finds the schema for `path`. This is different than + * calling `schema.path` as it also resolves paths with + * positional selectors (something.$.another.$.path). + * + * @param {String} path + * @api private + */ + +Query.prototype._getSchema = function _getSchema (path) { + return this.model._getSchema(path); +} + +/*! + * These operators require casting docs + * to real Documents for Update operations. + */ + +var castOps = { + $push: 1 + , $pushAll: 1 + , $addToSet: 1 + , $set: 1 +}; + +/*! + * These operators should be cast to numbers instead + * of their path schema type. + */ + +var numberOps = { + $pop: 1 + , $unset: 1 + , $inc: 1 +} + +/** + * Casts obj for an update command. + * + * @param {Object} obj + * @return {Object} obj after casting its values + * @api private + */ + +Query.prototype._castUpdate = function _castUpdate (obj, overwrite) { + if (!obj) return undefined; + + var ops = Object.keys(obj) + , i = ops.length + , ret = {} + , hasKeys + , val + + while (i--) { + var op = ops[i]; + // if overwrite is set, don't do any of the special $set stuff + if ('$' !== op[0] && !overwrite) { + // fix up $set sugar + if (!ret.$set) { + if (obj.$set) { + ret.$set = obj.$set; + } else { + ret.$set = {}; + } + } + ret.$set[op] = obj[op]; + ops.splice(i, 1); + if (!~ops.indexOf('$set')) ops.push('$set'); + } else if ('$set' === op) { + if (!ret.$set) { + ret[op] = obj[op]; + } + } else { + ret[op] = obj[op]; + } + } + + // cast each value + i = ops.length; + + // if we get passed {} for the update, we still need to respect that when it + // is an overwrite scenario + if (overwrite) { + hasKeys = true; + } + + while (i--) { + op = ops[i]; + val = ret[op]; + if ('Object' === val.constructor.name && !overwrite) { + hasKeys |= this._walkUpdatePath(val, op); + } else if (overwrite && 'Object' === ret.constructor.name) { + // if we are just using overwrite, cast the query and then we will + // *always* return the value, even if it is an empty object. We need to + // set hasKeys above because we need to account for the case where the + // user passes {} and wants to clobber the whole document + // Also, _walkUpdatePath expects an operation, so give it $set since that + // is basically what we're doing + this._walkUpdatePath(ret, '$set'); + } else { + var msg = 'Invalid atomic update value for ' + op + '. ' + + 'Expected an object, received ' + typeof val; + throw new Error(msg); + } + } + + return hasKeys && ret; +} + +/** + * Walk each path of obj and cast its values + * according to its schema. + * + * @param {Object} obj - part of a query + * @param {String} op - the atomic operator ($pull, $set, etc) + * @param {String} pref - path prefix (internal only) + * @return {Bool} true if this path has keys to update + * @api private + */ + +Query.prototype._walkUpdatePath = function _walkUpdatePath (obj, op, pref) { + var prefix = pref ? pref + '.' : '' + , keys = Object.keys(obj) + , i = keys.length + , hasKeys = false + , schema + , key + , val + + var strict = 'strict' in this._mongooseOptions + ? this._mongooseOptions.strict + : this.model.schema.options.strict; + + while (i--) { + key = keys[i]; + val = obj[key]; + + if (val && 'Object' === val.constructor.name) { + // watch for embedded doc schemas + schema = this._getSchema(prefix + key); + if (schema && schema.caster && op in castOps) { + // embedded doc schema + + if (strict && !schema) { + // path is not in our strict schema + if ('throw' == strict) { + throw new Error('Field `' + key + '` is not in schema.'); + } else { + // ignore paths not specified in schema + delete obj[key]; + } + } else { + hasKeys = true; + + if ('$each' in val) { + obj[key] = { + $each: this._castUpdateVal(schema, val.$each, op) + } + + if (val.$slice) { + obj[key].$slice = val.$slice | 0; + } + + if (val.$sort) { + obj[key].$sort = val.$sort; + } + + } else { + obj[key] = this._castUpdateVal(schema, val, op); + } + } + } else { + hasKeys |= this._walkUpdatePath(val, op, prefix + key); + } + } else { + schema = '$each' === key + ? this._getSchema(pref) + : this._getSchema(prefix + key); + + var skip = strict && + !schema && + !/real|nested/.test(this.model.schema.pathType(prefix + key)); + + if (skip) { + if ('throw' == strict) { + throw new Error('Field `' + prefix + key + '` is not in schema.'); + } else { + delete obj[key]; + } + } else { + hasKeys = true; + obj[key] = this._castUpdateVal(schema, val, op, key); + } + } + } + return hasKeys; +} + +/** + * Casts `val` according to `schema` and atomic `op`. + * + * @param {Schema} schema + * @param {Object} val + * @param {String} op - the atomic operator ($pull, $set, etc) + * @param {String} [$conditional] + * @api private + */ + +Query.prototype._castUpdateVal = function _castUpdateVal (schema, val, op, $conditional) { + if (!schema) { + // non-existing schema path + return op in numberOps + ? Number(val) + : val + } + + if (schema.caster && op in castOps && + (utils.isObject(val) || Array.isArray(val))) { + // Cast values for ops that add data to MongoDB. + // Ensures embedded documents get ObjectIds etc. + var tmp = schema.cast(val); + + if (Array.isArray(val)) { + val = tmp; + } else { + val = tmp[0]; + } + } + + if (op in numberOps) return Number(val); + if (/^\$/.test($conditional)) return schema.castForQuery($conditional, val); + return schema.castForQuery(val) +} + +/*! + * castQuery + * @api private + */ + +function castQuery (query) { + try { + return query.cast(query.model); + } catch (err) { + return err; + } +} + +/*! + * castDoc + * @api private + */ + +function castDoc (query) { + try { + return query._castUpdate(query._update); + } catch (err) { + return err; + } +} + +/** + * Specifies paths which should be populated with other documents. + * + * ####Example: + * + * Kitten.findOne().populate('owner').exec(function (err, kitten) { + * console.log(kitten.owner.name) // Max + * }) + * + * Kitten.find().populate({ + * path: 'owner' + * , select: 'name' + * , match: { color: 'black' } + * , options: { sort: { name: -1 }} + * }).exec(function (err, kittens) { + * console.log(kittens[0].owner.name) // Zoopa + * }) + * + * // alternatively + * Kitten.find().populate('owner', 'name', null, {sort: { name: -1 }}).exec(function (err, kittens) { + * console.log(kittens[0].owner.name) // Zoopa + * }) + * + * Paths are populated after the query executes and a response is received. A separate query is then executed for each path specified for population. After a response for each query has also been returned, the results are passed to the callback. + * + * @param {Object|String} path either the path to populate or an object specifying all parameters + * @param {Object|String} [select] Field selection for the population query + * @param {Model} [model] The name of the model you wish to use for population. If not specified, the name is looked up from the Schema ref. + * @param {Object} [match] Conditions for the population query + * @param {Object} [options] Options for the population query (sort, etc) + * @see population ./populate.html + * @see Query#select #query_Query-select + * @see Model.populate #model_Model.populate + * @return {Query} this + * @api public + */ + +Query.prototype.populate = function () { + var res = utils.populate.apply(null, arguments); + var opts = this._mongooseOptions; + + if (!utils.isObject(opts.populate)) { + opts.populate = {}; + } + + for (var i = 0; i < res.length; ++i) { + opts.populate[res[i].path] = res[i]; + } + + return this; +} + +/** + * Casts this query to the schema of `model` + * + * ####Note + * + * If `obj` is present, it is cast instead of this query. + * + * @param {Model} model + * @param {Object} [obj] + * @return {Object} + * @api public + */ + +Query.prototype.cast = function (model, obj) { + obj || (obj = this._conditions); + + var schema = model.schema + , paths = Object.keys(obj) + , i = paths.length + , any$conditionals + , schematype + , nested + , path + , type + , val; + + while (i--) { + path = paths[i]; + val = obj[path]; + + if ('$or' === path || '$nor' === path || '$and' === path) { + var k = val.length + , orComponentQuery; + + while (k--) { + orComponentQuery = new Query(val[k], {}, null, this.mongooseCollection); + orComponentQuery.cast(model); + val[k] = orComponentQuery._conditions; + } + + } else if (path === '$where') { + type = typeof val; + + if ('string' !== type && 'function' !== type) { + throw new Error("Must have a string or function for $where"); + } + + if ('function' === type) { + obj[path] = val.toString(); + } + + continue; + + } else { + + if (!schema) { + // no casting for Mixed types + continue; + } + + schematype = schema.path(path); + + if (!schematype) { + // Handle potential embedded array queries + var split = path.split('.') + , j = split.length + , pathFirstHalf + , pathLastHalf + , remainingConds + , castingQuery; + + // Find the part of the var path that is a path of the Schema + while (j--) { + pathFirstHalf = split.slice(0, j).join('.'); + schematype = schema.path(pathFirstHalf); + if (schematype) break; + } + + // If a substring of the input path resolves to an actual real path... + if (schematype) { + // Apply the casting; similar code for $elemMatch in schema/array.js + if (schematype.caster && schematype.caster.schema) { + remainingConds = {}; + pathLastHalf = split.slice(j).join('.'); + remainingConds[pathLastHalf] = val; + castingQuery = new Query(remainingConds, {}, null, this.mongooseCollection); + castingQuery.cast(schematype.caster); + obj[path] = castingQuery._conditions[pathLastHalf]; + } else { + obj[path] = val; + } + continue; + } + + if (utils.isObject(val)) { + // handle geo schemas that use object notation + // { loc: { long: Number, lat: Number } + + var geo = val.$near ? '$near' : + val.$nearSphere ? '$nearSphere' : + val.$within ? '$within' : + val.$geoIntersects ? '$geoIntersects' : ''; + + if (!geo) { + continue; + } + + var numbertype = new Types.Number('__QueryCasting__') + var value = val[geo]; + + if (val.$maxDistance) { + val.$maxDistance = numbertype.castForQuery(val.$maxDistance); + } + + if ('$within' == geo) { + var withinType = value.$center + || value.$centerSphere + || value.$box + || value.$polygon; + + if (!withinType) { + throw new Error('Bad $within paramater: ' + JSON.stringify(val)); + } + + value = withinType; + + } else if ('$near' == geo && + 'string' == typeof value.type && Array.isArray(value.coordinates)) { + // geojson; cast the coordinates + value = value.coordinates; + + } else if (('$near' == geo || '$geoIntersects' == geo) && + value.$geometry && 'string' == typeof value.$geometry.type && + Array.isArray(value.$geometry.coordinates)) { + // geojson; cast the coordinates + value = value.$geometry.coordinates; + } + + ;(function _cast (val) { + if (Array.isArray(val)) { + val.forEach(function (item, i) { + if (Array.isArray(item) || utils.isObject(item)) { + return _cast(item); + } + val[i] = numbertype.castForQuery(item); + }); + } else { + var nearKeys= Object.keys(val); + var nearLen = nearKeys.length; + while (nearLen--) { + var nkey = nearKeys[nearLen]; + var item = val[nkey]; + if (Array.isArray(item) || utils.isObject(item)) { + _cast(item); + val[nkey] = item; + } else { + val[nkey] = numbertype.castForQuery(item); + } + } + } + })(value); + } + + } else if (val === null || val === undefined) { + continue; + } else if ('Object' === val.constructor.name) { + + any$conditionals = Object.keys(val).some(function (k) { + return k.charAt(0) === '$' && k !== '$id' && k !== '$ref'; + }); + + if (!any$conditionals) { + obj[path] = schematype.castForQuery(val); + } else { + + var ks = Object.keys(val) + , k = ks.length + , $cond; + + while (k--) { + $cond = ks[k]; + nested = val[$cond]; + + if ('$exists' === $cond) { + if ('boolean' !== typeof nested) { + throw new Error("$exists parameter must be Boolean"); + } + continue; + } + + if ('$type' === $cond) { + if ('number' !== typeof nested) { + throw new Error("$type parameter must be Number"); + } + continue; + } + + if ('$not' === $cond) { + this.cast(model, nested); + } else { + val[$cond] = schematype.castForQuery($cond, nested); + } + } + } + } else { + obj[path] = schematype.castForQuery(val); + } + } + } + + return obj; +} + +/** + * Casts selected field arguments for field selection with mongo 2.2 + * + * query.select({ ids: { $elemMatch: { $in: [hexString] }}) + * + * @param {Object} fields + * @see https://github.com/LearnBoost/mongoose/issues/1091 + * @see http://docs.mongodb.org/manual/reference/projection/elemMatch/ + * @api private + */ + +Query.prototype._castFields = function _castFields (fields) { + var selected + , elemMatchKeys + , keys + , key + , out + , i + + if (fields) { + keys = Object.keys(fields); + elemMatchKeys = []; + i = keys.length; + + // collect $elemMatch args + while (i--) { + key = keys[i]; + if (fields[key].$elemMatch) { + selected || (selected = {}); + selected[key] = fields[key]; + elemMatchKeys.push(key); + } + } + } + + if (selected) { + // they passed $elemMatch, cast em + try { + out = this.cast(this.model, selected); + } catch (err) { + return err; + } + + // apply the casted field args + i = elemMatchKeys.length; + while (i--) { + key = elemMatchKeys[i]; + fields[key] = out[key]; + } + } + + return fields; +} + +/** + * Applies schematype selected options to this query. + * @api private + */ + +Query.prototype._applyPaths = function applyPaths () { + // determine if query is selecting or excluding fields + + var fields = this._fields + , exclude + , keys + , ki + + if (fields) { + keys = Object.keys(fields); + ki = keys.length; + + while (ki--) { + if ('+' == keys[ki][0]) continue; + exclude = 0 === fields[keys[ki]]; + break; + } + } + + // if selecting, apply default schematype select:true fields + // if excluding, apply schematype select:false fields + + var selected = [] + , excluded = [] + , seen = []; + + analyzeSchema(this.model.schema); + + switch (exclude) { + case true: + excluded.length && this.select('-' + excluded.join(' -')); + break; + case false: + selected.length && this.select(selected.join(' ')); + break; + case undefined: + // user didn't specify fields, implies returning all fields. + // only need to apply excluded fields + excluded.length && this.select('-' + excluded.join(' -')); + break; + } + + return seen = excluded = selected = keys = fields = null; + + function analyzeSchema (schema, prefix) { + prefix || (prefix = ''); + + // avoid recursion + if (~seen.indexOf(schema)) return; + seen.push(schema); + + schema.eachPath(function (path, type) { + if (prefix) path = prefix + '.' + path; + + analyzePath(path, type); + + // array of subdocs? + if (type.schema) { + analyzeSchema(type.schema, path); + } + + }); + } + + function analyzePath (path, type) { + if ('boolean' != typeof type.selected) return; + + var plusPath = '+' + path; + if (fields && plusPath in fields) { + // forced inclusion + delete fields[plusPath]; + + // if there are other fields being included, add this one + // if no other included fields, leave this out (implied inclusion) + if (false === exclude && keys.length > 1 && !~keys.indexOf(path)) { + fields[path] = 1; + } + + return + }; + + // check for parent exclusions + var root = path.split('.')[0]; + if (~excluded.indexOf(root)) return; + + ;(type.selected ? selected : excluded).push(path); + } +} + +/** + * Casts selected field arguments for field selection with mongo 2.2 + * + * query.select({ ids: { $elemMatch: { $in: [hexString] }}) + * + * @param {Object} fields + * @see https://github.com/LearnBoost/mongoose/issues/1091 + * @see http://docs.mongodb.org/manual/reference/projection/elemMatch/ + * @api private + */ + +Query.prototype._castFields = function _castFields (fields) { + var selected + , elemMatchKeys + , keys + , key + , out + , i + + if (fields) { + keys = Object.keys(fields); + elemMatchKeys = []; + i = keys.length; + + // collect $elemMatch args + while (i--) { + key = keys[i]; + if (fields[key].$elemMatch) { + selected || (selected = {}); + selected[key] = fields[key]; + elemMatchKeys.push(key); + } + } + } + + if (selected) { + // they passed $elemMatch, cast em + try { + out = this.cast(this.model, selected); + } catch (err) { + return err; + } + + // apply the casted field args + i = elemMatchKeys.length; + while (i--) { + key = elemMatchKeys[i]; + fields[key] = out[key]; + } + } + + return fields; +} + +/** + * Returns a Node.js 0.8 style [read stream](http://nodejs.org/docs/v0.8.21/api/stream.html#stream_readable_stream) interface. + * + * ####Example + * + * // follows the nodejs 0.8 stream api + * Thing.find({ name: /^hello/ }).stream().pipe(res) + * + * // manual streaming + * var stream = Thing.find({ name: /^hello/ }).stream(); + * + * stream.on('data', function (doc) { + * // do something with the mongoose document + * }).on('error', function (err) { + * // handle the error + * }).on('close', function () { + * // the stream is closed + * }); + * + * ####Valid options + * + * - `transform`: optional function which accepts a mongoose document. The return value of the function will be emitted on `data`. + * + * ####Example + * + * // JSON.stringify all documents before emitting + * var stream = Thing.find().stream({ transform: JSON.stringify }); + * stream.pipe(writeStream); + * + * @return {QueryStream} + * @param {Object} [options] + * @see QueryStream + * @api public + */ + +Query.prototype.stream = function stream (opts) { + return new QueryStream(this, opts); +} + +// the rest of these are basically to support older Mongoose syntax with mquery + +/** + * _DEPRECATED_ Alias of `maxScan` + * + * @deprecated + * @see maxScan #query_Query-maxScan + * @method maxscan + * @memberOf Query + */ + +Query.prototype.maxscan = Query.base.maxScan; + +/** + * Sets the tailable option (for use with capped collections). + * + * ####Example + * + * query.tailable() // true + * query.tailable(true) + * query.tailable(false) + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @param {Boolean} bool defaults to true + * @see tailable http://docs.mongodb.org/manual/tutorial/create-tailable-cursor/ + * @api public + */ + +Query.prototype.tailable = function (val, opts) { + // we need to support the tailable({ awaitdata : true }) as well as the + // tailable(true, {awaitdata :true}) syntax that mquery does not support + if (val && val.constructor.name == 'Object') { + opts = val; + val = true; + } + + if (val === undefined) { + val = true; + } + + if (opts && opts.awaitdata) this.options.awaitdata = true; + return Query.base.tailable.call(this, val); +} + +/** + * Declares an intersects query for `geometry()`. + * + * ####Example + * + * query.where('path').intersects().geometry({ + * type: 'LineString' + * , coordinates: [[180.0, 11.0], [180, 9.0]] + * }) + * + * query.where('path').intersects({ + * type: 'LineString' + * , coordinates: [[180.0, 11.0], [180, 9.0]] + * }) + * + * ####NOTE: + * + * **MUST** be used after `where()`. + * + * ####NOTE: + * + * In Mongoose 3.7, `intersects` changed from a getter to a function. If you need the old syntax, use [this](https://github.com/ebensing/mongoose-within). + * + * @method intersects + * @memberOf Query + * @param {Object} [arg] + * @return {Query} this + * @see $geometry http://docs.mongodb.org/manual/reference/operator/geometry/ + * @see geoIntersects http://docs.mongodb.org/manual/reference/operator/geoIntersects/ + * @api public + */ + +/** + * Specifies a `$geometry` condition + * + * ####Example + * + * var polyA = [[[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]] + * query.where('loc').within().geometry({ type: 'Polygon', coordinates: polyA }) + * + * // or + * var polyB = [[ 0, 0 ], [ 1, 1 ]] + * query.where('loc').within().geometry({ type: 'LineString', coordinates: polyB }) + * + * // or + * var polyC = [ 0, 0 ] + * query.where('loc').within().geometry({ type: 'Point', coordinates: polyC }) + * + * // or + * query.where('loc').intersects().geometry({ type: 'Point', coordinates: polyC }) + * + * The argument is assigned to the most recent path passed to `where()`. + * + * ####NOTE: + * + * `geometry()` **must** come after either `intersects()` or `within()`. + * + * The `object` argument must contain `type` and `coordinates` properties. + * - type {String} + * - coordinates {Array} + * + * @method geometry + * @memberOf Query + * @param {Object} object Must contain a `type` property which is a String and a `coordinates` property which is an Array. See the examples. + * @return {Query} this + * @see $geometry http://docs.mongodb.org/manual/reference/operator/geometry/ + * @see http://docs.mongodb.org/manual/release-notes/2.4/#new-geospatial-indexes-with-geojson-and-improved-spherical-geometry + * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing + * @api public + */ + +/** + * Specifies a `$near` or `$nearSphere` condition + * + * These operators return documents sorted by distance. + * + * ####Example + * + * query.where('loc').near({ center: [10, 10] }); + * query.where('loc').near({ center: [10, 10], maxDistance: 5 }); + * query.where('loc').near({ center: [10, 10], maxDistance: 5, spherical: true }); + * query.near('loc', { center: [10, 10], maxDistance: 5 }); + * + * @method near + * @memberOf Query + * @param {String} [path] + * @param {Object} val + * @return {Query} this + * @see $near http://docs.mongodb.org/manual/reference/operator/near/ + * @see $nearSphere http://docs.mongodb.org/manual/reference/operator/nearSphere/ + * @see $maxDistance http://docs.mongodb.org/manual/reference/operator/maxDistance/ + * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing + * @api public + */ + +/*! + * Overwriting mquery is needed to support a couple different near() forms found in older + * versions of mongoose + * near([1,1]) + * near(1,1) + * near(field, [1,2]) + * near(field, 1, 2) + * In addition to all of the normal forms supported by mquery + */ + +Query.prototype.near = function () { + var params = []; + var sphere = this._mongooseOptions.nearSphere; + + // TODO refactor + + if (arguments.length === 1) { + if (Array.isArray(arguments[0])) { + params.push({ center: arguments[0], spherical: sphere }); + } else if ('string' == typeof arguments[0]) { + // just passing a path + params.push(arguments[0]); + } else if (utils.isObject(arguments[0])) { + if ('boolean' != typeof arguments[0].spherical) { + arguments[0].spherical = sphere; + } + params.push(arguments[0]); + } else { + throw new TypeError('invalid argument'); + } + } else if (arguments.length === 2) { + if ('number' == typeof arguments[0] && 'number' == typeof arguments[1]) { + params.push({ center: [arguments[0], arguments[1]], spherical: sphere}); + } else if ('string' == typeof arguments[0] && Array.isArray(arguments[1])) { + params.push(arguments[0]); + params.push({ center: arguments[1], spherical: sphere }); + } else if ('string' == typeof arguments[0] && utils.isObject(arguments[1])) { + params.push(arguments[0]); + if ('boolean' != typeof arguments[1].spherical) { + arguments[1].spherical = sphere; + } + params.push(arguments[1]); + } else { + throw new TypeError('invalid argument'); + } + } else if (arguments.length === 3) { + if ('string' == typeof arguments[0] && 'number' == typeof arguments[1] + && 'number' == typeof arguments[2]) { + params.push(arguments[0]); + params.push({ center: [arguments[1], arguments[2]], spherical: sphere }); + } else { + throw new TypeError('invalid argument'); + } + } else { + throw new TypeError('invalid argument'); + } + + return Query.base.near.apply(this, params); +} + +/** + * _DEPRECATED_ Specifies a `$nearSphere` condition + * + * ####Example + * + * query.where('loc').nearSphere({ center: [10, 10], maxDistance: 5 }); + * + * **Deprecated.** Use `query.near()` instead with the `spherical` option set to `true`. + * + * ####Example + * + * query.where('loc').near({ center: [10, 10], spherical: true }); + * + * @deprecated + * @see near() #query_Query-near + * @see $near http://docs.mongodb.org/manual/reference/operator/near/ + * @see $nearSphere http://docs.mongodb.org/manual/reference/operator/nearSphere/ + * @see $maxDistance http://docs.mongodb.org/manual/reference/operator/maxDistance/ + */ + +Query.prototype.nearSphere = function () { + this._mongooseOptions.nearSphere = true; + this.near.apply(this, arguments); + return this; +} + +/** + * Specifies a $polygon condition + * + * ####Example + * + * query.where('loc').within().polygon([10,20], [13, 25], [7,15]) + * query.polygon('loc', [10,20], [13, 25], [7,15]) + * + * @method polygon + * @memberOf Query + * @param {String|Array} [path] + * @param {Array|Object} [coordinatePairs...] + * @return {Query} this + * @see $polygon http://docs.mongodb.org/manual/reference/operator/polygon/ + * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing + * @api public + */ + +/** + * Specifies a $box condition + * + * ####Example + * + * var lowerLeft = [40.73083, -73.99756] + * var upperRight= [40.741404, -73.988135] + * + * query.where('loc').within().box(lowerLeft, upperRight) + * query.box({ ll : lowerLeft, ur : upperRight }) + * + * @method box + * @memberOf Query + * @see $box http://docs.mongodb.org/manual/reference/operator/box/ + * @see within() Query#within #query_Query-within + * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing + * @param {Object} val + * @param [Array] Upper Right Coords + * @return {Query} this + * @api public + */ + +/*! + * this is needed to support the mongoose syntax of: + * box(field, { ll : [x,y], ur : [x2,y2] }) + * box({ ll : [x,y], ur : [x2,y2] }) + */ + +Query.prototype.box = function (ll, ur) { + if (!Array.isArray(ll) && utils.isObject(ll)) { + ur = ll.ur; + ll = ll.ll; + } + return Query.base.box.call(this, ll, ur); +} + +/** + * Specifies a $center or $centerSphere condition. + * + * ####Example + * + * var area = { center: [50, 50], radius: 10, unique: true } + * query.where('loc').within().circle(area) + * // alternatively + * query.circle('loc', area); + * + * // spherical calculations + * var area = { center: [50, 50], radius: 10, unique: true, spherical: true } + * query.where('loc').within().circle(area) + * // alternatively + * query.circle('loc', area); + * + * New in 3.7.0 + * + * @method circle + * @memberOf Query + * @param {String} [path] + * @param {Object} area + * @return {Query} this + * @see $center http://docs.mongodb.org/manual/reference/operator/center/ + * @see $centerSphere http://docs.mongodb.org/manual/reference/operator/centerSphere/ + * @see $geoWithin http://docs.mongodb.org/manual/reference/operator/within/ + * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing + * @api public + */ + +/** + * _DEPRECATED_ Alias for [circle](#query_Query-circle) + * + * **Deprecated.** Use [circle](#query_Query-circle) instead. + * + * @deprecated + * @method center + * @memberOf Query + * @api public + */ + +Query.prototype.center = Query.base.circle; + +/** + * _DEPRECATED_ Specifies a $centerSphere condition + * + * **Deprecated.** Use [circle](#query_Query-circle) instead. + * + * ####Example + * + * var area = { center: [50, 50], radius: 10 }; + * query.where('loc').within().centerSphere(area); + * + * @deprecated + * @param {String} [path] + * @param {Object} val + * @return {Query} this + * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing + * @see $centerSphere http://docs.mongodb.org/manual/reference/operator/centerSphere/ + * @api public + */ + +Query.prototype.centerSphere = function () { + if (arguments[0] && arguments[0].constructor.name == 'Object') { + arguments[0].spherical = true; + } + + if (arguments[1] && arguments[1].constructor.name == 'Object') { + arguments[1].spherical = true; + } + + Query.base.circle.apply(this, arguments); +} + +/*! + * Export + */ + +module.exports = Query; diff --git a/node_modules/mongoose/lib/queryhelpers.js b/node_modules/mongoose/lib/queryhelpers.js new file mode 100644 index 0000000..6741c1a --- /dev/null +++ b/node_modules/mongoose/lib/queryhelpers.js @@ -0,0 +1,53 @@ + +/*! + * Module dependencies + */ + +var utils = require('./utils') + +/*! + * Prepare a set of path options for query population. + * + * @param {Query} query + * @param {Object} options + * @return {Array} + */ + +exports.preparePopulationOptions = function preparePopulationOptions (query, options) { + var pop = utils.object.vals(query.options.populate); + + // lean options should trickle through all queries + if (options.lean) pop.forEach(makeLean); + + return pop; +} + +/*! + * Prepare a set of path options for query population. This is the MongooseQuery + * version + * + * @param {Query} query + * @param {Object} options + * @return {Array} + */ + +exports.preparePopulationOptionsMQ = function preparePopulationOptionsMQ (query, options) { + var pop = utils.object.vals(query._mongooseOptions.populate); + + // lean options should trickle through all queries + if (options.lean) pop.forEach(makeLean); + + return pop; +} + +/*! + * Set each path query option to lean + * + * @param {Object} option + */ + +function makeLean (option) { + option.options || (option.options = {}); + option.options.lean = true; +} + diff --git a/node_modules/mongoose/lib/querystream.js b/node_modules/mongoose/lib/querystream.js new file mode 100644 index 0000000..47fb02c --- /dev/null +++ b/node_modules/mongoose/lib/querystream.js @@ -0,0 +1,336 @@ + +/*! + * Module dependencies. + */ + +var Stream = require('stream').Stream +var utils = require('./utils') +var helpers = require('./queryhelpers') +var K = function(k){ return k } + +/** + * Provides a Node.js 0.8 style [ReadStream](http://nodejs.org/docs/v0.8.21/api/stream.html#stream_readable_stream) interface for Queries. + * + * var stream = Model.find().stream(); + * + * stream.on('data', function (doc) { + * // do something with the mongoose document + * }).on('error', function (err) { + * // handle the error + * }).on('close', function () { + * // the stream is closed + * }); + * + * + * The stream interface allows us to simply "plug-in" to other _Node.js 0.8_ style write streams. + * + * Model.where('created').gte(twoWeeksAgo).stream().pipe(writeStream); + * + * ####Valid options + * + * - `transform`: optional function which accepts a mongoose document. The return value of the function will be emitted on `data`. + * + * ####Example + * + * // JSON.stringify all documents before emitting + * var stream = Thing.find().stream({ transform: JSON.stringify }); + * stream.pipe(writeStream); + * + * _NOTE: plugging into an HTTP response will *not* work out of the box. Those streams expect only strings or buffers to be emitted, so first formatting our documents as strings/buffers is necessary._ + * + * _NOTE: these streams are Node.js 0.8 style read streams which differ from Node.js 0.10 style. Node.js 0.10 streams are not well tested yet and are not guaranteed to work._ + * + * @param {Query} query + * @param {Object} [options] + * @inherits NodeJS Stream http://nodejs.org/docs/v0.8.21/api/stream.html#stream_readable_stream + * @event `data`: emits a single Mongoose document + * @event `error`: emits when an error occurs during streaming. This will emit _before_ the `close` event. + * @event `close`: emits when the stream reaches the end of the cursor or an error occurs, or the stream is manually `destroy`ed. After this event, no more events are emitted. + * @api public + */ + +function QueryStream (query, options) { + Stream.call(this); + + this.query = query; + this.readable = true; + this.paused = false; + this._cursor = null; + this._destroyed = null; + this._fields = null; + this._buffer = null; + this._inline = T_INIT; + this._running = false; + this._transform = options && 'function' == typeof options.transform + ? options.transform + : K; + + // give time to hook up events + var self = this; + process.nextTick(function () { + self._init(); + }); +} + +/*! + * Inherit from Stream + */ + +QueryStream.prototype.__proto__ = Stream.prototype; + +/** + * Flag stating whether or not this stream is readable. + * + * @property readable + * @api public + */ + +QueryStream.prototype.readable; + +/** + * Flag stating whether or not this stream is paused. + * + * @property paused + * @api public + */ + +QueryStream.prototype.paused; + +// trampoline flags +var T_INIT = 0; +var T_IDLE = 1; +var T_CONT = 2; + +/** + * Initializes the query. + * + * @api private + */ + +QueryStream.prototype._init = function () { + if (this._destroyed) return; + + var query = this.query + , model = query.model + , options = query._optionsForExec(model) + , self = this + + try { + query.cast(model); + } catch (err) { + return self.destroy(err); + } + + self._fields = utils.clone(query._fields); + options.fields = query._castFields(self._fields); + + model.collection.find(query._conditions, options, function (err, cursor) { + if (err) return self.destroy(err); + self._cursor = cursor; + self._next(); + }); +} + +/** + * Trampoline for pulling the next doc from cursor. + * + * @see QueryStream#__next #querystream_QueryStream-__next + * @api private + */ + +QueryStream.prototype._next = function _next () { + if (this.paused || this._destroyed) { + return this._running = false; + } + + this._running = true; + + if (this._buffer && this._buffer.length) { + var arg; + while (!this.paused && !this._destroyed && (arg = this._buffer.shift())) { + this._onNextObject.apply(this, arg); + } + } + + // avoid stack overflows with large result sets. + // trampoline instead of recursion. + while (this.__next()) {} +} + +/** + * Pulls the next doc from the cursor. + * + * @see QueryStream#_next #querystream_QueryStream-_next + * @api private + */ + +QueryStream.prototype.__next = function () { + if (this.paused || this._destroyed) + return this._running = false; + + var self = this; + self._inline = T_INIT; + + self._cursor.nextObject(function cursorcb (err, doc) { + self._onNextObject(err, doc); + }); + + // if onNextObject() was already called in this tick + // return ourselves to the trampoline. + if (T_CONT === this._inline) { + return true; + } else { + // onNextObject() hasn't fired yet. tell onNextObject + // that its ok to call _next b/c we are not within + // the trampoline anymore. + this._inline = T_IDLE; + } +} + +/** + * Transforms raw `doc`s returned from the cursor into a model instance. + * + * @param {Error|null} err + * @param {Object} doc + * @api private + */ + +QueryStream.prototype._onNextObject = function _onNextObject (err, doc) { + if (this._destroyed) return; + + if (this.paused) { + this._buffer || (this._buffer = []); + this._buffer.push([err, doc]); + return this._running = false; + } + + if (err) return this.destroy(err); + + // when doc is null we hit the end of the cursor + if (!doc) { + this.emit('end'); + return this.destroy(); + } + + var opts = this.query._mongooseOptions; + + if (!opts.populate) { + return true === opts.lean + ? emit(this, doc) + : createAndEmit(this, doc); + } + + var self = this; + var pop = helpers.preparePopulationOptionsMQ(self.query, self.query._mongooseOptions); + + self.query.model.populate(doc, pop, function (err, doc) { + if (err) return self.destroy(err); + return true === opts.lean + ? emit(self, doc) + : createAndEmit(self, doc); + }) +} + +function createAndEmit (self, doc) { + var instance = new self.query.model(undefined, self._fields, true); + instance.init(doc, function (err) { + if (err) return self.destroy(err); + emit(self, instance); + }); +} + +/*! + * Emit a data event and manage the trampoline state + */ + +function emit (self, doc) { + self.emit('data', self._transform(doc)); + + // trampoline management + if (T_IDLE === self._inline) { + // no longer in trampoline. restart it. + self._next(); + } else { + // in a trampoline. tell __next that its + // ok to continue jumping. + self._inline = T_CONT; + } +} + +/** + * Pauses this stream. + * + * @api public + */ + +QueryStream.prototype.pause = function () { + this.paused = true; +} + +/** + * Resumes this stream. + * + * @api public + */ + +QueryStream.prototype.resume = function () { + this.paused = false; + + if (!this._cursor) { + // cannot start if not initialized + return; + } + + // are we within the trampoline? + if (T_INIT === this._inline) { + return; + } + + if (!this._running) { + // outside QueryStream control, need manual restart + return this._next(); + } +} + +/** + * Destroys the stream, closing the underlying cursor. No more events will be emitted. + * + * @param {Error} [err] + * @api public + */ + +QueryStream.prototype.destroy = function (err) { + if (this._destroyed) return; + this._destroyed = true; + this._running = false; + this.readable = false; + + if (this._cursor) { + this._cursor.close(); + } + + if (err) { + this.emit('error', err); + } + + this.emit('close'); +} + +/** + * Pipes this query stream into another stream. This method is inherited from NodeJS Streams. + * + * ####Example: + * + * query.stream().pipe(writeStream [, options]) + * + * @method pipe + * @memberOf QueryStream + * @see NodeJS http://nodejs.org/api/stream.html + * @api public + */ + +/*! + * Module exports + */ + +module.exports = exports = QueryStream; diff --git a/node_modules/mongoose/lib/schema.js b/node_modules/mongoose/lib/schema.js new file mode 100644 index 0000000..d5f291f --- /dev/null +++ b/node_modules/mongoose/lib/schema.js @@ -0,0 +1,882 @@ +/*! + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , VirtualType = require('./virtualtype') + , utils = require('./utils') + , mquery = require('mquery') + , Query + , Types + +/** + * Schema constructor. + * + * ####Example: + * + * var child = new Schema({ name: String }); + * var schema = new Schema({ name: String, age: Number, children: [child] }); + * var Tree = mongoose.model('Tree', schema); + * + * // setting schema options + * new Schema({ name: String }, { _id: false, autoIndex: false }) + * + * ####Options: + * + * - [autoIndex](/docs/guide.html#autoIndex): bool - defaults to true + * - [bufferCommands](/docs/guide.html#bufferCommands): bool - defaults to true + * - [capped](/docs/guide.html#capped): bool - defaults to false + * - [collection](/docs/guide.html#collection): string - no default + * - [id](/docs/guide.html#id): bool - defaults to true + * - [_id](/docs/guide.html#_id): bool - defaults to true + * - `minimize`: bool - controls [document#toObject](#document_Document-toObject) behavior when called manually - defaults to true + * - [read](/docs/guide.html#read): string + * - [safe](/docs/guide.html#safe): bool - defaults to true. + * - [shardKey](/docs/guide.html#shardKey): bool - defaults to `null` + * - [strict](/docs/guide.html#strict): bool - defaults to true + * - [toJSON](/docs/guide.html#toJSON) - object - no default + * - [toObject](/docs/guide.html#toObject) - object - no default + * - [versionKey](/docs/guide.html#versionKey): bool - defaults to "__v" + * + * ####Note: + * + * _When nesting schemas, (`children` in the example above), always declare the child schema first before passing it into is parent._ + * + * @param {Object} definition + * @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter + * @event `init`: Emitted after the schema is compiled into a `Model`. + * @api public + */ + +function Schema (obj, options) { + if (!(this instanceof Schema)) + return new Schema(obj, options); + + this.paths = {}; + this.subpaths = {}; + this.virtuals = {}; + this.nested = {}; + this.inherits = {}; + this.callQueue = []; + this._indexes = []; + this.methods = {}; + this.statics = {}; + this.tree = {}; + this._requiredpaths = undefined; + this.discriminatorMapping = undefined; + + this.options = this.defaultOptions(options); + + // build paths + if (obj) { + this.add(obj); + } + + // ensure the documents get an auto _id unless disabled + var auto_id = !this.paths['_id'] && (!this.options.noId && this.options._id); + if (auto_id) { + this.add({ _id: {type: Schema.ObjectId, auto: true} }); + } + + // ensure the documents receive an id getter unless disabled + var autoid = !this.paths['id'] && (!this.options.noVirtualId && this.options.id); + if (autoid) { + this.virtual('id').get(idGetter); + } +} + +/*! + * Returns this documents _id cast to a string. + */ + +function idGetter () { + if (this.$__._id) { + return this.$__._id; + } + + return this.$__._id = null == this._id + ? null + : String(this._id); +} + +/*! + * Inherit from EventEmitter. + */ + +Schema.prototype.__proto__ = EventEmitter.prototype; + +/** + * Schema as flat paths + * + * ####Example: + * { + * '_id' : SchemaType, + * , 'nested.key' : SchemaType, + * } + * + * @api private + * @property paths + */ + +Schema.prototype.paths; + +/** + * Schema as a tree + * + * ####Example: + * { + * '_id' : ObjectId + * , 'nested' : { + * 'key' : String + * } + * } + * + * @api private + * @property tree + */ + +Schema.prototype.tree; + +/** + * Returns default options for this schema, merged with `options`. + * + * @param {Object} options + * @return {Object} + * @api private + */ + +Schema.prototype.defaultOptions = function (options) { + if (options && false === options.safe) { + options.safe = { w: 0 }; + } + + if (options && options.safe && 0 === options.safe.w) { + // if you turn off safe writes, then versioning goes off as well + options.versionKey = false; + } + + options = utils.options({ + strict: true + , bufferCommands: true + , capped: false // { size, max, autoIndexId } + , versionKey: '__v' + , discriminatorKey: '__t' + , minimize: true + , autoIndex: true + , shardKey: null + , read: null + // the following are only applied at construction time + , noId: false // deprecated, use { _id: false } + , _id: true + , noVirtualId: false // deprecated, use { id: false } + , id: true +// , pluralization: true // only set this to override the global option + }, options); + + if (options.read) { + options.read = mquery.utils.readPref(options.read); + } + + return options; +} + +/** + * Adds key path / schema type pairs to this schema. + * + * ####Example: + * + * var ToySchema = new Schema; + * ToySchema.add({ name: 'string', color: 'string', price: 'number' }); + * + * @param {Object} obj + * @param {String} prefix + * @api public + */ + +Schema.prototype.add = function add (obj, prefix) { + prefix = prefix || ''; + var keys = Object.keys(obj); + + for (var i = 0; i < keys.length; ++i) { + var key = keys[i]; + + if (null == obj[key]) { + throw new TypeError('Invalid value for schema path `'+ prefix + key +'`'); + } + + if (utils.isObject(obj[key]) && (!obj[key].constructor || 'Object' == obj[key].constructor.name) && (!obj[key].type || obj[key].type.type)) { + if (Object.keys(obj[key]).length) { + // nested object { last: { name: String }} + this.nested[prefix + key] = true; + this.add(obj[key], prefix + key + '.'); + } else { + this.path(prefix + key, obj[key]); // mixed type + } + } else { + this.path(prefix + key, obj[key]); + } + } +}; + +/** + * Reserved document keys. + * + * Keys in this object are names that are rejected in schema declarations b/c they conflict with mongoose functionality. Using these key name will throw an error. + * + * on, emit, _events, db, init, isNew, errors, schema, options, modelName, collection, _pres, _posts, toObject + * + * _NOTE:_ Use of these terms as method names is permitted, but play at your own risk, as they may be existing mongoose document methods you are stomping on. + * + * var schema = new Schema(..); + * schema.methods.init = function () {} // potentially breaking + */ + +Schema.reserved = Object.create(null); +var reserved = Schema.reserved; +reserved.on = +reserved.db = +reserved.init = +reserved.isNew = +reserved.errors = +reserved.schema = +reserved.options = +reserved.modelName = +reserved.collection = +reserved.toObject = +reserved.emit = // EventEmitter +reserved._events = // EventEmitter +reserved._pres = reserved._posts = 1 // hooks.js + +/** + * Gets/sets schema paths. + * + * Sets a path (if arity 2) + * Gets a path (if arity 1) + * + * ####Example + * + * schema.path('name') // returns a SchemaType + * schema.path('name', Number) // changes the schemaType of `name` to Number + * + * @param {String} path + * @param {Object} constructor + * @api public + */ + +Schema.prototype.path = function (path, obj) { + if (obj == undefined) { + if (this.paths[path]) return this.paths[path]; + if (this.subpaths[path]) return this.subpaths[path]; + + // subpaths? + return /\.\d+\.?.*$/.test(path) + ? getPositionalPath(this, path) + : undefined; + } + + // some path names conflict with document methods + if (reserved[path]) { + throw new Error("`" + path + "` may not be used as a schema pathname"); + } + + // update the tree + var subpaths = path.split(/\./) + , last = subpaths.pop() + , branch = this.tree; + + subpaths.forEach(function(sub, i) { + if (!branch[sub]) branch[sub] = {}; + if ('object' != typeof branch[sub]) { + var msg = 'Cannot set nested path `' + path + '`. ' + + 'Parent path `' + + subpaths.slice(0, i).concat([sub]).join('.') + + '` already set to type ' + branch[sub].name + + '.'; + throw new Error(msg); + } + branch = branch[sub]; + }); + + branch[last] = utils.clone(obj); + + this.paths[path] = Schema.interpretAsType(path, obj); + return this; +}; + +/** + * Converts type arguments into Mongoose Types. + * + * @param {String} path + * @param {Object} obj constructor + * @api private + */ + +Schema.interpretAsType = function (path, obj) { + if (obj.constructor && obj.constructor.name != 'Object') + obj = { type: obj }; + + // Get the type making sure to allow keys named "type" + // and default to mixed if not specified. + // { type: { type: String, default: 'freshcut' } } + var type = obj.type && !obj.type.type + ? obj.type + : {}; + + if ('Object' == type.constructor.name || 'mixed' == type) { + return new Types.Mixed(path, obj); + } + + if (Array.isArray(type) || Array == type || 'array' == type) { + // if it was specified through { type } look for `cast` + var cast = (Array == type || 'array' == type) + ? obj.cast + : type[0]; + + if (cast instanceof Schema) { + return new Types.DocumentArray(path, cast, obj); + } + + if ('string' == typeof cast) { + cast = Types[cast.charAt(0).toUpperCase() + cast.substring(1)]; + } else if (cast && (!cast.type || cast.type.type) + && 'Object' == cast.constructor.name + && Object.keys(cast).length) { + return new Types.DocumentArray(path, new Schema(cast), obj); + } + + return new Types.Array(path, cast || Types.Mixed, obj); + } + + var name = 'string' == typeof type + ? type + : type.name; + + if (name) { + name = name.charAt(0).toUpperCase() + name.substring(1); + } + + if (undefined == Types[name]) { + throw new TypeError('Undefined type at `' + path + + '`\n Did you try nesting Schemas? ' + + 'You can only nest using refs or arrays.'); + } + + return new Types[name](path, obj); +}; + +/** + * Iterates the schemas paths similar to Array#forEach. + * + * The callback is passed the pathname and schemaType as arguments on each iteration. + * + * @param {Function} fn callback function + * @return {Schema} this + * @api public + */ + +Schema.prototype.eachPath = function (fn) { + var keys = Object.keys(this.paths) + , len = keys.length; + + for (var i = 0; i < len; ++i) { + fn(keys[i], this.paths[keys[i]]); + } + + return this; +}; + +/** + * Returns an Array of path strings that are required by this schema. + * + * @api public + * @return {Array} + */ + +Schema.prototype.requiredPaths = function requiredPaths () { + if (this._requiredpaths) return this._requiredpaths; + + var paths = Object.keys(this.paths) + , i = paths.length + , ret = []; + + while (i--) { + var path = paths[i]; + if (this.paths[path].isRequired) ret.push(path); + } + + return this._requiredpaths = ret; +} + +/** + * Returns the pathType of `path` for this schema. + * + * Given a path, returns whether it is a real, virtual, nested, or ad-hoc/undefined path. + * + * @param {String} path + * @return {String} + * @api public + */ + +Schema.prototype.pathType = function (path) { + if (path in this.paths) return 'real'; + if (path in this.virtuals) return 'virtual'; + if (path in this.nested) return 'nested'; + if (path in this.subpaths) return 'real'; + + if (/\.\d+\.|\.\d+$/.test(path) && getPositionalPath(this, path)) { + return 'real'; + } else { + return 'adhocOrUndefined' + } +}; + +/*! + * ignore + */ + +function getPositionalPath (self, path) { + var subpaths = path.split(/\.(\d+)\.|\.(\d+)$/).filter(Boolean); + if (subpaths.length < 2) { + return self.paths[subpaths[0]]; + } + + var val = self.path(subpaths[0]); + if (!val) return val; + + var last = subpaths.length - 1 + , subpath + , i = 1; + + for (; i < subpaths.length; ++i) { + subpath = subpaths[i]; + + if (i === last && val && !val.schema && !/\D/.test(subpath)) { + if (val instanceof Types.Array) { + // StringSchema, NumberSchema, etc + val = val.caster; + } else { + val = undefined; + } + break; + } + + // ignore if its just a position segment: path.0.subpath + if (!/\D/.test(subpath)) continue; + + if (!(val && val.schema)) { + val = undefined; + break; + } + + val = val.schema.path(subpath); + } + + return self.subpaths[path] = val; +} + +/** + * Adds a method call to the queue. + * + * @param {String} name name of the document method to call later + * @param {Array} args arguments to pass to the method + * @api private + */ + +Schema.prototype.queue = function(name, args){ + this.callQueue.push([name, args]); + return this; +}; + +/** + * Defines a pre hook for the document. + * + * ####Example + * + * var toySchema = new Schema(..); + * + * toySchema.pre('save', function (next) { + * if (!this.created) this.created = new Date; + * next(); + * }) + * + * toySchema.pre('validate', function (next) { + * if (this.name != 'Woody') this.name = 'Woody'; + * next(); + * }) + * + * @param {String} method + * @param {Function} callback + * @see hooks.js https://github.com/bnoguchi/hooks-js/tree/31ec571cef0332e21121ee7157e0cf9728572cc3 + * @api public + */ + +Schema.prototype.pre = function(){ + return this.queue('pre', arguments); +}; + +/** + * Defines a post for the document + * + * Post hooks fire `on` the event emitted from document instances of Models compiled from this schema. + * + * var schema = new Schema(..); + * schema.post('save', function (doc) { + * console.log('this fired after a document was saved'); + * }); + * + * var Model = mongoose.model('Model', schema); + * + * var m = new Model(..); + * m.save(function (err) { + * console.log('this fires after the `post` hook'); + * }); + * + * @param {String} method name of the method to hook + * @param {Function} fn callback + * @see hooks.js https://github.com/bnoguchi/hooks-js/tree/31ec571cef0332e21121ee7157e0cf9728572cc3 + * @api public + */ + +Schema.prototype.post = function(method, fn){ + return this.queue('on', arguments); +}; + +/** + * Registers a plugin for this schema. + * + * @param {Function} plugin callback + * @param {Object} opts + * @see plugins + * @api public + */ + +Schema.prototype.plugin = function (fn, opts) { + fn(this, opts); + return this; +}; + +/** + * Adds an instance method to documents constructed from Models compiled from this schema. + * + * ####Example + * + * var schema = kittySchema = new Schema(..); + * + * schema.method('meow', function () { + * console.log('meeeeeoooooooooooow'); + * }) + * + * var Kitty = mongoose.model('Kitty', schema); + * + * var fizz = new Kitty; + * fizz.meow(); // meeeeeooooooooooooow + * + * If a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as methods. + * + * schema.method({ + * purr: function () {} + * , scratch: function () {} + * }); + * + * // later + * fizz.purr(); + * fizz.scratch(); + * + * @param {String|Object} method name + * @param {Function} [fn] + * @api public + */ + +Schema.prototype.method = function (name, fn) { + if ('string' != typeof name) + for (var i in name) + this.methods[i] = name[i]; + else + this.methods[name] = fn; + return this; +}; + +/** + * Adds static "class" methods to Models compiled from this schema. + * + * ####Example + * + * var schema = new Schema(..); + * schema.static('findByName', function (name, callback) { + * return this.find({ name: name }, callback); + * }); + * + * var Drink = mongoose.model('Drink', schema); + * Drink.findByName('sanpellegrino', function (err, drinks) { + * // + * }); + * + * If a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as statics. + * + * @param {String} name + * @param {Function} fn + * @api public + */ + +Schema.prototype.static = function(name, fn) { + if ('string' != typeof name) + for (var i in name) + this.statics[i] = name[i]; + else + this.statics[name] = fn; + return this; +}; + +/** + * Defines an index (most likely compound) for this schema. + * + * ####Example + * + * schema.index({ first: 1, last: -1 }) + * + * @param {Object} fields + * @param {Object} [options] + * @api public + */ + +Schema.prototype.index = function (fields, options) { + options || (options = {}); + + if (options.expires) + utils.expires(options); + + this._indexes.push([fields, options]); + return this; +}; + +/** + * Sets/gets a schema option. + * + * @param {String} key option name + * @param {Object} [value] if not passed, the current option value is returned + * @api public + */ + +Schema.prototype.set = function (key, value, _tags) { + if (1 === arguments.length) { + return this.options[key]; + } + + switch (key) { + case 'read': + this.options[key] = mquery.utils.readPref(value, _tags) + break; + case 'safe': + this.options[key] = false === value + ? { w: 0 } + : value + break; + default: + this.options[key] = value; + } + + return this; +} + +/** + * Gets a schema option. + * + * @param {String} key option name + * @api public + */ + +Schema.prototype.get = function (key) { + return this.options[key]; +} + +/** + * The allowed index types + * + * @static indexTypes + * @receiver Schema + * @api public + */ + +var indexTypes = '2d 2dsphere hashed text'.split(' '); + +Object.defineProperty(Schema, 'indexTypes', { + get: function () { return indexTypes } + , set: function () { throw new Error('Cannot overwrite Schema.indexTypes') } +}) + +/** + * Compiles indexes from fields and schema-level indexes + * + * @api public + */ + +Schema.prototype.indexes = function () { + 'use strict'; + + var indexes = [] + , seenSchemas = [] + collectIndexes(this); + return indexes; + + function collectIndexes (schema, prefix) { + if (~seenSchemas.indexOf(schema)) return; + seenSchemas.push(schema); + + prefix = prefix || ''; + + var key, path, index, field, isObject, options, type; + var keys = Object.keys(schema.paths); + + for (var i = 0; i < keys.length; ++i) { + key = keys[i]; + path = schema.paths[key]; + + if (path instanceof Types.DocumentArray) { + collectIndexes(path.schema, key + '.'); + } else { + index = path._index; + + if (false !== index && null != index) { + field = {}; + isObject = utils.isObject(index); + options = isObject ? index : {}; + type = 'string' == typeof index ? index : + isObject ? index.type : + false; + + if (type && ~Schema.indexTypes.indexOf(type)) { + field[prefix + key] = type; + } else { + field[prefix + key] = 1; + } + + delete options.type; + if (!('background' in options)) { + options.background = true; + } + + indexes.push([field, options]); + } + } + } + + if (prefix) { + fixSubIndexPaths(schema, prefix); + } else { + schema._indexes.forEach(function (index) { + if (!('background' in index[1])) index[1].background = true; + }); + indexes = indexes.concat(schema._indexes); + } + } + + /*! + * Checks for indexes added to subdocs using Schema.index(). + * These indexes need their paths prefixed properly. + * + * schema._indexes = [ [indexObj, options], [indexObj, options] ..] + */ + + function fixSubIndexPaths (schema, prefix) { + var subindexes = schema._indexes + , len = subindexes.length + , indexObj + , newindex + , klen + , keys + , key + , i = 0 + , j + + for (i = 0; i < len; ++i) { + indexObj = subindexes[i][0]; + keys = Object.keys(indexObj); + klen = keys.length; + newindex = {}; + + // use forward iteration, order matters + for (j = 0; j < klen; ++j) { + key = keys[j]; + newindex[prefix + key] = indexObj[key]; + } + + indexes.push([newindex, subindexes[i][1]]); + } + } +} + +/** + * Creates a virtual type with the given name. + * + * @param {String} name + * @param {Object} [options] + * @return {VirtualType} + */ + +Schema.prototype.virtual = function (name, options) { + var virtuals = this.virtuals; + var parts = name.split('.'); + return virtuals[name] = parts.reduce(function (mem, part, i) { + mem[part] || (mem[part] = (i === parts.length-1) + ? new VirtualType(options, name) + : {}); + return mem[part]; + }, this.tree); +}; + +/** + * Returns the virtual type with the given `name`. + * + * @param {String} name + * @return {VirtualType} + */ + +Schema.prototype.virtualpath = function (name) { + return this.virtuals[name]; +}; + +/*! + * Module exports. + */ + +module.exports = exports = Schema; + +// require down here because of reference issues + +/** + * The various built-in Mongoose Schema Types. + * + * ####Example: + * + * var mongoose = require('mongoose'); + * var ObjectId = mongoose.Schema.Types.ObjectId; + * + * ####Types: + * + * - [String](#schema-string-js) + * - [Number](#schema-number-js) + * - [Boolean](#schema-boolean-js) | Bool + * - [Array](#schema-array-js) + * - [Buffer](#schema-buffer-js) + * - [Date](#schema-date-js) + * - [ObjectId](#schema-objectid-js) | Oid + * - [Mixed](#schema-mixed-js) + * + * Using this exposed access to the `Mixed` SchemaType, we can use them in our schema. + * + * var Mixed = mongoose.Schema.Types.Mixed; + * new mongoose.Schema({ _user: Mixed }) + * + * @api public + */ + +Schema.Types = require('./schema/index'); + +/*! + * ignore + */ + +Types = Schema.Types; +Query = require('./query'); +var ObjectId = exports.ObjectId = Types.ObjectId; + diff --git a/node_modules/mongoose/lib/schema/array.js b/node_modules/mongoose/lib/schema/array.js new file mode 100644 index 0000000..79af774 --- /dev/null +++ b/node_modules/mongoose/lib/schema/array.js @@ -0,0 +1,351 @@ +/*! + * Module dependencies. + */ + +var SchemaType = require('../schematype') + , CastError = SchemaType.CastError + , NumberSchema = require('./number') + , Types = { + Boolean: require('./boolean') + , Date: require('./date') + , Number: require('./number') + , String: require('./string') + , ObjectId: require('./objectid') + , Buffer: require('./buffer') + } + , MongooseArray = require('../types').Array + , EmbeddedDoc = require('../types').Embedded + , Mixed = require('./mixed') + , Query = require('../query') + , utils = require('../utils') + , isMongooseObject = utils.isMongooseObject + +/** + * Array SchemaType constructor + * + * @param {String} key + * @param {SchemaType} cast + * @param {Object} options + * @inherits SchemaType + * @api private + */ + +function SchemaArray (key, cast, options) { + if (cast) { + var castOptions = {}; + + if ('Object' === cast.constructor.name) { + if (cast.type) { + // support { type: Woot } + castOptions = utils.clone(cast); // do not alter user arguments + delete castOptions.type; + cast = cast.type; + } else { + cast = Mixed; + } + } + + // support { type: 'String' } + var name = 'string' == typeof cast + ? cast + : cast.name; + + var caster = name in Types + ? Types[name] + : cast; + + this.casterConstructor = caster; + this.caster = new caster(null, castOptions); + if (!(this.caster instanceof EmbeddedDoc)) { + this.caster.path = key; + } + } + + SchemaType.call(this, key, options); + + var self = this + , defaultArr + , fn; + + if (this.defaultValue) { + defaultArr = this.defaultValue; + fn = 'function' == typeof defaultArr; + } + + this.default(function(){ + var arr = fn ? defaultArr() : defaultArr || []; + return new MongooseArray(arr, self.path, this); + }); +}; + +/*! + * Inherits from SchemaType. + */ + +SchemaArray.prototype.__proto__ = SchemaType.prototype; + +/** + * Check required + * + * @param {Array} value + * @api private + */ + +SchemaArray.prototype.checkRequired = function (value) { + return !!(value && value.length); +}; + +/** + * Overrides the getters application for the population special-case + * + * @param {Object} value + * @param {Object} scope + * @api private + */ + +SchemaArray.prototype.applyGetters = function (value, scope) { + if (this.caster.options && this.caster.options.ref) { + // means the object id was populated + return value; + } + + return SchemaType.prototype.applyGetters.call(this, value, scope); +}; + +/** + * Casts values for set(). + * + * @param {Object} value + * @param {Document} doc document that triggers the casting + * @param {Boolean} init whether this is an initialization cast + * @api private + */ + +SchemaArray.prototype.cast = function (value, doc, init) { + if (Array.isArray(value)) { + if (!(value instanceof MongooseArray)) { + value = new MongooseArray(value, this.path, doc); + } + + if (this.caster) { + try { + for (var i = 0, l = value.length; i < l; i++) { + value[i] = this.caster.cast(value[i], doc, init); + } + } catch (e) { + // rethrow + throw new CastError(e.type, value, this.path); + } + } + + return value; + } else { + return this.cast([value], doc, init); + } +}; + +/** + * Casts values for queries. + * + * @param {String} $conditional + * @param {any} [value] + * @api private + */ + +SchemaArray.prototype.castForQuery = function ($conditional, value) { + var handler + , val; + + if (arguments.length === 2) { + handler = this.$conditionalHandlers[$conditional]; + + if (!handler) { + throw new Error("Can't use " + $conditional + " with Array."); + } + + val = handler.call(this, value); + + } else { + + val = $conditional; + var proto = this.casterConstructor.prototype; + var method = proto.castForQuery || proto.cast; + var caster = this.caster; + + if (Array.isArray(val)) { + val = val.map(function (v) { + if (method) v = method.call(caster, v); + return isMongooseObject(v) + ? v.toObject() + : v; + }); + + } else if (method) { + val = method.call(caster, val); + } + } + + return val && isMongooseObject(val) + ? val.toObject() + : val; +}; + +/*! + * @ignore + * + * $atomic cast helpers + */ + +function castToNumber (val) { + return Types.Number.prototype.cast.call(this, val); +} + +function castArraysOfNumbers (arr, self) { + self || (self = this); + + arr.forEach(function (v, i) { + if (Array.isArray(v)) { + castArraysOfNumbers(v, self); + } else { + arr[i] = castToNumber.call(self, v); + } + }); +} + +function cast$near (val) { + if (Array.isArray(val)) { + castArraysOfNumbers(val, this); + return val; + } + + if (val && val.$geometry) { + return cast$geometry(val, this); + } + + return SchemaArray.prototype.castForQuery.call(this, val); +} + +function cast$geometry (val, self) { + switch (val.$geometry.type) { + case 'Polygon': + case 'LineString': + case 'Point': + castArraysOfNumbers(val.$geometry.coordinates, self); + break; + default: + // ignore unknowns + break; + } + + if (val.$maxDistance) { + val.$maxDistance = castToNumber.call(self, val.$maxDistance); + } + + return val; +} + +function cast$within (val) { + var self = this; + + if (val.$maxDistance) { + val.$maxDistance = castToNumber.call(self, val.$maxDistance); + } + + if (val.$box || val.$polygon) { + var type = val.$box ? '$box' : '$polygon'; + val[type].forEach(function (arr) { + if (!Array.isArray(arr)) { + var msg = 'Invalid $within $box argument. ' + + 'Expected an array, received ' + arr; + throw new TypeError(msg); + } + arr.forEach(function (v, i) { + arr[i] = castToNumber.call(this, v); + }); + }) + } else if (val.$center || val.$centerSphere) { + var type = val.$center ? '$center' : '$centerSphere'; + val[type].forEach(function (item, i) { + if (Array.isArray(item)) { + item.forEach(function (v, j) { + item[j] = castToNumber.call(this, v); + }); + } else { + val[type][i] = castToNumber.call(this, item); + } + }) + } else if (val.$geometry) { + cast$geometry(val, this); + } + + return val; +} + +function cast$all (val) { + if (!Array.isArray(val)) { + val = [val]; + } + + val = val.map(function (v) { + if (utils.isObject(v)) { + var o = {}; + o[this.path] = v; + var query = new Query(o); + query.cast(this.casterConstructor); + return query._conditions[this.path]; + } + return v; + }, this); + + return this.castForQuery(val); +} + +function cast$elemMatch (val) { + if (val.$in) { + val.$in = this.castForQuery('$in', val.$in); + return val; + } + + var query = new Query(val); + query.cast(this.casterConstructor); + return query._conditions; +} + +function cast$geoIntersects (val) { + var geo = val.$geometry; + if (!geo) return; + + cast$geometry(val, this); + return val; +} + +var handle = SchemaArray.prototype.$conditionalHandlers = {}; + +handle.$all = cast$all; +handle.$options = String; +handle.$elemMatch = cast$elemMatch; +handle.$geoIntersects = cast$geoIntersects; + +handle.$near = +handle.$nearSphere = cast$near; + +handle.$within = +handle.$geoWithin = cast$within; + +handle.$size = +handle.$maxDistance = castToNumber; + +handle.$regex = +handle.$ne = +handle.$in = +handle.$nin = +handle.$gt = +handle.$gte = +handle.$lt = +handle.$lte = SchemaArray.prototype.castForQuery; + +/*! + * Module exports. + */ + +module.exports = SchemaArray; diff --git a/node_modules/mongoose/lib/schema/boolean.js b/node_modules/mongoose/lib/schema/boolean.js new file mode 100644 index 0000000..cc16b7a --- /dev/null +++ b/node_modules/mongoose/lib/schema/boolean.js @@ -0,0 +1,92 @@ +/*! + * Module dependencies. + */ + +var SchemaType = require('../schematype'); + +/** + * Boolean SchemaType constructor. + * + * @param {String} path + * @param {Object} options + * @inherits SchemaType + * @api private + */ + +function SchemaBoolean (path, options) { + SchemaType.call(this, path, options); +}; + +/*! + * Inherits from SchemaType. + */ +SchemaBoolean.prototype.__proto__ = SchemaType.prototype; + +/** + * Required validator + * + * @api private + */ + +SchemaBoolean.prototype.checkRequired = function (value) { + return value === true || value === false; +}; + +/** + * Casts to boolean + * + * @param {Object} value + * @api private + */ + +SchemaBoolean.prototype.cast = function (value) { + if (null === value) return value; + if ('0' === value) return false; + if ('true' === value) return true; + if ('false' === value) return false; + return !! value; +} + +/*! + * ignore + */ + +function handleArray (val) { + var self = this; + return val.map(function (m) { + return self.cast(m); + }); +} + +SchemaBoolean.$conditionalHandlers = { + '$in': handleArray +} + +/** + * Casts contents for queries. + * + * @param {String} $conditional + * @param {any} val + * @api private + */ + +SchemaBoolean.prototype.castForQuery = function ($conditional, val) { + var handler; + if (2 === arguments.length) { + handler = SchemaBoolean.$conditionalHandlers[$conditional]; + + if (handler) { + return handler.call(this, val); + } + + return this.cast(val); + } + + return this.cast($conditional); +}; + +/*! + * Module exports. + */ + +module.exports = SchemaBoolean; diff --git a/node_modules/mongoose/lib/schema/buffer.js b/node_modules/mongoose/lib/schema/buffer.js new file mode 100644 index 0000000..dbaf193 --- /dev/null +++ b/node_modules/mongoose/lib/schema/buffer.js @@ -0,0 +1,168 @@ +/*! + * Module dependencies. + */ + +var SchemaType = require('../schematype') + , CastError = SchemaType.CastError + , MongooseBuffer = require('../types').Buffer + , Binary = MongooseBuffer.Binary + , Query = require('../query') + , utils = require('../utils') + , Document + +/** + * Buffer SchemaType constructor + * + * @param {String} key + * @param {SchemaType} cast + * @inherits SchemaType + * @api private + */ + +function SchemaBuffer (key, options) { + SchemaType.call(this, key, options, 'Buffer'); +}; + +/*! + * Inherits from SchemaType. + */ + +SchemaBuffer.prototype.__proto__ = SchemaType.prototype; + +/** + * Check required + * + * @api private + */ + +SchemaBuffer.prototype.checkRequired = function (value, doc) { + if (SchemaType._isRef(this, value, doc, true)) { + return null != value; + } else { + return !!(value && value.length); + } +}; + +/** + * Casts contents + * + * @param {Object} value + * @param {Document} doc document that triggers the casting + * @param {Boolean} init + * @api private + */ + +SchemaBuffer.prototype.cast = function (value, doc, init) { + if (SchemaType._isRef(this, value, doc, init)) { + // wait! we may need to cast this to a document + + if (null == value) { + return value; + } + + // lazy load + Document || (Document = require('./../document')); + + if (value instanceof Document) { + value.$__.wasPopulated = true; + return value; + } + + // setting a populated path + if (Buffer.isBuffer(value)) { + return value; + } else if (!utils.isObject(value)) { + throw new CastError('buffer', value, this.path); + } + + // Handle the case where user directly sets a populated + // path to a plain object; cast to the Model used in + // the population query. + var path = doc.$__fullPath(this.path); + var owner = doc.ownerDocument ? doc.ownerDocument() : doc; + var pop = owner.populated(path, true); + var ret = new pop.options.model(value); + ret.$__.wasPopulated = true; + return ret; + } + + // documents + if (value && value._id) { + value = value._id; + } + + if (Buffer.isBuffer(value)) { + if (!(value instanceof MongooseBuffer)) { + value = new MongooseBuffer(value, [this.path, doc]); + } + + return value; + } else if (value instanceof Binary) { + var ret = new MongooseBuffer(value.value(true), [this.path, doc]); + ret.subtype(value.sub_type); + // do not override Binary subtypes. users set this + // to whatever they want. + return ret; + } + + if (null === value) return value; + + var type = typeof value; + if ('string' == type || 'number' == type || Array.isArray(value)) { + var ret = new MongooseBuffer(value, [this.path, doc]); + return ret; + } + + throw new CastError('buffer', value, this.path); +}; + +/*! + * ignore + */ +function handleSingle (val) { + return this.castForQuery(val); +} + +function handleArray (val) { + var self = this; + return val.map( function (m) { + return self.castForQuery(m); + }); +} + +SchemaBuffer.prototype.$conditionalHandlers = { + '$ne' : handleSingle + , '$in' : handleArray + , '$nin': handleArray + , '$gt' : handleSingle + , '$lt' : handleSingle + , '$gte': handleSingle + , '$lte': handleSingle +}; + +/** + * Casts contents for queries. + * + * @param {String} $conditional + * @param {any} [value] + * @api private + */ + +SchemaBuffer.prototype.castForQuery = function ($conditional, val) { + var handler; + if (arguments.length === 2) { + handler = this.$conditionalHandlers[$conditional]; + if (!handler) + throw new Error("Can't use " + $conditional + " with Buffer."); + return handler.call(this, val); + } else { + val = $conditional; + return this.cast(val).toObject(); + } +}; + +/*! + * Module exports. + */ + +module.exports = SchemaBuffer; diff --git a/node_modules/mongoose/lib/schema/date.js b/node_modules/mongoose/lib/schema/date.js new file mode 100644 index 0000000..86e4062 --- /dev/null +++ b/node_modules/mongoose/lib/schema/date.js @@ -0,0 +1,167 @@ +/*! + * Module requirements. + */ + +var SchemaType = require('../schematype'); +var CastError = SchemaType.CastError; +var utils = require('../utils'); + +/** + * Date SchemaType constructor. + * + * @param {String} key + * @param {Object} options + * @inherits SchemaType + * @api private + */ + +function SchemaDate (key, options) { + SchemaType.call(this, key, options); +}; + +/*! + * Inherits from SchemaType. + */ + +SchemaDate.prototype.__proto__ = SchemaType.prototype; + +/** + * Declares a TTL index (rounded to the nearest second) for _Date_ types only. + * + * This sets the `expiresAfterSeconds` index option available in MongoDB >= 2.1.2. + * This index type is only compatible with Date types. + * + * ####Example: + * + * // expire in 24 hours + * new Schema({ createdAt: { type: Date, expires: 60*60*24 }}); + * + * `expires` utilizes the `ms` module from [guille](https://github.com/guille/) allowing us to use a friendlier syntax: + * + * ####Example: + * + * // expire in 24 hours + * new Schema({ createdAt: { type: Date, expires: '24h' }}); + * + * // expire in 1.5 hours + * new Schema({ createdAt: { type: Date, expires: '1.5h' }}); + * + * // expire in 7 days + * var schema = new Schema({ createdAt: Date }); + * schema.path('createdAt').expires('7d'); + * + * @param {Number|String} when + * @added 3.0.0 + * @return {SchemaType} this + * @api public + */ + +SchemaDate.prototype.expires = function (when) { + if (!this._index || 'Object' !== this._index.constructor.name) { + this._index = {}; + } + + this._index.expires = when; + utils.expires(this._index); + return this; +}; + +/** + * Required validator for date + * + * @api private + */ + +SchemaDate.prototype.checkRequired = function (value) { + return value instanceof Date; +}; + +/** + * Casts to date + * + * @param {Object} value to cast + * @api private + */ + +SchemaDate.prototype.cast = function (value) { + if (value === null || value === '') + return null; + + if (value instanceof Date) + return value; + + var date; + + // support for timestamps + if (value instanceof Number || 'number' == typeof value + || String(value) == Number(value)) + date = new Date(Number(value)); + + // support for date strings + else if (value.toString) + date = new Date(value.toString()); + + if (date.toString() != 'Invalid Date') + return date; + + throw new CastError('date', value, this.path); +}; + +/*! + * Date Query casting. + * + * @api private + */ + +function handleSingle (val) { + return this.cast(val); +} + +function handleArray (val) { + var self = this; + return val.map( function (m) { + return self.cast(m); + }); +} + +SchemaDate.prototype.$conditionalHandlers = { + '$lt': handleSingle + , '$lte': handleSingle + , '$gt': handleSingle + , '$gte': handleSingle + , '$ne': handleSingle + , '$in': handleArray + , '$nin': handleArray + , '$all': handleArray +}; + + +/** + * Casts contents for queries. + * + * @param {String} $conditional + * @param {any} [value] + * @api private + */ + +SchemaDate.prototype.castForQuery = function ($conditional, val) { + var handler; + + if (2 !== arguments.length) { + return this.cast($conditional); + } + + handler = this.$conditionalHandlers[$conditional]; + + if (!handler) { + throw new Error("Can't use " + $conditional + " with Date."); + } + + return handler.call(this, val); +}; + +/*! + * Module exports. + */ + +module.exports = SchemaDate; diff --git a/node_modules/mongoose/lib/schema/documentarray.js b/node_modules/mongoose/lib/schema/documentarray.js new file mode 100644 index 0000000..3b02887 --- /dev/null +++ b/node_modules/mongoose/lib/schema/documentarray.js @@ -0,0 +1,189 @@ + +/*! + * Module dependencies. + */ + +var SchemaType = require('../schematype') + , ArrayType = require('./array') + , MongooseDocumentArray = require('../types/documentarray') + , Subdocument = require('../types/embedded') + , Document = require('../document'); + +/** + * SubdocsArray SchemaType constructor + * + * @param {String} key + * @param {Schema} schema + * @param {Object} options + * @inherits SchemaArray + * @api private + */ + +function DocumentArray (key, schema, options) { + + // compile an embedded document for this schema + function EmbeddedDocument () { + Subdocument.apply(this, arguments); + } + + EmbeddedDocument.prototype.__proto__ = Subdocument.prototype; + EmbeddedDocument.prototype.$__setSchema(schema); + EmbeddedDocument.schema = schema; + + // apply methods + for (var i in schema.methods) { + EmbeddedDocument.prototype[i] = schema.methods[i]; + } + + // apply statics + for (var i in schema.statics) + EmbeddedDocument[i] = schema.statics[i]; + + EmbeddedDocument.options = options; + this.schema = schema; + + ArrayType.call(this, key, EmbeddedDocument, options); + + this.schema = schema; + var path = this.path; + var fn = this.defaultValue; + + this.default(function(){ + var arr = fn.call(this); + if (!Array.isArray(arr)) arr = [arr]; + return new MongooseDocumentArray(arr, path, this); + }); +}; + +/*! + * Inherits from ArrayType. + */ + +DocumentArray.prototype.__proto__ = ArrayType.prototype; + +/** + * Performs local validations first, then validations on each embedded doc + * + * @api private + */ + +DocumentArray.prototype.doValidate = function (array, fn, scope) { + var self = this; + + SchemaType.prototype.doValidate.call(this, array, function (err) { + if (err) return fn(err); + + var count = array && array.length + , error; + + if (!count) return fn(); + + // handle sparse arrays, do not use array.forEach which does not + // iterate over sparse elements yet reports array.length including + // them :( + + for (var i = 0, len = count; i < len; ++i) { + // sidestep sparse entries + var doc = array[i]; + if (!doc) { + --count || fn(); + continue; + } + + ;(function (i) { + doc.validate(function (err) { + if (err && !error) { + // rewrite the key + err.key = self.key + '.' + i + '.' + err.key; + return fn(error = err); + } + --count || fn(); + }); + })(i); + } + }, scope); +}; + +/** + * Casts contents + * + * @param {Object} value + * @param {Document} document that triggers the casting + * @api private + */ + +DocumentArray.prototype.cast = function (value, doc, init, prev) { + var selected + , subdoc + , i + + if (!Array.isArray(value)) { + return this.cast([value], doc, init, prev); + } + + if (!(value instanceof MongooseDocumentArray)) { + value = new MongooseDocumentArray(value, this.path, doc); + } + + i = value.length; + + while (i--) { + if (!(value[i] instanceof Subdocument) && value[i]) { + if (init) { + selected || (selected = scopePaths(this, doc.$__.selected, init)); + subdoc = new this.casterConstructor(null, value, true, selected); + value[i] = subdoc.init(value[i]); + } else { + if (prev && (subdoc = prev.id(value[i]._id))) { + // handle resetting doc with existing id but differing data + // doc.array = [{ doc: 'val' }] + subdoc.set(value[i]); + } else { + subdoc = new this.casterConstructor(value[i], value); + } + + // if set() is hooked it will have no return value + // see gh-746 + value[i] = subdoc; + } + } + } + + return value; +} + +/*! + * Scopes paths selected in a query to this array. + * Necessary for proper default application of subdocument values. + * + * @param {DocumentArray} array - the array to scope `fields` paths + * @param {Object|undefined} fields - the root fields selected in the query + * @param {Boolean|undefined} init - if we are being created part of a query result + */ + +function scopePaths (array, fields, init) { + if (!(init && fields)) return undefined; + + var path = array.path + '.' + , keys = Object.keys(fields) + , i = keys.length + , selected = {} + , hasKeys + , key + + while (i--) { + key = keys[i]; + if (0 === key.indexOf(path)) { + hasKeys || (hasKeys = true); + selected[key.substring(path.length)] = fields[key]; + } + } + + return hasKeys && selected || undefined; +} + +/*! + * Module exports. + */ + +module.exports = DocumentArray; diff --git a/node_modules/mongoose/lib/schema/index.js b/node_modules/mongoose/lib/schema/index.js new file mode 100644 index 0000000..d1347ed --- /dev/null +++ b/node_modules/mongoose/lib/schema/index.js @@ -0,0 +1,28 @@ + +/*! + * Module exports. + */ + +exports.String = require('./string'); + +exports.Number = require('./number'); + +exports.Boolean = require('./boolean'); + +exports.DocumentArray = require('./documentarray'); + +exports.Array = require('./array'); + +exports.Buffer = require('./buffer'); + +exports.Date = require('./date'); + +exports.ObjectId = require('./objectid'); + +exports.Mixed = require('./mixed'); + +// alias + +exports.Oid = exports.ObjectId; +exports.Object = exports.Mixed; +exports.Bool = exports.Boolean; diff --git a/node_modules/mongoose/lib/schema/mixed.js b/node_modules/mongoose/lib/schema/mixed.js new file mode 100644 index 0000000..c34eb39 --- /dev/null +++ b/node_modules/mongoose/lib/schema/mixed.js @@ -0,0 +1,83 @@ + +/*! + * Module dependencies. + */ + +var SchemaType = require('../schematype'); +var utils = require('../utils'); + +/** + * Mixed SchemaType constructor. + * + * @param {String} path + * @param {Object} options + * @inherits SchemaType + * @api private + */ + +function Mixed (path, options) { + if (options && options.default) { + var def = options.default; + if (Array.isArray(def) && 0 === def.length) { + // make sure empty array defaults are handled + options.default = Array; + } else if (!options.shared && + utils.isObject(def) && + 0 === Object.keys(def).length) { + // prevent odd "shared" objects between documents + options.default = function () { + return {} + } + } + } + + SchemaType.call(this, path, options); +}; + +/*! + * Inherits from SchemaType. + */ + +Mixed.prototype.__proto__ = SchemaType.prototype; + +/** + * Required validator + * + * @api private + */ + +Mixed.prototype.checkRequired = function (val) { + return (val !== undefined) && (val !== null); +}; + +/** + * Casts `val` for Mixed. + * + * _this is a no-op_ + * + * @param {Object} value to cast + * @api private + */ + +Mixed.prototype.cast = function (val) { + return val; +}; + +/** + * Casts contents for queries. + * + * @param {String} $cond + * @param {any} [val] + * @api private + */ + +Mixed.prototype.castForQuery = function ($cond, val) { + if (arguments.length === 2) return val; + return $cond; +}; + +/*! + * Module exports. + */ + +module.exports = Mixed; diff --git a/node_modules/mongoose/lib/schema/number.js b/node_modules/mongoose/lib/schema/number.js new file mode 100644 index 0000000..29a372f --- /dev/null +++ b/node_modules/mongoose/lib/schema/number.js @@ -0,0 +1,256 @@ +/*! + * Module requirements. + */ + +var SchemaType = require('../schematype') + , CastError = SchemaType.CastError + , errorMessages = require('../error').messages + , utils = require('../utils') + , Document + +/** + * Number SchemaType constructor. + * + * @param {String} key + * @param {Object} options + * @inherits SchemaType + * @api private + */ + +function SchemaNumber (key, options) { + SchemaType.call(this, key, options, 'Number'); +}; + +/*! + * Inherits from SchemaType. + */ + +SchemaNumber.prototype.__proto__ = SchemaType.prototype; + +/** + * Required validator for number + * + * @api private + */ + +SchemaNumber.prototype.checkRequired = function checkRequired (value, doc) { + if (SchemaType._isRef(this, value, doc, true)) { + return null != value; + } else { + return typeof value == 'number' || value instanceof Number; + } +}; + +/** + * Sets a minimum number validator. + * + * ####Example: + * + * var s = new Schema({ n: { type: Number, min: 10 }) + * var M = db.model('M', s) + * var m = new M({ n: 9 }) + * m.save(function (err) { + * console.error(err) // validator error + * m.n = 10; + * m.save() // success + * }) + * + * // custom error messages + * // We can also use the special {MIN} token which will be replaced with the invalid value + * var min = [10, 'The value of path `{PATH}` ({VALUE}) is beneath the limit ({MIN}).']; + * var schema = new Schema({ n: { type: Number, min: min }) + * var M = mongoose.model('Measurement', schema); + * var s= new M({ n: 4 }); + * s.validate(function (err) { + * console.log(String(err)) // ValidationError: The value of path `n` (4) is beneath the limit (10). + * }) + * + * @param {Number} value minimum number + * @param {String} [message] optional custom error message + * @return {SchemaType} this + * @see Customized Error Messages #error_messages_MongooseError-messages + * @api public + */ + +SchemaNumber.prototype.min = function (value, message) { + if (this.minValidator) { + this.validators = this.validators.filter(function (v) { + return v[0] != this.minValidator; + }, this); + } + + if (null != value) { + var msg = message || errorMessages.Number.min; + msg = msg.replace(/{MIN}/, value); + this.validators.push([this.minValidator = function (v) { + return v === null || v >= value; + }, msg, 'min']); + } + + return this; +}; + +/** + * Sets a maximum number validator. + * + * ####Example: + * + * var s = new Schema({ n: { type: Number, max: 10 }) + * var M = db.model('M', s) + * var m = new M({ n: 11 }) + * m.save(function (err) { + * console.error(err) // validator error + * m.n = 10; + * m.save() // success + * }) + * + * // custom error messages + * // We can also use the special {MAX} token which will be replaced with the invalid value + * var max = [10, 'The value of path `{PATH}` ({VALUE}) exceeds the limit ({MAX}).']; + * var schema = new Schema({ n: { type: Number, max: max }) + * var M = mongoose.model('Measurement', schema); + * var s= new M({ n: 4 }); + * s.validate(function (err) { + * console.log(String(err)) // ValidationError: The value of path `n` (4) exceeds the limit (10). + * }) + * + * @param {Number} maximum number + * @param {String} [message] optional custom error message + * @return {SchemaType} this + * @see Customized Error Messages #error_messages_MongooseError-messages + * @api public + */ + +SchemaNumber.prototype.max = function (value, message) { + if (this.maxValidator) { + this.validators = this.validators.filter(function(v){ + return v[0] != this.maxValidator; + }, this); + } + + if (null != value) { + var msg = message || errorMessages.Number.max; + msg = msg.replace(/{MAX}/, value); + this.validators.push([this.maxValidator = function(v){ + return v === null || v <= value; + }, msg, 'max']); + } + + return this; +}; + +/** + * Casts to number + * + * @param {Object} value value to cast + * @param {Document} doc document that triggers the casting + * @param {Boolean} init + * @api private + */ + +SchemaNumber.prototype.cast = function (value, doc, init) { + if (SchemaType._isRef(this, value, doc, init)) { + // wait! we may need to cast this to a document + + if (null == value) { + return value; + } + + // lazy load + Document || (Document = require('./../document')); + + if (value instanceof Document) { + value.$__.wasPopulated = true; + return value; + } + + // setting a populated path + if ('number' == typeof value) { + return value; + } else if (Buffer.isBuffer(value) || !utils.isObject(value)) { + throw new CastError('number', value, this.path); + } + + // Handle the case where user directly sets a populated + // path to a plain object; cast to the Model used in + // the population query. + var path = doc.$__fullPath(this.path); + var owner = doc.ownerDocument ? doc.ownerDocument() : doc; + var pop = owner.populated(path, true); + var ret = new pop.options.model(value); + ret.$__.wasPopulated = true; + return ret; + } + + var val = value && value._id + ? value._id // documents + : value; + + if (!isNaN(val)){ + if (null === val) return val; + if ('' === val) return null; + if ('string' == typeof val) val = Number(val); + if (val instanceof Number) return val + if ('number' == typeof val) return val; + if (val.toString && !Array.isArray(val) && + val.toString() == Number(val)) { + return new Number(val) + } + } + + throw new CastError('number', value, this.path); +}; + +/*! + * ignore + */ + +function handleSingle (val) { + return this.cast(val) +} + +function handleArray (val) { + var self = this; + return val.map(function (m) { + return self.cast(m) + }); +} + +SchemaNumber.prototype.$conditionalHandlers = { + '$lt' : handleSingle + , '$lte': handleSingle + , '$gt' : handleSingle + , '$gte': handleSingle + , '$ne' : handleSingle + , '$in' : handleArray + , '$nin': handleArray + , '$mod': handleArray + , '$all': handleArray +}; + +/** + * Casts contents for queries. + * + * @param {String} $conditional + * @param {any} [value] + * @api private + */ + +SchemaNumber.prototype.castForQuery = function ($conditional, val) { + var handler; + if (arguments.length === 2) { + handler = this.$conditionalHandlers[$conditional]; + if (!handler) + throw new Error("Can't use " + $conditional + " with Number."); + return handler.call(this, val); + } else { + val = this.cast($conditional); + return val == null ? val : val + } +}; + +/*! + * Module exports. + */ + +module.exports = SchemaNumber; diff --git a/node_modules/mongoose/lib/schema/objectid.js b/node_modules/mongoose/lib/schema/objectid.js new file mode 100644 index 0000000..664f686 --- /dev/null +++ b/node_modules/mongoose/lib/schema/objectid.js @@ -0,0 +1,186 @@ +/*! + * Module dependencies. + */ + +var SchemaType = require('../schematype') + , CastError = SchemaType.CastError + , driver = global.MONGOOSE_DRIVER_PATH || './../drivers/node-mongodb-native' + , oid = require('../types/objectid') + , utils = require('../utils') + , Document + +/** + * ObjectId SchemaType constructor. + * + * @param {String} key + * @param {Object} options + * @inherits SchemaType + * @api private + */ + +function ObjectId (key, options) { + SchemaType.call(this, key, options, 'ObjectID'); +}; + +/*! + * Inherits from SchemaType. + */ + +ObjectId.prototype.__proto__ = SchemaType.prototype; + +/** + * Adds an auto-generated ObjectId default if turnOn is true. + * @param {Boolean} turnOn auto generated ObjectId defaults + * @api public + * @return {SchemaType} this + */ + +ObjectId.prototype.auto = function (turnOn) { + if (turnOn) { + this.default(defaultId); + this.set(resetId) + } + + return this; +}; + +/** + * Check required + * + * @api private + */ + +ObjectId.prototype.checkRequired = function checkRequired (value, doc) { + if (SchemaType._isRef(this, value, doc, true)) { + return null != value; + } else { + return value instanceof oid; + } +}; + +/** + * Casts to ObjectId + * + * @param {Object} value + * @param {Object} doc + * @param {Boolean} init whether this is an initialization cast + * @api private + */ + +ObjectId.prototype.cast = function (value, doc, init) { + if (SchemaType._isRef(this, value, doc, init)) { + // wait! we may need to cast this to a document + + if (null == value) { + return value; + } + + // lazy load + Document || (Document = require('./../document')); + + if (value instanceof Document) { + value.$__.wasPopulated = true; + return value; + } + + // setting a populated path + if (value instanceof oid) { + return value; + } else if (Buffer.isBuffer(value) || !utils.isObject(value)) { + throw new CastError('ObjectId', value, this.path); + } + + // Handle the case where user directly sets a populated + // path to a plain object; cast to the Model used in + // the population query. + var path = doc.$__fullPath(this.path); + var owner = doc.ownerDocument ? doc.ownerDocument() : doc; + var pop = owner.populated(path, true); + var ret = new pop.options.model(value); + ret.$__.wasPopulated = true; + return ret; + } + + if (value === null) return value; + + if (value instanceof oid) + return value; + + if (value._id && value._id instanceof oid) + return value._id; + + if (value.toString) { + try { + return oid.createFromHexString(value.toString()); + } catch (err) { + throw new CastError('ObjectId', value, this.path); + } + } + + throw new CastError('ObjectId', value, this.path); +}; + +/*! + * ignore + */ + +function handleSingle (val) { + return this.cast(val); +} + +function handleArray (val) { + var self = this; + return val.map(function (m) { + return self.cast(m); + }); +} + +ObjectId.prototype.$conditionalHandlers = { + '$ne': handleSingle + , '$in': handleArray + , '$nin': handleArray + , '$gt': handleSingle + , '$lt': handleSingle + , '$gte': handleSingle + , '$lte': handleSingle + , '$all': handleArray +}; + +/** + * Casts contents for queries. + * + * @param {String} $conditional + * @param {any} [val] + * @api private + */ + +ObjectId.prototype.castForQuery = function ($conditional, val) { + var handler; + if (arguments.length === 2) { + handler = this.$conditionalHandlers[$conditional]; + if (!handler) + throw new Error("Can't use " + $conditional + " with ObjectId."); + return handler.call(this, val); + } else { + return this.cast($conditional); + } +}; + +/*! + * ignore + */ + +function defaultId () { + return new oid(); +}; + +function resetId (v) { + this.$__._id = null; + return v; +} + +/*! + * Module exports. + */ + +module.exports = ObjectId; diff --git a/node_modules/mongoose/lib/schema/string.js b/node_modules/mongoose/lib/schema/string.js new file mode 100644 index 0000000..e4b9d37 --- /dev/null +++ b/node_modules/mongoose/lib/schema/string.js @@ -0,0 +1,356 @@ + +/*! + * Module dependencies. + */ + +var SchemaType = require('../schematype') + , CastError = SchemaType.CastError + , errorMessages = require('../error').messages + , utils = require('../utils') + , Document + +/** + * String SchemaType constructor. + * + * @param {String} key + * @param {Object} options + * @inherits SchemaType + * @api private + */ + +function SchemaString (key, options) { + this.enumValues = []; + this.regExp = null; + SchemaType.call(this, key, options, 'String'); +}; + +/*! + * Inherits from SchemaType. + */ + +SchemaString.prototype.__proto__ = SchemaType.prototype; + +/** + * Adds an enum validator + * + * ####Example: + * + * var states = 'opening open closing closed'.split(' ') + * var s = new Schema({ state: { type: String, enum: states }}) + * var M = db.model('M', s) + * var m = new M({ state: 'invalid' }) + * m.save(function (err) { + * console.error(String(err)) // ValidationError: `invalid` is not a valid enum value for path `state`. + * m.state = 'open' + * m.save(callback) // success + * }) + * + * // or with custom error messages + * var enu = { + * values: 'opening open closing closed'.split(' '), + * message: 'enum validator failed for path `{PATH}` with value `{VALUE}`' + * } + * var s = new Schema({ state: { type: String, enum: enu }) + * var M = db.model('M', s) + * var m = new M({ state: 'invalid' }) + * m.save(function (err) { + * console.error(String(err)) // ValidationError: enum validator failed for path `state` with value `invalid` + * m.state = 'open' + * m.save(callback) // success + * }) + * + * @param {String|Object} [args...] enumeration values + * @return {SchemaType} this + * @see Customized Error Messages #error_messages_MongooseError-messages + * @api public + */ + +SchemaString.prototype.enum = function () { + var len = arguments.length; + + if (this.enumValidator) { + this.validators = this.validators.filter(function(v){ + return v[0] != this.enumValidator; + }, this); + this.enumValidator = false; + } + + if (undefined === arguments[0] || false === arguments[0]) { + return this; + } + + var values; + if (utils.isObject(arguments[0])) { + values = arguments[0].values; + errorMessage = arguments[0].message; + } else { + values = arguments; + errorMessage = errorMessages.String.enum; + } + + for (var i = 0; i < len; i++) { + if (undefined !== values[i]) { + this.enumValues.push(this.cast(values[i])); + } + } + + var vals = this.enumValues; + this.enumValidator = function (v) { + return undefined === v || ~vals.indexOf(v); + }; + this.validators.push([this.enumValidator, errorMessage, 'enum']); + + return this; +}; + +/** + * Adds a lowercase setter. + * + * ####Example: + * + * var s = new Schema({ email: { type: String, lowercase: true }}) + * var M = db.model('M', s); + * var m = new M({ email: 'SomeEmail@example.COM' }); + * console.log(m.email) // someemail@example.com + * + * @api public + * @return {SchemaType} this + */ + +SchemaString.prototype.lowercase = function () { + return this.set(function (v, self) { + if ('string' != typeof v) v = self.cast(v) + if (v) return v.toLowerCase(); + return v; + }); +}; + +/** + * Adds an uppercase setter. + * + * ####Example: + * + * var s = new Schema({ caps: { type: String, uppercase: true }}) + * var M = db.model('M', s); + * var m = new M({ caps: 'an example' }); + * console.log(m.caps) // AN EXAMPLE + * + * @api public + * @return {SchemaType} this + */ + +SchemaString.prototype.uppercase = function () { + return this.set(function (v, self) { + if ('string' != typeof v) v = self.cast(v) + if (v) return v.toUpperCase(); + return v; + }); +}; + +/** + * Adds a trim setter. + * + * The string value will be trimmed when set. + * + * ####Example: + * + * var s = new Schema({ name: { type: String, trim: true }}) + * var M = db.model('M', s) + * var string = ' some name ' + * console.log(string.length) // 11 + * var m = new M({ name: string }) + * console.log(m.name.length) // 9 + * + * @api public + * @return {SchemaType} this + */ + +SchemaString.prototype.trim = function () { + return this.set(function (v, self) { + if ('string' != typeof v) v = self.cast(v) + if (v) return v.trim(); + return v; + }); +}; + +/** + * Sets a regexp validator. + * + * Any value that does not pass `regExp`.test(val) will fail validation. + * + * ####Example: + * + * var s = new Schema({ name: { type: String, match: /^a/ }}) + * var M = db.model('M', s) + * var m = new M({ name: 'I am invalid' }) + * m.validate(function (err) { + * console.error(String(err)) // "ValidationError: Path `name` is invalid (I am invalid)." + * m.name = 'apples' + * m.validate(function (err) { + * assert.ok(err) // success + * }) + * }) + * + * // using a custom error message + * var match = [ /\.html$/, "That file doesn't end in .html ({VALUE})" ]; + * var s = new Schema({ file: { type: String, match: match }}) + * var M = db.model('M', s); + * var m = new M({ file: 'invalid' }); + * m.validate(function (err) { + * console.log(String(err)) // "ValidationError: That file doesn't end in .html (invalid)" + * }) + * + * Empty strings, `undefined`, and `null` values always pass the match validator. If you require these values, enable the `required` validator also. + * + * var s = new Schema({ name: { type: String, match: /^a/, required: true }}) + * + * @param {RegExp} regExp regular expression to test against + * @param {String} [message] optional custom error message + * @return {SchemaType} this + * @see Customized Error Messages #error_messages_MongooseError-messages + * @api public + */ + +SchemaString.prototype.match = function match (regExp, message) { + // yes, we allow multiple match validators + + var msg = message || errorMessages.String.match; + + function matchValidator (v){ + return null != v && '' !== v + ? regExp.test(v) + : true + } + + this.validators.push([matchValidator, msg, 'regexp']); + return this; +}; + +/** + * Check required + * + * @param {String|null|undefined} value + * @api private + */ + +SchemaString.prototype.checkRequired = function checkRequired (value, doc) { + if (SchemaType._isRef(this, value, doc, true)) { + return null != value; + } else { + return (value instanceof String || typeof value == 'string') && value.length; + } +}; + +/** + * Casts to String + * + * @api private + */ + +SchemaString.prototype.cast = function (value, doc, init) { + if (SchemaType._isRef(this, value, doc, init)) { + // wait! we may need to cast this to a document + + if (null == value) { + return value; + } + + // lazy load + Document || (Document = require('./../document')); + + if (value instanceof Document) { + value.$__.wasPopulated = true; + return value; + } + + // setting a populated path + if ('string' == typeof value) { + return value; + } else if (Buffer.isBuffer(value) || !utils.isObject(value)) { + throw new CastError('string', value, this.path); + } + + // Handle the case where user directly sets a populated + // path to a plain object; cast to the Model used in + // the population query. + var path = doc.$__fullPath(this.path); + var owner = doc.ownerDocument ? doc.ownerDocument() : doc; + var pop = owner.populated(path, true); + var ret = new pop.options.model(value); + ret.$__.wasPopulated = true; + return ret; + } + + if (value === null) { + return value; + } + + if ('undefined' !== typeof value) { + // handle documents being passed + if (value._id && 'string' == typeof value._id) { + return value._id; + } + if (value.toString) { + return value.toString(); + } + } + + + throw new CastError('string', value, this.path); +}; + +/*! + * ignore + */ + +function handleSingle (val) { + return this.castForQuery(val); +} + +function handleArray (val) { + var self = this; + return val.map(function (m) { + return self.castForQuery(m); + }); +} + +SchemaString.prototype.$conditionalHandlers = { + '$ne' : handleSingle + , '$in' : handleArray + , '$nin': handleArray + , '$gt' : handleSingle + , '$lt' : handleSingle + , '$gte': handleSingle + , '$lte': handleSingle + , '$all': handleArray + , '$regex': handleSingle + , '$options': handleSingle +}; + +/** + * Casts contents for queries. + * + * @param {String} $conditional + * @param {any} [val] + * @api private + */ + +SchemaString.prototype.castForQuery = function ($conditional, val) { + var handler; + if (arguments.length === 2) { + handler = this.$conditionalHandlers[$conditional]; + if (!handler) + throw new Error("Can't use " + $conditional + " with String."); + return handler.call(this, val); + } else { + val = $conditional; + if (val instanceof RegExp) return val; + return this.cast(val); + } +}; + +/*! + * Module exports. + */ + +module.exports = SchemaString; diff --git a/node_modules/mongoose/lib/schemadefault.js b/node_modules/mongoose/lib/schemadefault.js new file mode 100644 index 0000000..aebcff5 --- /dev/null +++ b/node_modules/mongoose/lib/schemadefault.js @@ -0,0 +1,34 @@ + +/*! + * Module dependencies. + */ + +var Schema = require('./schema') + +/** + * Default model for querying the system.profiles collection. + * + * @property system.profile + * @receiver exports + * @api private + */ + +exports['system.profile'] = new Schema({ + ts: Date + , info: String // deprecated + , millis: Number + , op: String + , ns: String + , query: Schema.Types.Mixed + , updateobj: Schema.Types.Mixed + , ntoreturn: Number + , nreturned: Number + , nscanned: Number + , responseLength: Number + , client: String + , user: String + , idhack: Boolean + , scanAndOrder: Boolean + , keyUpdates: Number + , cursorid: Number +}, { noVirtualId: true, noId: true }); diff --git a/node_modules/mongoose/lib/schematype.js b/node_modules/mongoose/lib/schematype.js new file mode 100644 index 0000000..5030215 --- /dev/null +++ b/node_modules/mongoose/lib/schematype.js @@ -0,0 +1,678 @@ +/*! + * Module dependencies. + */ + +var utils = require('./utils'); +var error = require('./error'); +var errorMessages = error.messages; +var CastError = error.CastError; +var ValidatorError = error.ValidatorError; + +/** + * SchemaType constructor + * + * @param {String} path + * @param {Object} [options] + * @param {String} [instance] + * @api public + */ + +function SchemaType (path, options, instance) { + this.path = path; + this.instance = instance; + this.validators = []; + this.setters = []; + this.getters = []; + this.options = options; + this._index = null; + this.selected; + + for (var i in options) if (this[i] && 'function' == typeof this[i]) { + // { unique: true, index: true } + if ('index' == i && this._index) continue; + + var opts = Array.isArray(options[i]) + ? options[i] + : [options[i]]; + + this[i].apply(this, opts); + } +}; + +/** + * Sets a default value for this SchemaType. + * + * ####Example: + * + * var schema = new Schema({ n: { type: Number, default: 10 }) + * var M = db.model('M', schema) + * var m = new M; + * console.log(m.n) // 10 + * + * Defaults can be either `functions` which return the value to use as the default or the literal value itself. Either way, the value will be cast based on its schema type before being set during document creation. + * + * ####Example: + * + * // values are cast: + * var schema = new Schema({ aNumber: Number, default: "4.815162342" }) + * var M = db.model('M', schema) + * var m = new M; + * console.log(m.aNumber) // 4.815162342 + * + * // default unique objects for Mixed types: + * var schema = new Schema({ mixed: Schema.Types.Mixed }); + * schema.path('mixed').default(function () { + * return {}; + * }); + * + * // if we don't use a function to return object literals for Mixed defaults, + * // each document will receive a reference to the same object literal creating + * // a "shared" object instance: + * var schema = new Schema({ mixed: Schema.Types.Mixed }); + * schema.path('mixed').default({}); + * var M = db.model('M', schema); + * var m1 = new M; + * m1.mixed.added = 1; + * console.log(m1.mixed); // { added: 1 } + * var m2 = new M; + * console.log(m2.mixed); // { added: 1 } + * + * @param {Function|any} val the default value + * @return {defaultValue} + * @api public + */ + +SchemaType.prototype.default = function (val) { + if (1 === arguments.length) { + this.defaultValue = typeof val === 'function' + ? val + : this.cast(val); + return this; + } else if (arguments.length > 1) { + this.defaultValue = utils.args(arguments); + } + return this.defaultValue; +}; + +/** + * Declares the index options for this schematype. + * + * ####Example: + * + * var s = new Schema({ name: { type: String, index: true }) + * var s = new Schema({ loc: { type: [Number], index: 'hashed' }) + * var s = new Schema({ loc: { type: [Number], index: '2d', sparse: true }) + * var s = new Schema({ loc: { type: [Number], index: { type: '2dsphere', sparse: true }}) + * var s = new Schema({ date: { type: Date, index: { unique: true, expires: '1d' }}) + * Schema.path('my.path').index(true); + * Schema.path('my.date').index({ expires: 60 }); + * Schema.path('my.path').index({ unique: true, sparse: true }); + * + * ####NOTE: + * + * _Indexes are created in the background by default. Specify `background: false` to override._ + * + * [Direction doesn't matter for single key indexes](http://www.mongodb.org/display/DOCS/Indexes#Indexes-CompoundKeysIndexes) + * + * @param {Object|Boolean|String} options + * @return {SchemaType} this + * @api public + */ + +SchemaType.prototype.index = function (options) { + this._index = options; + utils.expires(this._index); + return this; +}; + +/** + * Declares an unique index. + * + * ####Example: + * + * var s = new Schema({ name: { type: String, unique: true }) + * Schema.path('name').index({ unique: true }); + * + * _NOTE: violating the constraint returns an `E11000` error from MongoDB when saving, not a Mongoose validation error._ + * + * @param {Boolean} bool + * @return {SchemaType} this + * @api public + */ + +SchemaType.prototype.unique = function (bool) { + if (null == this._index || 'boolean' == typeof this._index) { + this._index = {}; + } else if ('string' == typeof this._index) { + this._index = { type: this._index }; + } + + this._index.unique = bool; + return this; +}; + +/** + * Declares a sparse index. + * + * ####Example: + * + * var s = new Schema({ name: { type: String, sparse: true }) + * Schema.path('name').index({ sparse: true }); + * + * @param {Boolean} bool + * @return {SchemaType} this + * @api public + */ + +SchemaType.prototype.sparse = function (bool) { + if (null == this._index || 'boolean' == typeof this._index) { + this._index = {}; + } else if ('string' == typeof this._index) { + this._index = { type: this._index }; + } + + this._index.sparse = bool; + return this; +}; + +/** + * Adds a setter to this schematype. + * + * ####Example: + * + * function capitalize (val) { + * if ('string' != typeof val) val = ''; + * return val.charAt(0).toUpperCase() + val.substring(1); + * } + * + * // defining within the schema + * var s = new Schema({ name: { type: String, set: capitalize }}) + * + * // or by retreiving its SchemaType + * var s = new Schema({ name: String }) + * s.path('name').set(capitalize) + * + * Setters allow you to transform the data before it gets to the raw mongodb document and is set as a value on an actual key. + * + * Suppose you are implementing user registration for a website. Users provide an email and password, which gets saved to mongodb. The email is a string that you will want to normalize to lower case, in order to avoid one email having more than one account -- e.g., otherwise, avenue@q.com can be registered for 2 accounts via avenue@q.com and AvEnUe@Q.CoM. + * + * You can set up email lower case normalization easily via a Mongoose setter. + * + * function toLower (v) { + * return v.toLowerCase(); + * } + * + * var UserSchema = new Schema({ + * email: { type: String, set: toLower } + * }) + * + * var User = db.model('User', UserSchema) + * + * var user = new User({email: 'AVENUE@Q.COM'}) + * console.log(user.email); // 'avenue@q.com' + * + * // or + * var user = new User + * user.email = 'Avenue@Q.com' + * console.log(user.email) // 'avenue@q.com' + * + * As you can see above, setters allow you to transform the data before it gets to the raw mongodb document and is set as a value on an actual key. + * + * _NOTE: we could have also just used the built-in `lowercase: true` SchemaType option instead of defining our own function._ + * + * new Schema({ email: { type: String, lowercase: true }}) + * + * Setters are also passed a second argument, the schematype on which the setter was defined. This allows for tailored behavior based on options passed in the schema. + * + * function inspector (val, schematype) { + * if (schematype.options.required) { + * return schematype.path + ' is required'; + * } else { + * return val; + * } + * } + * + * var VirusSchema = new Schema({ + * name: { type: String, required: true, set: inspector }, + * taxonomy: { type: String, set: inspector } + * }) + * + * var Virus = db.model('Virus', VirusSchema); + * var v = new Virus({ name: 'Parvoviridae', taxonomy: 'Parvovirinae' }); + * + * console.log(v.name); // name is required + * console.log(v.taxonomy); // Parvovirinae + * + * @param {Function} fn + * @return {SchemaType} this + * @api public + */ + +SchemaType.prototype.set = function (fn) { + if ('function' != typeof fn) + throw new TypeError('A setter must be a function.'); + this.setters.push(fn); + return this; +}; + +/** + * Adds a getter to this schematype. + * + * ####Example: + * + * function dob (val) { + * if (!val) return val; + * return (val.getMonth() + 1) + "/" + val.getDate() + "/" + val.getFullYear(); + * } + * + * // defining within the schema + * var s = new Schema({ born: { type: Date, get: dob }) + * + * // or by retreiving its SchemaType + * var s = new Schema({ born: Date }) + * s.path('born').get(dob) + * + * Getters allow you to transform the representation of the data as it travels from the raw mongodb document to the value that you see. + * + * Suppose you are storing credit card numbers and you want to hide everything except the last 4 digits to the mongoose user. You can do so by defining a getter in the following way: + * + * function obfuscate (cc) { + * return '****-****-****-' + cc.slice(cc.length-4, cc.length); + * } + * + * var AccountSchema = new Schema({ + * creditCardNumber: { type: String, get: obfuscate } + * }); + * + * var Account = db.model('Account', AccountSchema); + * + * Account.findById(id, function (err, found) { + * console.log(found.creditCardNumber); // '****-****-****-1234' + * }); + * + * Getters are also passed a second argument, the schematype on which the getter was defined. This allows for tailored behavior based on options passed in the schema. + * + * function inspector (val, schematype) { + * if (schematype.options.required) { + * return schematype.path + ' is required'; + * } else { + * return schematype.path + ' is not'; + * } + * } + * + * var VirusSchema = new Schema({ + * name: { type: String, required: true, get: inspector }, + * taxonomy: { type: String, get: inspector } + * }) + * + * var Virus = db.model('Virus', VirusSchema); + * + * Virus.findById(id, function (err, virus) { + * console.log(virus.name); // name is required + * console.log(virus.taxonomy); // taxonomy is not + * }) + * + * @param {Function} fn + * @return {SchemaType} this + * @api public + */ + +SchemaType.prototype.get = function (fn) { + if ('function' != typeof fn) + throw new TypeError('A getter must be a function.'); + this.getters.push(fn); + return this; +}; + +/** + * Adds validator(s) for this document path. + * + * Validators always receive the value to validate as their first argument and must return `Boolean`. Returning `false` means validation failed. + * + * The error message argument is optional. If not passed, the [default generic error message template](#error_messages_MongooseError-messages) will be used. + * + * ####Examples: + * + * // make sure every value is equal to "something" + * function validator (val) { + * return val == 'something'; + * } + * new Schema({ name: { type: String, validate: validator }}); + * + * // with a custom error message + * + * var custom = [validator, 'Uh oh, {PATH} does not equal "something".'] + * new Schema({ name: { type: String, validate: custom }}); + * + * // adding many validators at a time + * + * var many = [ + * { validator: validator, msg: 'uh oh' } + * , { validator: anotherValidator, msg: 'failed' } + * ] + * new Schema({ name: { type: String, validate: many }}); + * + * // or utilizing SchemaType methods directly: + * + * var schema = new Schema({ name: 'string' }); + * schema.path('name').validate(validator, 'validation of `{PATH}` failed with value `{VALUE}`'); + * + * ####Error message templates: + * + * From the examples above, you may have noticed that error messages support baseic templating. There are a few other template keywords besides `{PATH}` and `{VALUE}` too. To find out more, details are available [here](#error_messages_MongooseError-messages) + * + * ####Asynchronous validation: + * + * Passing a validator function that receives two arguments tells mongoose that the validator is an asynchronous validator. The first argument passed to the validator function is the value being validated. The second argument is a callback function that must called when you finish validating the value and passed either `true` or `false` to communicate either success or failure respectively. + * + * schema.path('name').validate(function (value, respond) { + * doStuff(value, function () { + * ... + * respond(false); // validation failed + * }) +* }, '{PATH} failed validation.'); +* + * You might use asynchronous validators to retreive other documents from the database to validate against or to meet other I/O bound validation needs. + * + * Validation occurs `pre('save')` or whenever you manually execute [document#validate](#document_Document-validate). + * + * If validation fails during `pre('save')` and no callback was passed to receive the error, an `error` event will be emitted on your Models associated db [connection](#connection_Connection), passing the validation error object along. + * + * var conn = mongoose.createConnection(..); + * conn.on('error', handleError); + * + * var Product = conn.model('Product', yourSchema); + * var dvd = new Product(..); + * dvd.save(); // emits error on the `conn` above + * + * If you desire handling these errors at the Model level, attach an `error` listener to your Model and the event will instead be emitted there. + * + * // registering an error listener on the Model lets us handle errors more locally + * Product.on('error', handleError); + * + * @param {RegExp|Function|Object} obj validator + * @param {String} [errorMsg] optional error message + * @return {SchemaType} this + * @api public + */ + +SchemaType.prototype.validate = function (obj, message) { + if ('function' == typeof obj || obj && 'RegExp' === obj.constructor.name) { + if (!message) message = errorMessages.general.default; + this.validators.push([obj, message, 'user defined']); + return this; + } + + var i = arguments.length + , arg + + while (i--) { + arg = arguments[i]; + if (!(arg && 'Object' == arg.constructor.name)) { + var msg = 'Invalid validator. Received (' + typeof arg + ') ' + + arg + + '. See http://mongoosejs.com/docs/api.html#schematype_SchemaType-validate'; + + throw new Error(msg); + } + this.validate(arg.validator, arg.msg); + } + + return this; +}; + +/** + * Adds a required validator to this schematype. + * + * ####Example: + * + * var s = new Schema({ born: { type: Date, required: true }) + * + * // or with custom error message + * + * var s = new Schema({ born: { type: Date, required: '{PATH} is required!' }) + * + * // or through the path API + * + * Schema.path('name').required(true); + * + * // with custom error messaging + * + * Schema.path('name').required(true, 'grrr :( '); + * + * + * @param {Boolean} required enable/disable the validator + * @param {String} [message] optional custom error message + * @return {SchemaType} this + * @see Customized Error Messages #error_messages_MongooseError-messages + * @api public + */ + +SchemaType.prototype.required = function (required, message) { + if (false === required) { + this.validators = this.validators.filter(function (v) { + return v[0] != this.requiredValidator; + }, this); + + this.isRequired = false; + return this; + } + + var self = this; + this.isRequired = true; + + this.requiredValidator = function (v) { + // in here, `this` refers to the validating document. + // no validation when this path wasn't selected in the query. + if ('isSelected' in this && + !this.isSelected(self.path) && + !this.isModified(self.path)) return true; + return self.checkRequired(v, this); + } + + if ('string' == typeof required) { + message = required; + required = undefined; + } + + var msg = message || errorMessages.general.required; + this.validators.push([this.requiredValidator, msg, 'required']); + + return this; +}; + +/** + * Gets the default value + * + * @param {Object} scope the scope which callback are executed + * @param {Boolean} init + * @api private + */ + +SchemaType.prototype.getDefault = function (scope, init) { + var ret = 'function' === typeof this.defaultValue + ? this.defaultValue.call(scope) + : this.defaultValue; + + if (null !== ret && undefined !== ret) { + return this.cast(ret, scope, init); + } else { + return ret; + } +}; + +/** + * Applies setters + * + * @param {Object} value + * @param {Object} scope + * @param {Boolean} init + * @api private + */ + +SchemaType.prototype.applySetters = function (value, scope, init, priorVal) { + if (SchemaType._isRef(this, value, scope, init)) { + return init + ? value + : this.cast(value, scope, init, priorVal); + } + + var v = value + , setters = this.setters + , len = setters.length + + if (!len) { + if (null === v || undefined === v) return v; + return this.cast(v, scope, init, priorVal) + } + + while (len--) { + v = setters[len].call(scope, v, this); + } + + if (null === v || undefined === v) return v; + + // do not cast until all setters are applied #665 + v = this.cast(v, scope, init, priorVal); + + return v; +}; + +/** + * Applies getters to a value + * + * @param {Object} value + * @param {Object} scope + * @api private + */ + +SchemaType.prototype.applyGetters = function (value, scope) { + if (SchemaType._isRef(this, value, scope, true)) return value; + + var v = value + , getters = this.getters + , len = getters.length; + + if (!len) { + return v; + } + + while (len--) { + v = getters[len].call(scope, v, this); + } + + return v; +}; + +/** + * Sets default `select()` behavior for this path. + * + * Set to `true` if this path should always be included in the results, `false` if it should be excluded by default. This setting can be overridden at the query level. + * + * ####Example: + * + * T = db.model('T', new Schema({ x: { type: String, select: true }})); + * T.find(..); // field x will always be selected .. + * // .. unless overridden; + * T.find().select('-x').exec(callback); + * + * @param {Boolean} val + * @return {SchemaType} this + * @api public + */ + +SchemaType.prototype.select = function select (val) { + this.selected = !! val; + return this; +} + +/** + * Performs a validation of `value` using the validators declared for this SchemaType. + * + * @param {any} value + * @param {Function} callback + * @param {Object} scope + * @api private + */ + +SchemaType.prototype.doValidate = function (value, fn, scope) { + var err = false + , path = this.path + , count = this.validators.length; + + if (!count) return fn(null); + + function validate (ok, message, type, val) { + if (err) return; + if (ok === undefined || ok) { + --count || fn(null); + } else { + fn(err = new ValidatorError(path, message, type, val)); + } + } + + this.validators.forEach(function (v) { + var validator = v[0] + , message = v[1] + , type = v[2]; + + if (validator instanceof RegExp) { + validate(validator.test(value), message, type, value); + } else if ('function' === typeof validator) { + if (2 === validator.length) { + validator.call(scope, value, function (ok) { + validate(ok, message, type, value); + }); + } else { + validate(validator.call(scope, value), message, type, value); + } + } + }); +}; + +/** + * Determines if value is a valid Reference. + * + * @param {SchemaType} self + * @param {Object} value + * @param {Document} doc + * @param {Boolean} init + * @return {Boolean} + * @api private + */ + +SchemaType._isRef = function (self, value, doc, init) { + // fast path + var ref = init && self.options && self.options.ref; + + if (!ref && doc && doc.$__fullPath) { + // checks for + // - this populated with adhoc model and no ref was set in schema OR + // - setting / pushing values after population + var path = doc.$__fullPath(self.path); + var owner = doc.ownerDocument ? doc.ownerDocument() : doc; + ref = owner.populated(path); + } + + if (ref) { + if (null == value) return true; + if (!Buffer.isBuffer(value) && // buffers are objects too + 'Binary' != value._bsontype // raw binary value from the db + && utils.isObject(value) // might have deselected _id in population query + ) { + return true; + } + } + + return false; +} + +/*! + * Module exports. + */ + +module.exports = exports = SchemaType; + +exports.CastError = CastError; + +exports.ValidatorError = ValidatorError; diff --git a/node_modules/mongoose/lib/statemachine.js b/node_modules/mongoose/lib/statemachine.js new file mode 100644 index 0000000..76005d8 --- /dev/null +++ b/node_modules/mongoose/lib/statemachine.js @@ -0,0 +1,179 @@ + +/*! + * Module dependencies. + */ + +var utils = require('./utils'); + +/*! + * StateMachine represents a minimal `interface` for the + * constructors it builds via StateMachine.ctor(...). + * + * @api private + */ + +var StateMachine = module.exports = exports = function StateMachine () { + this.paths = {}; + this.states = {}; +} + +/*! + * StateMachine.ctor('state1', 'state2', ...) + * A factory method for subclassing StateMachine. + * The arguments are a list of states. For each state, + * the constructor's prototype gets state transition + * methods named after each state. These transition methods + * place their path argument into the given state. + * + * @param {String} state + * @param {String} [state] + * @return {Function} subclass constructor + * @private + */ + +StateMachine.ctor = function () { + var states = utils.args(arguments); + + var ctor = function () { + StateMachine.apply(this, arguments); + this.stateNames = states; + + var i = states.length + , state; + + while (i--) { + state = states[i]; + this.states[state] = {}; + } + }; + + ctor.prototype.__proto__ = StateMachine.prototype; + + states.forEach(function (state) { + // Changes the `path`'s state to `state`. + ctor.prototype[state] = function (path) { + this._changeState(path, state); + } + }); + + return ctor; +}; + +/*! + * This function is wrapped by the state change functions: + * + * - `require(path)` + * - `modify(path)` + * - `init(path)` + * + * @api private + */ + +StateMachine.prototype._changeState = function _changeState (path, nextState) { + var prevBucket = this.states[this.paths[path]]; + if (prevBucket) delete prevBucket[path]; + + this.paths[path] = nextState; + this.states[nextState][path] = true; +} + +/*! + * ignore + */ + +StateMachine.prototype.clear = function clear (state) { + var keys = Object.keys(this.states[state]) + , i = keys.length + , path + + while (i--) { + path = keys[i]; + delete this.states[state][path]; + delete this.paths[path]; + } +} + +/*! + * Checks to see if at least one path is in the states passed in via `arguments` + * e.g., this.some('required', 'inited') + * + * @param {String} state that we want to check for. + * @private + */ + +StateMachine.prototype.some = function some () { + var self = this; + var what = arguments.length ? arguments : this.stateNames; + return Array.prototype.some.call(what, function (state) { + return Object.keys(self.states[state]).length; + }); +} + +/*! + * This function builds the functions that get assigned to `forEach` and `map`, + * since both of those methods share a lot of the same logic. + * + * @param {String} iterMethod is either 'forEach' or 'map' + * @return {Function} + * @api private + */ + +StateMachine.prototype._iter = function _iter (iterMethod) { + return function () { + var numArgs = arguments.length + , states = utils.args(arguments, 0, numArgs-1) + , callback = arguments[numArgs-1]; + + if (!states.length) states = this.stateNames; + + var self = this; + + var paths = states.reduce(function (paths, state) { + return paths.concat(Object.keys(self.states[state])); + }, []); + + return paths[iterMethod](function (path, i, paths) { + return callback(path, i, paths); + }); + }; +} + +/*! + * Iterates over the paths that belong to one of the parameter states. + * + * The function profile can look like: + * this.forEach(state1, fn); // iterates over all paths in state1 + * this.forEach(state1, state2, fn); // iterates over all paths in state1 or state2 + * this.forEach(fn); // iterates over all paths in all states + * + * @param {String} [state] + * @param {String} [state] + * @param {Function} callback + * @private + */ + +StateMachine.prototype.forEach = function forEach () { + this.forEach = this._iter('forEach'); + return this.forEach.apply(this, arguments); +} + +/*! + * Maps over the paths that belong to one of the parameter states. + * + * The function profile can look like: + * this.forEach(state1, fn); // iterates over all paths in state1 + * this.forEach(state1, state2, fn); // iterates over all paths in state1 or state2 + * this.forEach(fn); // iterates over all paths in all states + * + * @param {String} [state] + * @param {String} [state] + * @param {Function} callback + * @return {Array} + * @private + */ + +StateMachine.prototype.map = function map () { + this.map = this._iter('map'); + return this.map.apply(this, arguments); +} + diff --git a/node_modules/mongoose/lib/types/array.js b/node_modules/mongoose/lib/types/array.js new file mode 100644 index 0000000..e0d7700 --- /dev/null +++ b/node_modules/mongoose/lib/types/array.js @@ -0,0 +1,679 @@ + +/*! + * Module dependencies. + */ + +var EmbeddedDocument = require('./embedded'); +var Document = require('../document'); +var ObjectId = require('./objectid'); +var utils = require('../utils'); +var isMongooseObject = utils.isMongooseObject; + +/** + * Mongoose Array constructor. + * + * ####NOTE: + * + * _Values always have to be passed to the constructor to initialize, otherwise `MongooseArray#push` will mark the array as modified._ + * + * @param {Array} values + * @param {String} path + * @param {Document} doc parent document + * @api private + * @inherits Array + * @see http://bit.ly/f6CnZU + */ + +function MongooseArray (values, path, doc) { + var arr = []; + arr.push.apply(arr, values); + arr.__proto__ = MongooseArray.prototype; + + arr._atomics = {}; + arr.validators = []; + arr._path = path; + + if (doc) { + arr._parent = doc; + arr._schema = doc.schema.path(path); + } + + return arr; +}; + +/*! + * Inherit from Array + */ + +MongooseArray.prototype = new Array; + +/** + * Stores a queue of atomic operations to perform + * + * @property _atomics + * @api private + */ + +MongooseArray.prototype._atomics; + +/** + * Parent owner document + * + * @property _parent + * @api private + */ + +MongooseArray.prototype._parent; + +/** + * Casts a member based on this arrays schema. + * + * @param {any} value + * @return value the casted value + * @api private + */ + +MongooseArray.prototype._cast = function (value) { + var owner = this._owner; + var populated = false; + var Model; + + if (this._parent) { + // if a populated array, we must cast to the same model + // instance as specified in the original query. + if (!owner) { + owner = this._owner = this._parent.ownerDocument + ? this._parent.ownerDocument() + : this._parent; + } + + populated = owner.populated(this._path, true); + } + + if (populated && null != value) { + // cast to the populated Models schema + var Model = populated.options.model; + + // only objects are permitted so we can safely assume that + // non-objects are to be interpreted as _id + if (Buffer.isBuffer(value) || + value instanceof ObjectId || !utils.isObject(value)) { + value = { _id: value }; + } + + value = new Model(value); + return this._schema.caster.cast(value, this._parent, true) + } + + return this._schema.caster.cast(value, this._parent, false) +} + +/** + * Marks this array as modified. + * + * If it bubbles up from an embedded document change, then it takes the following arguments (otherwise, takes 0 arguments) + * + * @param {EmbeddedDocument} embeddedDoc the embedded doc that invoked this method on the Array + * @param {String} embeddedPath the path which changed in the embeddedDoc + * @api private + */ + +MongooseArray.prototype._markModified = function (elem, embeddedPath) { + var parent = this._parent + , dirtyPath; + + if (parent) { + dirtyPath = this._path; + + if (arguments.length) { + if (null != embeddedPath) { + // an embedded doc bubbled up the change + dirtyPath = dirtyPath + '.' + this.indexOf(elem) + '.' + embeddedPath; + } else { + // directly set an index + dirtyPath = dirtyPath + '.' + elem; + } + } + parent.markModified(dirtyPath); + } + + return this; +}; + +/** + * Register an atomic operation with the parent. + * + * @param {Array} op operation + * @param {any} val + * @api private + */ + +MongooseArray.prototype._registerAtomic = function (op, val) { + if ('$set' == op) { + // $set takes precedence over all other ops. + // mark entire array modified. + this._atomics = { $set: val }; + return this; + } + + var atomics = this._atomics; + + // reset pop/shift after save + if ('$pop' == op && !('$pop' in atomics)) { + var self = this; + this._parent.once('save', function () { + self._popped = self._shifted = null; + }); + } + + // check for impossible $atomic combos (Mongo denies more than one + // $atomic op on a single path + if (this._atomics.$set || + Object.keys(atomics).length && !(op in atomics)) { + // a different op was previously registered. + // save the entire thing. + this._atomics = { $set: this }; + return this; + } + + if (op === '$pullAll' || op === '$pushAll' || op === '$addToSet') { + atomics[op] || (atomics[op] = []); + atomics[op] = atomics[op].concat(val); + } else if (op === '$pullDocs') { + var pullOp = atomics['$pull'] || (atomics['$pull'] = {}) + , selector = pullOp['_id'] || (pullOp['_id'] = {'$in' : [] }); + selector['$in'] = selector['$in'].concat(val); + } else { + atomics[op] = val; + } + + return this; +}; + +/** + * Depopulates stored atomic operation values as necessary for direct insertion to MongoDB. + * + * If no atomics exist, we return all array values after conversion. + * + * @return {Array} + * @method $__getAtomics + * @memberOf MongooseArray + * @api private + */ + +MongooseArray.prototype.$__getAtomics = function () { + var ret = []; + var keys = Object.keys(this._atomics); + var i = keys.length; + + if (0 === i) { + ret[0] = ['$set', this.toObject({ depopulate: 1 })]; + return ret; + } + + while (i--) { + var op = keys[i]; + var val = this._atomics[op]; + + // the atomic values which are arrays are not MongooseArrays. we + // need to convert their elements as if they were MongooseArrays + // to handle populated arrays versus DocumentArrays properly. + if (isMongooseObject(val)) { + val = val.toObject({ depopulate: 1 }); + } else if (Array.isArray(val)) { + val = this.toObject.call(val, { depopulate: 1 }); + } else if (val.valueOf) { + val = val.valueOf(); + } + + if ('$addToSet' == op) { + val = { $each: val } + } + + ret.push([op, val]); + } + + return ret; +} + +/** + * Returns the number of pending atomic operations to send to the db for this array. + * + * @api private + * @return {Number} + */ + +MongooseArray.prototype.hasAtomics = function hasAtomics () { + if (!(this._atomics && 'Object' === this._atomics.constructor.name)) { + return 0; + } + + return Object.keys(this._atomics).length; +} + +/** + * Wraps [`Array#push`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/push) with proper change tracking. + * + * @param {Object} [args...] + * @api public + */ + +MongooseArray.prototype.push = function () { + var values = [].map.call(arguments, this._cast, this) + , ret = [].push.apply(this, values); + + // $pushAll might be fibbed (could be $push). But it makes it easier to + // handle what could have been $push, $pushAll combos + this._registerAtomic('$pushAll', values); + this._markModified(); + return ret; +}; + +/** + * Pushes items to the array non-atomically. + * + * ####NOTE: + * + * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._ + * + * @param {any} [args...] + * @api public + */ + +MongooseArray.prototype.nonAtomicPush = function () { + var values = [].map.call(arguments, this._cast, this) + , ret = [].push.apply(this, values); + this._registerAtomic('$set', this); + this._markModified(); + return ret; +}; + +/** + * Pops the array atomically at most one time per document `save()`. + * + * #### NOTE: + * + * _Calling this mulitple times on an array before saving sends the same command as calling it once._ + * _This update is implemented using the MongoDB [$pop](http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pop) method which enforces this restriction._ + * + * doc.array = [1,2,3]; + * + * var popped = doc.array.$pop(); + * console.log(popped); // 3 + * console.log(doc.array); // [1,2] + * + * // no affect + * popped = doc.array.$pop(); + * console.log(doc.array); // [1,2] + * + * doc.save(function (err) { + * if (err) return handleError(err); + * + * // we saved, now $pop works again + * popped = doc.array.$pop(); + * console.log(popped); // 2 + * console.log(doc.array); // [1] + * }) + * + * @api public + * @method $pop + * @memberOf MongooseArray + * @see mongodb http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pop + */ + +MongooseArray.prototype.$pop = function () { + this._registerAtomic('$pop', 1); + this._markModified(); + + // only allow popping once + if (this._popped) return; + this._popped = true; + + return [].pop.call(this); +}; + +/** + * Wraps [`Array#pop`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/pop) with proper change tracking. + * + * ####Note: + * + * _marks the entire array as modified which will pass the entire thing to $set potentially overwritting any changes that happen between when you retrieved the object and when you save it._ + * + * @see MongooseArray#$pop #types_array_MongooseArray-%24pop + * @api public + */ + +MongooseArray.prototype.pop = function () { + var ret = [].pop.call(this); + this._registerAtomic('$set', this); + this._markModified(); + return ret; +}; + +/** + * Atomically shifts the array at most one time per document `save()`. + * + * ####NOTE: + * + * _Calling this mulitple times on an array before saving sends the same command as calling it once._ + * _This update is implemented using the MongoDB [$pop](http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pop) method which enforces this restriction._ + * + * doc.array = [1,2,3]; + * + * var shifted = doc.array.$shift(); + * console.log(shifted); // 1 + * console.log(doc.array); // [2,3] + * + * // no affect + * shifted = doc.array.$shift(); + * console.log(doc.array); // [2,3] + * + * doc.save(function (err) { + * if (err) return handleError(err); + * + * // we saved, now $shift works again + * shifted = doc.array.$shift(); + * console.log(shifted ); // 2 + * console.log(doc.array); // [3] + * }) + * + * @api public + * @memberOf MongooseArray + * @method $shift + * @see mongodb http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pop + */ + +MongooseArray.prototype.$shift = function $shift () { + this._registerAtomic('$pop', -1); + this._markModified(); + + // only allow shifting once + if (this._shifted) return; + this._shifted = true; + + return [].shift.call(this); +}; + +/** + * Wraps [`Array#shift`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/unshift) with proper change tracking. + * + * ####Example: + * + * doc.array = [2,3]; + * var res = doc.array.shift(); + * console.log(res) // 2 + * console.log(doc.array) // [3] + * + * ####Note: + * + * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._ + * + * @api public + */ + +MongooseArray.prototype.shift = function () { + var ret = [].shift.call(this); + this._registerAtomic('$set', this); + this._markModified(); + return ret; +}; + +/** + * Pulls items from the array atomically. + * + * ####Examples: + * + * doc.array.pull(ObjectId) + * doc.array.pull({ _id: 'someId' }) + * doc.array.pull(36) + * doc.array.pull('tag 1', 'tag 2') + * + * To remove a document from a subdocument array we may pass an object with a matching `_id`. + * + * doc.subdocs.push({ _id: 4815162342 }) + * doc.subdocs.pull({ _id: 4815162342 }) // removed + * + * Or we may passing the _id directly and let mongoose take care of it. + * + * doc.subdocs.push({ _id: 4815162342 }) + * doc.subdocs.pull(4815162342); // works + * + * @param {any} [args...] + * @see mongodb http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pull + * @api public + */ + +MongooseArray.prototype.pull = function () { + var values = [].map.call(arguments, this._cast, this) + , cur = this._parent.get(this._path) + , i = cur.length + , mem; + + while (i--) { + mem = cur[i]; + if (mem instanceof EmbeddedDocument) { + if (values.some(function (v) { return v.equals(mem); } )) { + [].splice.call(cur, i, 1); + } + } else if (~cur.indexOf.call(values, mem)) { + [].splice.call(cur, i, 1); + } + } + + if (values[0] instanceof EmbeddedDocument) { + this._registerAtomic('$pullDocs', values.map( function (v) { return v._id; } )); + } else { + this._registerAtomic('$pullAll', values); + } + + this._markModified(); + return this; +}; + +/** + * Alias of [pull](#types_array_MongooseArray-pull) + * + * @see MongooseArray#pull #types_array_MongooseArray-pull + * @see mongodb http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pull + * @api public + * @memberOf MongooseArray + * @method remove + */ + +MongooseArray.prototype.remove = MongooseArray.prototype.pull; + +/** + * Wraps [`Array#splice`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice) with proper change tracking and casting. + * + * ####Note: + * + * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._ + * + * @api public + */ + +MongooseArray.prototype.splice = function splice () { + var ret, vals, i; + + if (arguments.length) { + vals = []; + for (i = 0; i < arguments.length; ++i) { + vals[i] = i < 2 + ? arguments[i] + : this._cast(arguments[i]); + } + ret = [].splice.apply(this, vals); + this._registerAtomic('$set', this); + this._markModified(); + } + + return ret; +} + +/** + * Wraps [`Array#unshift`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/unshift) with proper change tracking. + * + * ####Note: + * + * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._ + * + * @api public + */ + +MongooseArray.prototype.unshift = function () { + var values = [].map.call(arguments, this._cast, this); + [].unshift.apply(this, values); + this._registerAtomic('$set', this); + this._markModified(); + return this.length; +}; + +/** + * Wraps [`Array#sort`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort) with proper change tracking. + * + * ####NOTE: + * + * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._ + * + * @api public + */ + +MongooseArray.prototype.sort = function () { + var ret = [].sort.apply(this, arguments); + this._registerAtomic('$set', this); + this._markModified(); + return ret; +} + +/** + * Adds values to the array if not already present. + * + * ####Example: + * + * console.log(doc.array) // [2,3,4] + * var added = doc.array.addToSet(4,5); + * console.log(doc.array) // [2,3,4,5] + * console.log(added) // [5] + * + * @param {any} [args...] + * @return {Array} the values that were added + * @api public + */ + +MongooseArray.prototype.addToSet = function addToSet () { + var values = [].map.call(arguments, this._cast, this) + , added = [] + , type = values[0] instanceof EmbeddedDocument ? 'doc' : + values[0] instanceof Date ? 'date' : + ''; + + values.forEach(function (v) { + var found; + switch (type) { + case 'doc': + found = this.some(function(doc){ return doc.equals(v) }); + break; + case 'date': + var val = +v; + found = this.some(function(d){ return +d === val }); + break; + default: + found = ~this.indexOf(v); + } + + if (!found) { + [].push.call(this, v); + this._registerAtomic('$addToSet', v); + this._markModified(); + [].push.call(added, v); + } + }, this); + + return added; +}; + +/** + * Sets the casted `val` at index `i` and marks the array modified. + * + * ####Example: + * + * // given documents based on the following + * var Doc = mongoose.model('Doc', new Schema({ array: [Number] })); + * + * var doc = new Doc({ array: [2,3,4] }) + * + * console.log(doc.array) // [2,3,4] + * + * doc.array.set(1,"5"); + * console.log(doc.array); // [2,5,4] // properly cast to number + * doc.save() // the change is saved + * + * // VS not using array#set + * doc.array[1] = "5"; + * console.log(doc.array); // [2,"5",4] // no casting + * doc.save() // change is not saved + * + * @return {Array} this + * @api public + */ + +MongooseArray.prototype.set = function set (i, val) { + this[i] = this._cast(val); + this._markModified(i); + return this; +} + +/** + * Returns a native js Array. + * + * @param {Object} options + * @return {Array} + * @api public + */ + +MongooseArray.prototype.toObject = function (options) { + if (options && options.depopulate) { + return this.map(function (doc) { + return doc instanceof Document + ? doc.toObject(options) + : doc + }); + } + + return this.slice(); +} + +/** + * Helper for console.log + * + * @api public + */ + +MongooseArray.prototype.inspect = function () { + return '[' + this.map(function (doc) { + return ' ' + doc; + }) + ' ]'; +}; + +/** + * Return the index of `obj` or `-1` if not found. + * + * @param {Object} obj the item to look for + * @return {Number} + * @api public + */ + +MongooseArray.prototype.indexOf = function indexOf (obj) { + if (obj instanceof ObjectId) obj = obj.toString(); + for (var i = 0, len = this.length; i < len; ++i) { + if (obj == this[i]) + return i; + } + return -1; +}; + +/*! + * Module exports. + */ + +module.exports = exports = MongooseArray; diff --git a/node_modules/mongoose/lib/types/buffer.js b/node_modules/mongoose/lib/types/buffer.js new file mode 100644 index 0000000..bb41e4b --- /dev/null +++ b/node_modules/mongoose/lib/types/buffer.js @@ -0,0 +1,255 @@ + +/*! + * Access driver. + */ + +var driver = global.MONGOOSE_DRIVER_PATH || '../drivers/node-mongodb-native'; + +/*! + * Module dependencies. + */ + +var Binary = require(driver + '/binary'); + +/** + * Mongoose Buffer constructor. + * + * Values always have to be passed to the constructor to initialize. + * + * @param {Buffer} value + * @param {String} encode + * @param {Number} offset + * @api private + * @inherits Buffer + * @see http://bit.ly/f6CnZU + */ + +function MongooseBuffer (value, encode, offset) { + var length = arguments.length; + var val; + + if (0 === length || null === arguments[0] || undefined === arguments[0]) { + val = 0; + } else { + val = value; + } + + var encoding; + var path; + var doc; + + if (Array.isArray(encode)) { + // internal casting + path = encode[0]; + doc = encode[1]; + } else { + encoding = encode; + } + + var buf = new Buffer(val, encoding, offset); + buf.__proto__ = MongooseBuffer.prototype; + + // make sure these internal props don't show up in Object.keys() + Object.defineProperties(buf, { + validators: { value: [] } + , _path: { value: path } + , _parent: { value: doc } + }); + + if (doc && "string" === typeof path) { + Object.defineProperty(buf, '_schema', { + value: doc.schema.path(path) + }); + } + + buf._subtype = 0; + return buf; +}; + +/*! + * Inherit from Buffer. + */ + +MongooseBuffer.prototype = new Buffer(0); + +/** + * Parent owner document + * + * @api private + * @property _parent + */ + +MongooseBuffer.prototype._parent; + +/** + * Default subtype for the Binary representing this Buffer + * + * @api private + * @property _subtype + */ + +MongooseBuffer.prototype._subtype; + +/** + * Marks this buffer as modified. + * + * @api private + */ + +MongooseBuffer.prototype._markModified = function () { + var parent = this._parent; + + if (parent) { + parent.markModified(this._path); + } + return this; +}; + +/** +* Writes the buffer. +*/ + +MongooseBuffer.prototype.write = function () { + var written = Buffer.prototype.write.apply(this, arguments); + + if (written > 0) { + this._markModified(); + } + + return written; +}; + +/** + * Copies the buffer. + * + * ####Note: + * + * `Buffer#copy` does not mark `target` as modified so you must copy from a `MongooseBuffer` for it to work as expected. This is a work around since `copy` modifies the target, not this. + * + * @return {MongooseBuffer} + * @param {Buffer} target + */ + +MongooseBuffer.prototype.copy = function (target) { + var ret = Buffer.prototype.copy.apply(this, arguments); + + if (target instanceof MongooseBuffer) { + target._markModified(); + } + + return ret; +}; + +/*! + * Compile other Buffer methods marking this buffer as modified. + */ + +;( +// node < 0.5 +'writeUInt8 writeUInt16 writeUInt32 writeInt8 writeInt16 writeInt32 ' + +'writeFloat writeDouble fill ' + +'utf8Write binaryWrite asciiWrite set ' + + +// node >= 0.5 +'writeUInt16LE writeUInt16BE writeUInt32LE writeUInt32BE ' + +'writeInt16LE writeInt16BE writeInt32LE writeInt32BE ' + +'writeFloatLE writeFloatBE writeDoubleLE writeDoubleBE' +).split(' ').forEach(function (method) { + if (!Buffer.prototype[method]) return; + MongooseBuffer.prototype[method] = new Function( + 'var ret = Buffer.prototype.'+method+'.apply(this, arguments);' + + 'this._markModified();' + + 'return ret;' + ) +}); + +/** + * Converts this buffer to its Binary type representation. + * + * ####SubTypes: + * + * var bson = require('bson') + * bson.BSON_BINARY_SUBTYPE_DEFAULT + * bson.BSON_BINARY_SUBTYPE_FUNCTION + * bson.BSON_BINARY_SUBTYPE_BYTE_ARRAY + * bson.BSON_BINARY_SUBTYPE_UUID + * bson.BSON_BINARY_SUBTYPE_MD5 + * bson.BSON_BINARY_SUBTYPE_USER_DEFINED + * + * doc.buffer.toObject(bson.BSON_BINARY_SUBTYPE_USER_DEFINED); + * + * @see http://bsonspec.org/#/specification + * @param {Hex} [subtype] + * @return {Binary} + * @api public + */ + +MongooseBuffer.prototype.toObject = function (options) { + var subtype = 'number' == typeof options + ? options + : (this._subtype || 0); + return new Binary(this, subtype); +}; + +/** + * Determines if this buffer is equals to `other` buffer + * + * @param {Buffer} other + * @return {Boolean} + */ + +MongooseBuffer.prototype.equals = function (other) { + if (!Buffer.isBuffer(other)) { + return false; + } + + if (this.length !== other.length) { + return false; + } + + for (var i = 0; i < this.length; ++i) { + if (this[i] !== other[i]) return false; + } + + return true; +} + +/** + * Sets the subtype option and marks the buffer modified. + * + * ####SubTypes: + * + * var bson = require('bson') + * bson.BSON_BINARY_SUBTYPE_DEFAULT + * bson.BSON_BINARY_SUBTYPE_FUNCTION + * bson.BSON_BINARY_SUBTYPE_BYTE_ARRAY + * bson.BSON_BINARY_SUBTYPE_UUID + * bson.BSON_BINARY_SUBTYPE_MD5 + * bson.BSON_BINARY_SUBTYPE_USER_DEFINED + * + * doc.buffer.subtype(bson.BSON_BINARY_SUBTYPE_UUID); + * + * @see http://bsonspec.org/#/specification + * @param {Hex} subtype + * @api public + */ + +MongooseBuffer.prototype.subtype = function (subtype) { + if ('number' != typeof subtype) { + throw new TypeError('Invalid subtype. Expected a number'); + } + + if (this._subtype != subtype) { + this._markModified(); + } + + this._subtype = subtype; +} + +/*! + * Module exports. + */ + +MongooseBuffer.Binary = Binary; + +module.exports = MongooseBuffer; diff --git a/node_modules/mongoose/lib/types/documentarray.js b/node_modules/mongoose/lib/types/documentarray.js new file mode 100644 index 0000000..af6cec7 --- /dev/null +++ b/node_modules/mongoose/lib/types/documentarray.js @@ -0,0 +1,194 @@ + +/*! + * Module dependencies. + */ + +var MongooseArray = require('./array') + , driver = global.MONGOOSE_DRIVER_PATH || '../drivers/node-mongodb-native' + , ObjectId = require(driver + '/objectid') + , ObjectIdSchema = require('../schema/objectid') + , utils = require('../utils') + , util = require('util') + , Document = require('../document') + +/** + * DocumentArray constructor + * + * @param {Array} values + * @param {String} path the path to this array + * @param {Document} doc parent document + * @api private + * @return {MongooseDocumentArray} + * @inherits MongooseArray + * @see http://bit.ly/f6CnZU + */ + +function MongooseDocumentArray (values, path, doc) { + var arr = []; + + // Values always have to be passed to the constructor to initialize, since + // otherwise MongooseArray#push will mark the array as modified to the parent. + arr.push.apply(arr, values); + arr.__proto__ = MongooseDocumentArray.prototype; + + arr._atomics = {}; + arr.validators = []; + arr._path = path; + + if (doc) { + arr._parent = doc; + arr._schema = doc.schema.path(path); + doc.on('save', arr.notify('save')); + doc.on('isNew', arr.notify('isNew')); + } + + return arr; +}; + +/*! + * Inherits from MongooseArray + */ + +MongooseDocumentArray.prototype.__proto__ = MongooseArray.prototype; + +/** + * Overrides MongooseArray#cast + * + * @api private + */ + +MongooseDocumentArray.prototype._cast = function (value) { + if (value instanceof this._schema.casterConstructor) { + if (!(value.__parent && value.__parentArray)) { + // value may have been created using array.create() + value.__parent = this._parent; + value.__parentArray = this; + } + return value; + } + + // handle cast('string') or cast(ObjectId) etc. + // only objects are permitted so we can safely assume that + // non-objects are to be interpreted as _id + if (Buffer.isBuffer(value) || + value instanceof ObjectId || !utils.isObject(value)) { + value = { _id: value }; + } + + return new this._schema.casterConstructor(value, this); +}; + +/** + * Searches array items for the first document with a matching _id. + * + * ####Example: + * + * var embeddedDoc = m.array.id(some_id); + * + * @return {EmbeddedDocument|null} the subdocuent or null if not found. + * @param {ObjectId|String|Number|Buffer} id + * @TODO cast to the _id based on schema for proper comparison + * @api public + */ + +MongooseDocumentArray.prototype.id = function (id) { + var casted + , sid + , _id + + try { + var casted_ = ObjectIdSchema.prototype.cast.call({}, id); + if (casted_) casted = String(casted_); + } catch (e) { + casted = null; + } + + for (var i = 0, l = this.length; i < l; i++) { + _id = this[i].get('_id'); + + if (_id instanceof Document) { + sid || (sid = String(id)); + if (sid == _id._id) return this[i]; + } else if (!(_id instanceof ObjectId)) { + sid || (sid = String(id)); + if (sid == _id) return this[i]; + } else if (casted == _id) { + return this[i]; + } + } + + return null; +}; + +/** + * Returns a native js Array of plain js objects + * + * ####NOTE: + * + * _Each sub-document is converted to a plain object by calling its `#toObject` method._ + * + * @param {Object} [options] optional options to pass to each documents `toObject` method call during conversion + * @return {Array} + * @api public + */ + +MongooseDocumentArray.prototype.toObject = function (options) { + return this.map(function (doc) { + return doc && doc.toObject(options) || null; + }); +}; + +/** + * Helper for console.log + * + * @api public + */ + +MongooseDocumentArray.prototype.inspect = function () { + return '[' + this.map(function (doc) { + if (doc) { + return doc.inspect + ? doc.inspect() + : util.inspect(doc) + } + return 'null' + }).join('\n') + ']'; +}; + +/** + * Creates a subdocument casted to this schema. + * + * This is the same subdocument constructor used for casting. + * + * @param {Object} obj the value to cast to this arrays SubDocument schema + * @api public + */ + +MongooseDocumentArray.prototype.create = function (obj) { + return new this._schema.casterConstructor(obj); +} + +/** + * Creates a fn that notifies all child docs of `event`. + * + * @param {String} event + * @return {Function} + * @api private + */ + +MongooseDocumentArray.prototype.notify = function notify (event) { + var self = this; + return function notify (val) { + var i = self.length; + while (i--) { + if (!self[i]) continue; + self[i].emit(event, val); + } + } +} + +/*! + * Module exports. + */ + +module.exports = MongooseDocumentArray; diff --git a/node_modules/mongoose/lib/types/embedded.js b/node_modules/mongoose/lib/types/embedded.js new file mode 100644 index 0000000..6de36e6 --- /dev/null +++ b/node_modules/mongoose/lib/types/embedded.js @@ -0,0 +1,244 @@ +/*! + * Module dependencies. + */ + +var Document = require('../document') + , inspect = require('util').inspect; + +/** + * EmbeddedDocument constructor. + * + * @param {Object} obj js object returned from the db + * @param {MongooseDocumentArray} parentArr the parent array of this document + * @param {Boolean} skipId + * @inherits Document + * @api private + */ + +function EmbeddedDocument (obj, parentArr, skipId, fields) { + if (parentArr) { + this.__parentArray = parentArr; + this.__parent = parentArr._parent; + } else { + this.__parentArray = undefined; + this.__parent = undefined; + } + + Document.call(this, obj, fields, skipId); + + var self = this; + this.on('isNew', function (val) { + self.isNew = val; + }); +}; + +/*! + * Inherit from Document + */ + +EmbeddedDocument.prototype.__proto__ = Document.prototype; + +/** + * Marks the embedded doc modified. + * + * ####Example: + * + * var doc = blogpost.comments.id(hexstring); + * doc.mixed.type = 'changed'; + * doc.markModified('mixed.type'); + * + * @param {String} path the path which changed + * @api public + */ + +EmbeddedDocument.prototype.markModified = function (path) { + if (!this.__parentArray) return; + + this.$__.activePaths.modify(path); + + if (this.isNew) { + // Mark the WHOLE parent array as modified + // if this is a new document (i.e., we are initializing + // a document), + this.__parentArray._markModified(); + } else + this.__parentArray._markModified(this, path); +}; + +/** + * Used as a stub for [hooks.js](https://github.com/bnoguchi/hooks-js/tree/31ec571cef0332e21121ee7157e0cf9728572cc3) + * + * ####NOTE: + * + * _This is a no-op. Does not actually save the doc to the db._ + * + * @param {Function} [fn] + * @return {EmbeddedDocument} this + * @api private + */ + +EmbeddedDocument.prototype.save = function(fn) { + if (fn) + fn(null); + return this; +}; + +/** + * Removes the subdocument from its parent array. + * + * @param {Function} [fn] + * @api public + */ + +EmbeddedDocument.prototype.remove = function (fn) { + if (!this.__parentArray) return this; + + var _id; + if (!this.willRemove) { + _id = this._doc._id; + if (!_id) { + throw new Error('For your own good, Mongoose does not know ' + + 'how to remove an EmbeddedDocument that has no _id'); + } + this.__parentArray.pull({ _id: _id }); + this.willRemove = true; + } + + if (fn) + fn(null); + + return this; +}; + +/** + * Override #update method of parent documents. + * @api private + */ + +EmbeddedDocument.prototype.update = function () { + throw new Error('The #update method is not available on EmbeddedDocuments'); +} + +/** + * Helper for console.log + * + * @api public + */ + +EmbeddedDocument.prototype.inspect = function () { + return inspect(this.toObject()); +}; + +/** + * Marks a path as invalid, causing validation to fail. + * + * @param {String} path the field to invalidate + * @param {String|Error} err error which states the reason `path` was invalid + * @return {Boolean} + * @api public + */ + +EmbeddedDocument.prototype.invalidate = function (path, err, val, first) { + if (!this.__parent) { + var msg = 'Unable to invalidate a subdocument that has not been added to an array.' + throw new Error(msg); + } + + var index = this.__parentArray.indexOf(this); + var parentPath = this.__parentArray._path; + var fullPath = [parentPath, index, path].join('.'); + + // sniffing arguments: + // need to check if user passed a value to keep + // our error message clean. + if (2 < arguments.length) { + this.__parent.invalidate(fullPath, err, val); + } else { + this.__parent.invalidate(fullPath, err); + } + + if (first) + this.$__.validationError = this.ownerDocument().$__.validationError; + return true; +} + +/** + * Returns the top level document of this sub-document. + * + * @return {Document} + */ + +EmbeddedDocument.prototype.ownerDocument = function () { + if (this.$__.ownerDocument) { + return this.$__.ownerDocument; + } + + var parent = this.__parent; + if (!parent) return this; + + while (parent.__parent) { + parent = parent.__parent; + } + + return this.$__.ownerDocument = parent; +} + +/** + * Returns the full path to this document. If optional `path` is passed, it is appended to the full path. + * + * @param {String} [path] + * @return {String} + * @api private + * @method $__fullPath + * @memberOf EmbeddedDocument + */ + +EmbeddedDocument.prototype.$__fullPath = function (path) { + if (!this.$__.fullPath) { + var parent = this; + if (!parent.__parent) return path; + + var paths = []; + while (parent.__parent) { + paths.unshift(parent.__parentArray._path); + parent = parent.__parent; + } + + this.$__.fullPath = paths.join('.'); + + if (!this.$__.ownerDocument) { + // optimization + this.$__.ownerDocument = parent; + } + } + + return path + ? this.$__.fullPath + '.' + path + : this.$__.fullPath; +} + +/** + * Returns this sub-documents parent document. + * + * @api public + */ + +EmbeddedDocument.prototype.parent = function () { + return this.__parent; +} + +/** + * Returns this sub-documents parent array. + * + * @api public + */ + +EmbeddedDocument.prototype.parentArray = function () { + return this.__parentArray; +} + +/*! + * Module exports. + */ + +module.exports = EmbeddedDocument; diff --git a/node_modules/mongoose/lib/types/index.js b/node_modules/mongoose/lib/types/index.js new file mode 100644 index 0000000..e6a9901 --- /dev/null +++ b/node_modules/mongoose/lib/types/index.js @@ -0,0 +1,13 @@ + +/*! + * Module exports. + */ + +exports.Array = require('./array'); +exports.Buffer = require('./buffer'); + +exports.Document = // @deprecate +exports.Embedded = require('./embedded'); + +exports.DocumentArray = require('./documentarray'); +exports.ObjectId = require('./objectid'); diff --git a/node_modules/mongoose/lib/types/objectid.js b/node_modules/mongoose/lib/types/objectid.js new file mode 100644 index 0000000..44ad43f --- /dev/null +++ b/node_modules/mongoose/lib/types/objectid.js @@ -0,0 +1,43 @@ + +/*! + * Access driver. + */ + +var driver = global.MONGOOSE_DRIVER_PATH || '../drivers/node-mongodb-native'; + +/** + * ObjectId type constructor + * + * ####Example + * + * var id = new mongoose.Types.ObjectId; + * + * @constructor ObjectId + */ + +var ObjectId = require(driver + '/objectid'); +module.exports = ObjectId; + +/** + * Creates an ObjectId from `str` + * + * @param {ObjectId|HexString} str + * @static fromString + * @receiver ObjectId + * @return {ObjectId} + * @api private + */ + +ObjectId.fromString; + +/** + * Converts `oid` to a string. + * + * @param {ObjectId} oid ObjectId instance + * @static toString + * @receiver ObjectId + * @return {String} + * @api private + */ + +ObjectId.toString; diff --git a/node_modules/mongoose/lib/utils.js b/node_modules/mongoose/lib/utils.js new file mode 100644 index 0000000..95de06b --- /dev/null +++ b/node_modules/mongoose/lib/utils.js @@ -0,0 +1,684 @@ +/*! + * Module dependencies. + */ + +var ReadPref = require('mongodb').ReadPreference + , ObjectId = require('./types/objectid') + , cloneRegExp = require('regexp-clone') + , sliced = require('sliced') + , mpath = require('mpath') + , ms = require('ms') + , MongooseBuffer + , MongooseArray + , Document + +/*! + * Produces a collection name from model `name`. + * + * @param {String} name a model name + * @return {String} a collection name + * @api private + */ + +exports.toCollectionName = function (name, options) { + options = options || {}; + if ('system.profile' === name) return name; + if ('system.indexes' === name) return name; + if (options.pluralization === false) return name; + return pluralize(name.toLowerCase()); +}; + +/** + * Pluralization rules. + * + * These rules are applied while processing the argument to `toCollectionName`. + * + * @deprecated remove in 4.x gh-1350 + */ + +exports.pluralization = [ + [/(m)an$/gi, '$1en'], + [/(pe)rson$/gi, '$1ople'], + [/(child)$/gi, '$1ren'], + [/^(ox)$/gi, '$1en'], + [/(ax|test)is$/gi, '$1es'], + [/(octop|vir)us$/gi, '$1i'], + [/(alias|status)$/gi, '$1es'], + [/(bu)s$/gi, '$1ses'], + [/(buffal|tomat|potat)o$/gi, '$1oes'], + [/([ti])um$/gi, '$1a'], + [/sis$/gi, 'ses'], + [/(?:([^f])fe|([lr])f)$/gi, '$1$2ves'], + [/(hive)$/gi, '$1s'], + [/([^aeiouy]|qu)y$/gi, '$1ies'], + [/(x|ch|ss|sh)$/gi, '$1es'], + [/(matr|vert|ind)ix|ex$/gi, '$1ices'], + [/([m|l])ouse$/gi, '$1ice'], + [/(quiz)$/gi, '$1zes'], + [/s$/gi, 's'], + [/([^a-z])$/, '$1'], + [/$/gi, 's'] +]; +var rules = exports.pluralization; + +/** + * Uncountable words. + * + * These words are applied while processing the argument to `toCollectionName`. + * @api public + */ + +exports.uncountables = [ + 'advice', + 'energy', + 'excretion', + 'digestion', + 'cooperation', + 'health', + 'justice', + 'labour', + 'machinery', + 'equipment', + 'information', + 'pollution', + 'sewage', + 'paper', + 'money', + 'species', + 'series', + 'rain', + 'rice', + 'fish', + 'sheep', + 'moose', + 'deer', + 'news', + 'expertise', + 'status', + 'media' +]; +var uncountables = exports.uncountables; + +/*! + * Pluralize function. + * + * @author TJ Holowaychuk (extracted from _ext.js_) + * @param {String} string to pluralize + * @api private + */ + +function pluralize (str) { + var rule, found; + if (!~uncountables.indexOf(str.toLowerCase())){ + found = rules.filter(function(rule){ + return str.match(rule[0]); + }); + if (found[0]) return str.replace(found[0][0], found[0][1]); + } + return str; +}; + +/*! + * Determines if `a` and `b` are deep equal. + * + * Modified from node/lib/assert.js + * + * @param {any} a a value to compare to `b` + * @param {any} b a value to compare to `a` + * @return {Boolean} + * @api private + */ + +exports.deepEqual = function deepEqual (a, b) { + if (a === b) return true; + + if (a instanceof Date && b instanceof Date) + return a.getTime() === b.getTime(); + + if (a instanceof ObjectId && b instanceof ObjectId) { + return a.toString() === b.toString(); + } + + if (a instanceof RegExp && b instanceof RegExp) { + return a.source == b.source && + a.ignoreCase == b.ignoreCase && + a.multiline == b.multiline && + a.global == b.global; + } + + if (typeof a !== 'object' && typeof b !== 'object') + return a == b; + + if (a === null || b === null || a === undefined || b === undefined) + return false + + if (a.prototype !== b.prototype) return false; + + // Handle MongooseNumbers + if (a instanceof Number && b instanceof Number) { + return a.valueOf() === b.valueOf(); + } + + if (Buffer.isBuffer(a)) { + return exports.buffer.areEqual(a, b); + } + + if (isMongooseObject(a)) a = a.toObject(); + if (isMongooseObject(b)) b = b.toObject(); + + 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; +}; + +/*! + * Object clone with Mongoose natives support. + * + * If options.minimize is true, creates a minimal data object. Empty objects and undefined values will not be cloned. This makes the data payload sent to MongoDB as small as possible. + * + * Functions are never cloned. + * + * @param {Object} obj the object to clone + * @param {Object} options + * @return {Object} the cloned object + * @api private + */ + +exports.clone = function clone (obj, options) { + if (obj === undefined || obj === null) + return obj; + + if (Array.isArray(obj)) + return cloneArray(obj, options); + + if (isMongooseObject(obj)) { + if (options && options.json && 'function' === typeof obj.toJSON) { + return obj.toJSON(options); + } else { + return obj.toObject(options); + } + } + + if (obj.constructor) { + switch (obj.constructor.name) { + case 'Object': + return cloneObject(obj, options); + case 'Date': + return new obj.constructor(+obj); + case 'RegExp': + return cloneRegExp(obj); + default: + // ignore + break; + } + } + + if (obj instanceof ObjectId) + return new ObjectId(obj.id); + + if (!obj.constructor && exports.isObject(obj)) { + // object created with Object.create(null) + return cloneObject(obj, options); + } + + if (obj.valueOf) + return obj.valueOf(); +}; +var clone = exports.clone; + +/*! + * ignore + */ + +function cloneObject (obj, options) { + var retainKeyOrder = options && options.retainKeyOrder + , minimize = options && options.minimize + , ret = {} + , hasKeys + , keys + , val + , k + , i + + if (retainKeyOrder) { + for (k in obj) { + val = clone(obj[k], options); + + if (!minimize || ('undefined' !== typeof val)) { + hasKeys || (hasKeys = true); + ret[k] = val; + } + } + } else { + // faster + + keys = Object.keys(obj); + i = keys.length; + + while (i--) { + k = keys[i]; + val = clone(obj[k], options); + + if (!minimize || ('undefined' !== typeof val)) { + if (!hasKeys) hasKeys = true; + ret[k] = val; + } + } + } + + return minimize + ? hasKeys && ret + : ret; +}; + +function cloneArray (arr, options) { + var ret = []; + for (var i = 0, l = arr.length; i < l; i++) + ret.push(clone(arr[i], options)); + return ret; +}; + +/*! + * Shallow copies defaults into options. + * + * @param {Object} defaults + * @param {Object} options + * @return {Object} the merged object + * @api private + */ + +exports.options = function (defaults, options) { + var keys = Object.keys(defaults) + , i = keys.length + , k ; + + options = options || {}; + + while (i--) { + k = keys[i]; + if (!(k in options)) { + options[k] = defaults[k]; + } + } + + return options; +}; + +/*! + * Generates a random string + * + * @api private + */ + +exports.random = function () { + return Math.random().toString().substr(3); +}; + +/*! + * Merges `from` into `to` without overwriting existing properties. + * + * @param {Object} to + * @param {Object} from + * @api private + */ + +exports.merge = function merge (to, from) { + var keys = Object.keys(from) + , i = keys.length + , key; + + while (i--) { + key = keys[i]; + if ('undefined' === typeof to[key]) { + to[key] = from[key]; + } else if (exports.isObject(from[key])) { + merge(to[key], from[key]); + } + } +}; + +/*! + * toString helper + */ + +var toString = Object.prototype.toString; + +/*! + * Determines if `arg` is an object. + * + * @param {Object|Array|String|Function|RegExp|any} arg + * @api private + * @return {Boolean} + */ + +exports.isObject = function (arg) { + return '[object Object]' == toString.call(arg); +} + +/*! + * A faster Array.prototype.slice.call(arguments) alternative + * @api private + */ + +exports.args = sliced; + +/*! + * process.nextTick helper. + * + * Wraps `callback` in a try/catch + nextTick. + * + * node-mongodb-native has a habit of state corruption when an error is immediately thrown from within a collection callback. + * + * @param {Function} callback + * @api private + */ + +exports.tick = function tick (callback) { + if ('function' !== typeof callback) return; + return function () { + try { + callback.apply(this, arguments); + } catch (err) { + // only nextTick on err to get out of + // the event loop and avoid state corruption. + process.nextTick(function () { + throw err; + }); + } + } +} + +/*! + * Returns if `v` is a mongoose object that has a `toObject()` method we can use. + * + * This is for compatibility with libs like Date.js which do foolish things to Natives. + * + * @param {any} v + * @api private + */ + +exports.isMongooseObject = function (v) { + Document || (Document = require('./document')); + MongooseArray || (MongooseArray = require('./types').Array); + MongooseBuffer || (MongooseBuffer = require('./types').Buffer); + + return v instanceof Document || + v instanceof MongooseArray || + v instanceof MongooseBuffer +} +var isMongooseObject = exports.isMongooseObject; + +/*! + * Converts `expires` options of index objects to `expiresAfterSeconds` options for MongoDB. + * + * @param {Object} object + * @api private + */ + +exports.expires = function expires (object) { + if (!(object && 'Object' == object.constructor.name)) return; + if (!('expires' in object)) return; + + var when; + if ('string' != typeof object.expires) { + when = object.expires; + } else { + when = Math.round(ms(object.expires) / 1000); + } + object.expireAfterSeconds = when; + delete object.expires; +} + +/*! + * Converts arguments to ReadPrefs the driver + * can understand. + * + * @TODO move this into the driver layer + * @param {String|Array} pref + * @param {Array} [tags] + */ + +exports.readPref = function readPref (pref, tags) { + if (Array.isArray(pref)) { + tags = pref[1]; + pref = pref[0]; + } + + switch (pref) { + case 'p': + pref = 'primary'; + break; + case 'pp': + pref = 'primaryPreferred'; + break; + case 's': + pref = 'secondary'; + break; + case 'sp': + pref = 'secondaryPreferred'; + break; + case 'n': + pref = 'nearest'; + break; + } + + return new ReadPref(pref, tags); +} + +/*! + * Populate options constructor + */ + +function PopulateOptions (path, select, match, options, model) { + this.path = path; + this.match = match; + this.select = select; + this.options = options; + this.model = model; + this._docs = {}; +} + +// make it compatible with utils.clone +PopulateOptions.prototype.constructor = Object; + +// expose +exports.PopulateOptions = PopulateOptions; + +/*! + * populate helper + */ + +exports.populate = function populate (path, select, model, match, options) { + // The order of select/conditions args is opposite Model.find but + // necessary to keep backward compatibility (select could be + // an array, string, or object literal). + + // might have passed an object specifying all arguments + if (1 === arguments.length) { + if (path instanceof PopulateOptions) { + return [path]; + } + + if (Array.isArray(path)) { + return path.map(function(o){ + return exports.populate(o)[0]; + }); + } + + if (exports.isObject(path)) { + match = path.match; + options = path.options; + select = path.select; + model = path.model; + path = path.path; + } + } else if ('string' !== typeof model) { + options = match; + match = model; + model = undefined; + } + + if ('string' != typeof path) { + throw new TypeError('utils.populate: invalid path. Expected string. Got typeof `' + typeof path + '`'); + } + + var ret = []; + var paths = path.split(' '); + for (var i = 0; i < paths.length; ++i) { + ret.push(new PopulateOptions(paths[i], select, match, options, model)); + } + + return ret; +} + +/*! + * Return the value of `obj` at the given `path`. + * + * @param {String} path + * @param {Object} obj + */ + +exports.getValue = function (path, obj, map) { + return mpath.get(path, obj, '_doc', map); +} + +/*! + * Sets the value of `obj` at the given `path`. + * + * @param {String} path + * @param {Anything} val + * @param {Object} obj + */ + +exports.setValue = function (path, val, obj, map) { + mpath.set(path, val, obj, '_doc', map); +} + +/*! + * Returns an array of values from object `o`. + * + * @param {Object} o + * @return {Array} + * @private + */ + +exports.object = {}; +exports.object.vals = function vals (o) { + var keys = Object.keys(o) + , i = keys.length + , ret = []; + + while (i--) { + ret.push(o[keys[i]]); + } + + return ret; +} + +/*! + * @see exports.options + */ + +exports.object.shallowCopy = exports.options; + +/*! + * Safer helper for hasOwnProperty checks + * + * @param {Object} obj + * @param {String} prop + */ + +var hop = Object.prototype.hasOwnProperty; +exports.object.hasOwnProperty = function (obj, prop) { + return hop.call(obj, prop); +} + +/*! + * Determine if `val` is null or undefined + * + * @return {Boolean} + */ + +exports.isNullOrUndefined = function (val) { + return null == val +} + +/*! + * ignore + */ + +exports.array = {}; + +/*! + * Flattens an array. + * + * [ 1, [ 2, 3, [4] ]] -> [1,2,3,4] + * + * @param {Array} arr + * @param {Function} [filter] If passed, will be invoked with each item in the array. If `filter` returns a falsey value, the item will not be included in the results. + * @return {Array} + * @private + */ + +exports.array.flatten = function flatten (arr, filter, ret) { + ret || (ret = []); + + arr.forEach(function (item) { + if (Array.isArray(item)) { + flatten(item, filter, ret); + } else { + if (!filter || filter(item)) { + ret.push(item); + } + } + }); + + return ret; +} + +/*! + * Determines if two buffers are equal. + * + * @param {Buffer} a + * @param {Object} b + */ + +exports.buffer = {}; +exports.buffer.areEqual = function (a, b) { + if (!Buffer.isBuffer(a)) return false; + if (!Buffer.isBuffer(b)) return false; + if (a.length !== b.length) return false; + for (var i = 0, len = a.length; i < len; ++i) { + if (a[i] !== b[i]) return false; + } + return true; +} + diff --git a/node_modules/mongoose/lib/virtualtype.js b/node_modules/mongoose/lib/virtualtype.js new file mode 100644 index 0000000..819ac10 --- /dev/null +++ b/node_modules/mongoose/lib/virtualtype.js @@ -0,0 +1,103 @@ + +/** + * VirtualType constructor + * + * This is what mongoose uses to define virtual attributes via `Schema.prototype.virtual`. + * + * ####Example: + * + * var fullname = schema.virtual('fullname'); + * fullname instanceof mongoose.VirtualType // true + * + * @parma {Object} options + * @api public + */ + +function VirtualType (options, name) { + this.path = name; + this.getters = []; + this.setters = []; + this.options = options || {}; +} + +/** + * Defines a getter. + * + * ####Example: + * + * var virtual = schema.virtual('fullname'); + * virtual.get(function () { + * return this.name.first + ' ' + this.name.last; + * }); + * + * @param {Function} fn + * @return {VirtualType} this + * @api public + */ + +VirtualType.prototype.get = function (fn) { + this.getters.push(fn); + return this; +}; + +/** + * Defines a setter. + * + * ####Example: + * + * var virtual = schema.virtual('fullname'); + * virtual.set(function (v) { + * var parts = v.split(' '); + * this.name.first = parts[0]; + * this.name.last = parts[1]; + * }); + * + * @param {Function} fn + * @return {VirtualType} this + * @api public + */ + +VirtualType.prototype.set = function (fn) { + this.setters.push(fn); + return this; +}; + +/** + * Applies getters to `value` using optional `scope`. + * + * @param {Object} value + * @param {Object} scope + * @return {any} the value after applying all getters + * @api public + */ + +VirtualType.prototype.applyGetters = function (value, scope) { + var v = value; + for (var l = this.getters.length - 1; l >= 0; l--) { + v = this.getters[l].call(scope, v, this); + } + return v; +}; + +/** + * Applies setters to `value` using optional `scope`. + * + * @param {Object} value + * @param {Object} scope + * @return {any} the value after applying all setters + * @api public + */ + +VirtualType.prototype.applySetters = function (value, scope) { + var v = value; + for (var l = this.setters.length - 1; l >= 0; l--) { + v = this.setters[l].call(scope, v, this); + } + return v; +}; + +/*! + * exports + */ + +module.exports = VirtualType; diff --git a/node_modules/mongoose/node_modules/hooks/.npmignore b/node_modules/mongoose/node_modules/hooks/.npmignore new file mode 100644 index 0000000..96e29a8 --- /dev/null +++ b/node_modules/mongoose/node_modules/hooks/.npmignore @@ -0,0 +1,2 @@ +**.swp +node_modules diff --git a/node_modules/mongoose/node_modules/hooks/Makefile b/node_modules/mongoose/node_modules/hooks/Makefile new file mode 100644 index 0000000..1db5d65 --- /dev/null +++ b/node_modules/mongoose/node_modules/hooks/Makefile @@ -0,0 +1,9 @@ +test: + @NODE_ENV=test ./node_modules/expresso/bin/expresso \ + $(TESTFLAGS) \ + ./test.js + +test-cov: + @TESTFLAGS=--cov $(MAKE) test + +.PHONY: test test-cov diff --git a/node_modules/mongoose/node_modules/hooks/README.md b/node_modules/mongoose/node_modules/hooks/README.md new file mode 100644 index 0000000..af90a48 --- /dev/null +++ b/node_modules/mongoose/node_modules/hooks/README.md @@ -0,0 +1,306 @@ +hooks +============ + +Add pre and post middleware hooks to your JavaScript methods. + +## Installation + npm install hooks + +## Motivation +Suppose you have a JavaScript object with a `save` method. + +It would be nice to be able to declare code that runs before `save` and after `save`. +For example, you might want to run validation code before every `save`, +and you might want to dispatch a job to a background job queue after `save`. + +One might have an urge to hard code this all into `save`, but that turns out to +couple all these pieces of functionality (validation, save, and job creation) more +tightly than is necessary. For example, what if someone does not want to do background +job creation after the logical save? + +It is nicer to tack on functionality using what we call `pre` and `post` hooks. These +are functions that you define and that you direct to execute before or after particular +methods. + +## Example +We can use `hooks` to add validation and background jobs in the following way: + + var hooks = require('hooks') + , Document = require('./path/to/some/document/constructor'); + + // Add hooks' methods: `hook`, `pre`, and `post` + for (var k in hooks) { + Document[k] = hooks[k]; + } + + // Define a new method that is able to invoke pre and post middleware + Document.hook('save', Document.prototype.save); + + // Define a middleware function to be invoked before 'save' + Document.pre('save', function validate (next) { + // The `this` context inside of `pre` and `post` functions + // is the Document instance + if (this.isValid()) next(); // next() passes control to the next middleware + // or to the target method itself + else next(new Error("Invalid")); // next(error) invokes an error callback + }); + + // Define a middleware function to be invoked after 'save' + Document.post('save', function createJob () { + this.sendToBackgroundQueue(); + }); + +If you already have defined `Document.prototype` methods for which you want pres and posts, +then you do not need to explicitly invoke `Document.hook(...)`. Invoking `Document.pre(methodName, fn)` +or `Document.post(methodName, fn)` will automatically and lazily change `Document.prototype[methodName]` +so that it plays well with `hooks`. An equivalent way to implement the previous example is: + +```javascript +var hooks = require('hooks') + , Document = require('./path/to/some/document/constructor'); + +// Add hooks' methods: `hook`, `pre`, and `post` +for (var k in hooks) { + Document[k] = hooks[k]; +} + +Document.prototype.save = function () { + // ... +}; + +// Define a middleware function to be invoked before 'save' +Document.pre('save', function validate (next) { + // The `this` context inside of `pre` and `post` functions + // is the Document instance + if (this.isValid()) next(); // next() passes control to the next middleware + // or to the target method itself + else next(new Error("Invalid")); // next(error) invokes an error callback +}); + +// Define a middleware function to be invoked after 'save' +Document.post('save', function createJob () { + this.sendToBackgroundQueue(); +}); +``` + +## Pres and Posts as Middleware +We structure pres and posts as middleware to give you maximum flexibility: + +1. You can define **multiple** pres (or posts) for a single method. +2. These pres (or posts) are then executed as a chain of methods. +3. Any functions in this middleware chain can choose to halt the chain's execution by `next`ing an Error from that middleware function. If this occurs, then none of the other middleware in the chain will execute, and the main method (e.g., `save`) will not execute. This is nice, for example, when we don't want a document to save if it is invalid. + +## Defining multiple pres (or posts) +`pre` is chainable, so you can define multiple pres via: + Document.pre('save', function (next, halt) { + console.log("hello"); + }).pre('save', function (next, halt) { + console.log("world"); + }); + +As soon as one pre finishes executing, the next one will be invoked, and so on. + +## Error Handling +You can define a default error handler by passing a 2nd function as the 3rd argument to `hook`: + Document.hook('set', function (path, val) { + this[path] = val; + }, function (err) { + // Handler the error here + console.error(err); + }); + +Then, we can pass errors to this handler from a pre or post middleware function: + Document.pre('set', function (next, path, val) { + next(new Error()); + }); + +If you do not set up a default handler, then `hooks` makes the default handler that just throws the `Error`. + +The default error handler can be over-rided on a per method invocation basis. + +If the main method that you are surrounding with pre and post middleware expects its last argument to be a function +with callback signature `function (error, ...)`, then that callback becomes the error handler, over-riding the default +error handler you may have set up. + +```javascript +Document.hook('save', function (callback) { + // Save logic goes here + ... +}); + +var doc = new Document(); +doc.save( function (err, saved) { + // We can pass err via `next` in any of our pre or post middleware functions + if (err) console.error(err); + + // Rest of callback logic follows ... +}); +``` + +## Mutating Arguments via Middleware +`pre` and `post` middleware can also accept the intended arguments for the method +they augment. This is useful if you want to mutate the arguments before passing +them along to the next middleware and eventually pass a mutated arguments list to +the main method itself. + +As a simple example, let's define a method `set` that just sets a key, value pair. +If we want to namespace the key, we can do so by adding a `pre` middleware hook +that runs before `set`, alters the arguments by namespacing the `key` argument, and passes them onto `set`: + + Document.hook('set', function (key, val) { + this[key] = val; + }); + Document.pre('set', function (next, key, val) { + next('namespace-' + key, val); + }); + var doc = new Document(); + doc.set('hello', 'world'); + console.log(doc.hello); // undefined + console.log(doc['namespace-hello']); // 'world' + +As you can see above, we pass arguments via `next`. + +If you are not mutating the arguments, then you can pass zero arguments +to `next`, and the next middleware function will still have access +to the arguments. + + Document.hook('set', function (key, val) { + this[key] = val; + }); + Document.pre('set', function (next, key, val) { + // I have access to key and val here + next(); // We don't need to pass anything to next + }); + Document.pre('set', function (next, key, val) { + // And I still have access to the original key and val here + next(); + }); + +Finally, you can add arguments that downstream middleware can also see: + + // Note that in the definition of `set`, there is no 3rd argument, options + Document.hook('set', function (key, val) { + // But... + var options = arguments[2]; // ...I have access to an options argument + // because of pre function pre2 (defined below) + console.log(options); // '{debug: true}' + this[key] = val; + }); + Document.pre('set', function pre1 (next, key, val) { + // I only have access to key and val arguments + console.log(arguments.length); // 3 + next(key, val, {debug: true}); + }); + Document.pre('set', function pre2 (next, key, val, options) { + console.log(arguments.length); // 4 + console.log(options); // '{ debug: true}' + next(); + }); + Document.pre('set', function pre3 (next, key, val, options) { + // I still have access to key, val, AND the options argument introduced via the preceding middleware + console.log(arguments.length); // 4 + console.log(options); // '{ debug: true}' + next(); + }); + + var doc = new Document() + doc.set('hey', 'there'); + +## Parallel `pre` middleware + +All middleware up to this point has been "serial" middleware -- i.e., middleware whose logic +is executed as a serial chain. + +Some scenarios call for parallel middleware -- i.e., middleware that can wait for several +asynchronous services at once to respond. + +For instance, you may only want to save a Document only after you have checked +that the Document is valid according to two different remote services. + +We accomplish asynchronous middleware by adding a second kind of flow control callback +(the only flow control callback so far has been `next`), called `done`. + +- `next` passes control to the next middleware in the chain +- `done` keeps track of how many parallel middleware have invoked `done` and passes + control to the target method when ALL parallel middleware have invoked `done`. If + you pass an `Error` to `done`, then the error is handled, and the main method that is + wrapped by pres and posts will not get invoked. + +We declare pre middleware that is parallel by passing a 3rd boolean argument to our `pre` +definition method. + +We illustrate via the parallel validation example mentioned above: + + Document.hook('save', function targetFn (callback) { + // Save logic goes here + // ... + // This only gets run once the two `done`s are both invoked via preOne and preTwo. + }); + + // true marks this as parallel middleware + Document.pre('save', true, function preOne (next, doneOne, callback) { + remoteServiceOne.validate(this.serialize(), function (err, isValid) { + // The code in here will probably be run after the `next` below this block + // and could possibly be run after the console.log("Hola") in `preTwo + if (err) return doneOne(err); + if (isValid) doneOne(); + }); + next(); // Pass control to the next middleware + }); + + // We will suppose that we need 2 different remote services to validate our document + Document.pre('save', true, function preTwo (next, doneTwo, callback) { + remoteServiceTwo.validate(this.serialize(), function (err, isValid) { + if (err) return doneTwo(err); + if (isValid) doneTwo(); + }); + next(); + }); + + // While preOne and preTwo are parallel, preThree is a serial pre middleware + Document.pre('save', function preThree (next, callback) { + next(); + }); + + var doc = new Document(); + doc.save( function (err, doc) { + // Do stuff with the saved doc here... + }); + +In the above example, flow control may happen in the following way: + +(1) doc.save -> (2) preOne --(next)--> (3) preTwo --(next)--> (4) preThree --(next)--> (wait for dones to invoke) -> (5) doneTwo -> (6) doneOne -> (7) targetFn + +So what's happening is that: + +1. You call `doc.save(...)` +2. First, your preOne middleware gets executed. It makes a remote call to the validation service and `next()`s to the preTwo middleware. +3. Now, your preTwo middleware gets executed. It makes a remote call to another validation service and `next()`s to the preThree middleware. +4. Your preThree middleware gets executed. It immediately `next()`s. But nothing else gets executing until both `doneOne` and `doneTwo` are invoked inside the callbacks handling the response from the two valiation services. +5. We will suppose that validation remoteServiceTwo returns a response to us first. In this case, we call `doneTwo` inside the callback to remoteServiceTwo. +6. Some fractions of a second later, remoteServiceOne returns a response to us. In this case, we call `doneOne` inside the callback to remoteServiceOne. +7. `hooks` implementation keeps track of how many parallel middleware has been defined per target function. It detects that both asynchronous pre middlewares (`preOne` and `preTwo`) have finally called their `done` functions (`doneOne` and `doneTwo`), so the implementation finally invokes our `targetFn` (i.e., our core `save` business logic). + +## Removing Pres + +You can remove a particular pre associated with a hook: + + Document.pre('set', someFn); + Document.removePre('set', someFn); + +And you can also remove all pres associated with a hook: + Document.removePre('set'); // Removes all declared `pre`s on the hook 'set' + +## Tests +To run the tests: + make test + +### Contributors +- [Brian Noguchi](https://github.com/bnoguchi) + +### License +MIT License + +--- +### Author +Brian Noguchi diff --git a/node_modules/mongoose/node_modules/hooks/hooks.alt.js b/node_modules/mongoose/node_modules/hooks/hooks.alt.js new file mode 100644 index 0000000..6ced357 --- /dev/null +++ b/node_modules/mongoose/node_modules/hooks/hooks.alt.js @@ -0,0 +1,134 @@ +/** + * Hooks are useful if we want to add a method that automatically has `pre` and `post` hooks. + * For example, it would be convenient to have `pre` and `post` hooks for `save`. + * _.extend(Model, mixins.hooks); + * Model.hook('save', function () { + * console.log('saving'); + * }); + * Model.pre('save', function (next, done) { + * console.log('about to save'); + * next(); + * }); + * Model.post('save', function (next, done) { + * console.log('saved'); + * next(); + * }); + * + * var m = new Model(); + * m.save(); + * // about to save + * // saving + * // saved + */ + +// TODO Add in pre and post skipping options +module.exports = { + /** + * Declares a new hook to which you can add pres and posts + * @param {String} name of the function + * @param {Function} the method + * @param {Function} the error handler callback + */ + hook: function (name, fn, err) { + if (arguments.length === 1 && typeof name === 'object') { + for (var k in name) { // `name` is a hash of hookName->hookFn + this.hook(k, name[k]); + } + return; + } + + if (!err) err = fn; + + var proto = this.prototype || this + , pres = proto._pres = proto._pres || {} + , posts = proto._posts = proto._posts || {}; + pres[name] = pres[name] || []; + posts[name] = posts[name] || []; + + function noop () {} + + proto[name] = function () { + var self = this + , pres = this._pres[name] + , posts = this._posts[name] + , numAsyncPres = 0 + , hookArgs = [].slice.call(arguments) + , preChain = pres.map( function (pre, i) { + var wrapper = function () { + if (arguments[0] instanceof Error) + return err(arguments[0]); + if (numAsyncPres) { + // arguments[1] === asyncComplete + if (arguments.length) + hookArgs = [].slice.call(arguments, 2); + pre.apply(self, + [ preChain[i+1] || allPresInvoked, + asyncComplete + ].concat(hookArgs) + ); + } else { + if (arguments.length) + hookArgs = [].slice.call(arguments); + pre.apply(self, + [ preChain[i+1] || allPresDone ].concat(hookArgs)); + } + }; // end wrapper = function () {... + if (wrapper.isAsync = pre.isAsync) + numAsyncPres++; + return wrapper; + }); // end posts.map(...) + function allPresInvoked () { + if (arguments[0] instanceof Error) + err(arguments[0]); + } + + function allPresDone () { + if (arguments[0] instanceof Error) + return err(arguments[0]); + if (arguments.length) + hookArgs = [].slice.call(arguments); + fn.apply(self, hookArgs); + var postChain = posts.map( function (post, i) { + var wrapper = function () { + if (arguments[0] instanceof Error) + return err(arguments[0]); + if (arguments.length) + hookArgs = [].slice.call(arguments); + post.apply(self, + [ postChain[i+1] || noop].concat(hookArgs)); + }; // end wrapper = function () {... + return wrapper; + }); // end posts.map(...) + if (postChain.length) postChain[0](); + } + + if (numAsyncPres) { + complete = numAsyncPres; + function asyncComplete () { + if (arguments[0] instanceof Error) + return err(arguments[0]); + --complete || allPresDone.call(this); + } + } + (preChain[0] || allPresDone)(); + }; + + return this; + }, + + pre: function (name, fn, isAsync) { + var proto = this.prototype + , pres = proto._pres = proto._pres || {}; + if (fn.isAsync = isAsync) { + this.prototype[name].numAsyncPres++; + } + (pres[name] = pres[name] || []).push(fn); + return this; + }, + post: function (name, fn, isAsync) { + var proto = this.prototype + , posts = proto._posts = proto._posts || {}; + (posts[name] = posts[name] || []).push(fn); + return this; + } +}; diff --git a/node_modules/mongoose/node_modules/hooks/hooks.js b/node_modules/mongoose/node_modules/hooks/hooks.js new file mode 100644 index 0000000..9a887c7 --- /dev/null +++ b/node_modules/mongoose/node_modules/hooks/hooks.js @@ -0,0 +1,161 @@ +// TODO Add in pre and post skipping options +module.exports = { + /** + * Declares a new hook to which you can add pres and posts + * @param {String} name of the function + * @param {Function} the method + * @param {Function} the error handler callback + */ + hook: function (name, fn, errorCb) { + if (arguments.length === 1 && typeof name === 'object') { + for (var k in name) { // `name` is a hash of hookName->hookFn + this.hook(k, name[k]); + } + return; + } + + var proto = this.prototype || this + , pres = proto._pres = proto._pres || {} + , posts = proto._posts = proto._posts || {}; + pres[name] = pres[name] || []; + posts[name] = posts[name] || []; + + proto[name] = function () { + var self = this + , hookArgs // arguments eventually passed to the hook - are mutable + , lastArg = arguments[arguments.length-1] + , pres = this._pres[name] + , posts = this._posts[name] + , _total = pres.length + , _current = -1 + , _asyncsLeft = proto[name].numAsyncPres + , _next = function () { + if (arguments[0] instanceof Error) { + return handleError(arguments[0]); + } + var _args = Array.prototype.slice.call(arguments) + , currPre + , preArgs; + if (_args.length && !(arguments[0] == null && typeof lastArg === 'function')) + hookArgs = _args; + if (++_current < _total) { + currPre = pres[_current] + if (currPre.isAsync && currPre.length < 2) + throw new Error("Your pre must have next and done arguments -- e.g., function (next, done, ...)"); + if (currPre.length < 1) + throw new Error("Your pre must have a next argument -- e.g., function (next, ...)"); + preArgs = (currPre.isAsync + ? [once(_next), once(_asyncsDone)] + : [once(_next)]).concat(hookArgs); + return currPre.apply(self, preArgs); + } else if (!proto[name].numAsyncPres) { + return _done.apply(self, hookArgs); + } + } + , _done = function () { + var args_ = Array.prototype.slice.call(arguments) + , ret, total_, current_, next_, done_, postArgs; + if (_current === _total) { + ret = fn.apply(self, args_); + total_ = posts.length; + current_ = -1; + next_ = function () { + if (arguments[0] instanceof Error) { + return handleError(arguments[0]); + } + var args_ = Array.prototype.slice.call(arguments, 1) + , currPost + , postArgs; + if (args_.length) hookArgs = args_; + if (++current_ < total_) { + currPost = posts[current_] + if (currPost.length < 1) + throw new Error("Your post must have a next argument -- e.g., function (next, ...)"); + postArgs = [once(next_)].concat(hookArgs); + return currPost.apply(self, postArgs); + } + }; + if (total_) return next_(); + return ret; + } + }; + if (_asyncsLeft) { + function _asyncsDone (err) { + if (err && err instanceof Error) { + return handleError(err); + } + --_asyncsLeft || _done.apply(self, hookArgs); + } + } + function handleError (err) { + if ('function' == typeof lastArg) + return lastArg(err); + if (errorCb) return errorCb.call(self, err); + throw err; + } + return _next.apply(this, arguments); + }; + + proto[name].numAsyncPres = 0; + + return this; + }, + + pre: function (name, isAsync, fn, errorCb) { + if ('boolean' !== typeof arguments[1]) { + errorCb = fn; + fn = isAsync; + isAsync = false; + } + var proto = this.prototype || this + , pres = proto._pres = proto._pres || {}; + + this._lazySetupHooks(proto, name, errorCb); + + if (fn.isAsync = isAsync) { + proto[name].numAsyncPres++; + } + + (pres[name] = pres[name] || []).push(fn); + return this; + }, + post: function (name, isAsync, fn) { + if (arguments.length === 2) { + fn = isAsync; + isAsync = false; + } + var proto = this.prototype || this + , posts = proto._posts = proto._posts || {}; + + this._lazySetupHooks(proto, name); + (posts[name] = posts[name] || []).push(fn); + return this; + }, + removePre: function (name, fnToRemove) { + var proto = this.prototype || this + , pres = proto._pres || (proto._pres || {}); + if (!pres[name]) return this; + if (arguments.length === 1) { + // Remove all pre callbacks for hook `name` + pres[name].length = 0; + } else { + pres[name] = pres[name].filter( function (currFn) { + return currFn !== fnToRemove; + }); + } + return this; + }, + _lazySetupHooks: function (proto, methodName, errorCb) { + if ('undefined' === typeof proto[methodName].numAsyncPres) { + this.hook(methodName, proto[methodName], errorCb); + } + } +}; + +function once (fn, scope) { + return function fnWrapper () { + if (fnWrapper.hookCalled) return; + fnWrapper.hookCalled = true; + fn.apply(scope, arguments); + }; +} diff --git a/node_modules/mongoose/node_modules/hooks/package.json b/node_modules/mongoose/node_modules/hooks/package.json new file mode 100644 index 0000000..418d91a --- /dev/null +++ b/node_modules/mongoose/node_modules/hooks/package.json @@ -0,0 +1,53 @@ +{ + "name": "hooks", + "description": "Adds pre and post hook functionality to your JavaScript methods.", + "version": "0.2.1", + "keywords": [ + "node", + "hooks", + "middleware", + "pre", + "post" + ], + "homepage": "https://github.com/bnoguchi/hooks-js/", + "repository": { + "type": "git", + "url": "git://github.com/bnoguchi/hooks-js.git" + }, + "author": { + "name": "Brian Noguchi", + "email": "brian.noguchi@gmail.com", + "url": "https://github.com/bnoguchi/" + }, + "main": "./hooks.js", + "directories": { + "lib": "." + }, + "scripts": { + "test": "make test" + }, + "dependencies": {}, + "devDependencies": { + "expresso": ">=0.7.6", + "should": ">=0.2.1", + "underscore": ">=1.1.4" + }, + "engines": { + "node": ">=0.4.0" + }, + "licenses": [ + "MIT" + ], + "optionalDependencies": {}, + "readme": "hooks\n============\n\nAdd pre and post middleware hooks to your JavaScript methods.\n\n## Installation\n npm install hooks\n\n## Motivation\nSuppose you have a JavaScript object with a `save` method.\n\nIt would be nice to be able to declare code that runs before `save` and after `save`.\nFor example, you might want to run validation code before every `save`,\nand you might want to dispatch a job to a background job queue after `save`.\n\nOne might have an urge to hard code this all into `save`, but that turns out to\ncouple all these pieces of functionality (validation, save, and job creation) more\ntightly than is necessary. For example, what if someone does not want to do background\njob creation after the logical save? \n\nIt is nicer to tack on functionality using what we call `pre` and `post` hooks. These\nare functions that you define and that you direct to execute before or after particular\nmethods.\n\n## Example\nWe can use `hooks` to add validation and background jobs in the following way:\n\n var hooks = require('hooks')\n , Document = require('./path/to/some/document/constructor');\n\n // Add hooks' methods: `hook`, `pre`, and `post` \n for (var k in hooks) {\n Document[k] = hooks[k];\n }\n\n // Define a new method that is able to invoke pre and post middleware\n Document.hook('save', Document.prototype.save);\n\n // Define a middleware function to be invoked before 'save'\n Document.pre('save', function validate (next) {\n // The `this` context inside of `pre` and `post` functions\n // is the Document instance\n if (this.isValid()) next(); // next() passes control to the next middleware\n // or to the target method itself\n else next(new Error(\"Invalid\")); // next(error) invokes an error callback\n });\n\n // Define a middleware function to be invoked after 'save'\n Document.post('save', function createJob () {\n this.sendToBackgroundQueue();\n });\n\nIf you already have defined `Document.prototype` methods for which you want pres and posts,\nthen you do not need to explicitly invoke `Document.hook(...)`. Invoking `Document.pre(methodName, fn)`\nor `Document.post(methodName, fn)` will automatically and lazily change `Document.prototype[methodName]`\nso that it plays well with `hooks`. An equivalent way to implement the previous example is:\n\n```javascript\nvar hooks = require('hooks')\n , Document = require('./path/to/some/document/constructor');\n\n// Add hooks' methods: `hook`, `pre`, and `post` \nfor (var k in hooks) {\n Document[k] = hooks[k];\n}\n\nDocument.prototype.save = function () {\n // ...\n};\n\n// Define a middleware function to be invoked before 'save'\nDocument.pre('save', function validate (next) {\n // The `this` context inside of `pre` and `post` functions\n // is the Document instance\n if (this.isValid()) next(); // next() passes control to the next middleware\n // or to the target method itself\n else next(new Error(\"Invalid\")); // next(error) invokes an error callback\n});\n\n// Define a middleware function to be invoked after 'save'\nDocument.post('save', function createJob () {\n this.sendToBackgroundQueue();\n});\n```\n\n## Pres and Posts as Middleware\nWe structure pres and posts as middleware to give you maximum flexibility:\n\n1. You can define **multiple** pres (or posts) for a single method.\n2. These pres (or posts) are then executed as a chain of methods.\n3. Any functions in this middleware chain can choose to halt the chain's execution by `next`ing an Error from that middleware function. If this occurs, then none of the other middleware in the chain will execute, and the main method (e.g., `save`) will not execute. This is nice, for example, when we don't want a document to save if it is invalid.\n\n## Defining multiple pres (or posts)\n`pre` is chainable, so you can define multiple pres via:\n Document.pre('save', function (next, halt) {\n console.log(\"hello\");\n }).pre('save', function (next, halt) {\n console.log(\"world\");\n });\n\nAs soon as one pre finishes executing, the next one will be invoked, and so on.\n\n## Error Handling\nYou can define a default error handler by passing a 2nd function as the 3rd argument to `hook`:\n Document.hook('set', function (path, val) {\n this[path] = val;\n }, function (err) {\n // Handler the error here\n console.error(err);\n });\n\nThen, we can pass errors to this handler from a pre or post middleware function:\n Document.pre('set', function (next, path, val) {\n next(new Error());\n });\n\nIf you do not set up a default handler, then `hooks` makes the default handler that just throws the `Error`.\n\nThe default error handler can be over-rided on a per method invocation basis.\n\nIf the main method that you are surrounding with pre and post middleware expects its last argument to be a function\nwith callback signature `function (error, ...)`, then that callback becomes the error handler, over-riding the default\nerror handler you may have set up.\n \n```javascript\nDocument.hook('save', function (callback) {\n // Save logic goes here\n ...\n});\n\nvar doc = new Document();\ndoc.save( function (err, saved) {\n // We can pass err via `next` in any of our pre or post middleware functions\n if (err) console.error(err);\n \n // Rest of callback logic follows ...\n});\n```\n\n## Mutating Arguments via Middleware\n`pre` and `post` middleware can also accept the intended arguments for the method\nthey augment. This is useful if you want to mutate the arguments before passing\nthem along to the next middleware and eventually pass a mutated arguments list to\nthe main method itself.\n\nAs a simple example, let's define a method `set` that just sets a key, value pair.\nIf we want to namespace the key, we can do so by adding a `pre` middleware hook\nthat runs before `set`, alters the arguments by namespacing the `key` argument, and passes them onto `set`:\n\n Document.hook('set', function (key, val) {\n this[key] = val;\n });\n Document.pre('set', function (next, key, val) {\n next('namespace-' + key, val);\n });\n var doc = new Document();\n doc.set('hello', 'world');\n console.log(doc.hello); // undefined\n console.log(doc['namespace-hello']); // 'world'\n\nAs you can see above, we pass arguments via `next`.\n\nIf you are not mutating the arguments, then you can pass zero arguments\nto `next`, and the next middleware function will still have access\nto the arguments.\n\n Document.hook('set', function (key, val) {\n this[key] = val;\n });\n Document.pre('set', function (next, key, val) {\n // I have access to key and val here\n next(); // We don't need to pass anything to next\n });\n Document.pre('set', function (next, key, val) {\n // And I still have access to the original key and val here\n next();\n });\n\nFinally, you can add arguments that downstream middleware can also see:\n\n // Note that in the definition of `set`, there is no 3rd argument, options\n Document.hook('set', function (key, val) {\n // But...\n var options = arguments[2]; // ...I have access to an options argument\n // because of pre function pre2 (defined below)\n console.log(options); // '{debug: true}'\n this[key] = val;\n });\n Document.pre('set', function pre1 (next, key, val) {\n // I only have access to key and val arguments\n console.log(arguments.length); // 3\n next(key, val, {debug: true});\n });\n Document.pre('set', function pre2 (next, key, val, options) {\n console.log(arguments.length); // 4\n console.log(options); // '{ debug: true}'\n next();\n });\n Document.pre('set', function pre3 (next, key, val, options) {\n // I still have access to key, val, AND the options argument introduced via the preceding middleware\n console.log(arguments.length); // 4\n console.log(options); // '{ debug: true}'\n next();\n });\n \n var doc = new Document()\n doc.set('hey', 'there');\n\n## Parallel `pre` middleware\n\nAll middleware up to this point has been \"serial\" middleware -- i.e., middleware whose logic\nis executed as a serial chain.\n\nSome scenarios call for parallel middleware -- i.e., middleware that can wait for several\nasynchronous services at once to respond.\n\nFor instance, you may only want to save a Document only after you have checked\nthat the Document is valid according to two different remote services.\n\nWe accomplish asynchronous middleware by adding a second kind of flow control callback\n(the only flow control callback so far has been `next`), called `done`.\n\n- `next` passes control to the next middleware in the chain\n- `done` keeps track of how many parallel middleware have invoked `done` and passes\n control to the target method when ALL parallel middleware have invoked `done`. If\n you pass an `Error` to `done`, then the error is handled, and the main method that is\n wrapped by pres and posts will not get invoked.\n\nWe declare pre middleware that is parallel by passing a 3rd boolean argument to our `pre`\ndefinition method.\n\nWe illustrate via the parallel validation example mentioned above:\n\n Document.hook('save', function targetFn (callback) {\n // Save logic goes here\n // ...\n // This only gets run once the two `done`s are both invoked via preOne and preTwo.\n });\n\n // true marks this as parallel middleware\n Document.pre('save', true, function preOne (next, doneOne, callback) {\n remoteServiceOne.validate(this.serialize(), function (err, isValid) {\n // The code in here will probably be run after the `next` below this block\n // and could possibly be run after the console.log(\"Hola\") in `preTwo\n if (err) return doneOne(err);\n if (isValid) doneOne();\n });\n next(); // Pass control to the next middleware\n });\n \n // We will suppose that we need 2 different remote services to validate our document\n Document.pre('save', true, function preTwo (next, doneTwo, callback) {\n remoteServiceTwo.validate(this.serialize(), function (err, isValid) {\n if (err) return doneTwo(err);\n if (isValid) doneTwo();\n });\n next();\n });\n \n // While preOne and preTwo are parallel, preThree is a serial pre middleware\n Document.pre('save', function preThree (next, callback) {\n next();\n });\n \n var doc = new Document();\n doc.save( function (err, doc) {\n // Do stuff with the saved doc here...\n });\n\nIn the above example, flow control may happen in the following way:\n\n(1) doc.save -> (2) preOne --(next)--> (3) preTwo --(next)--> (4) preThree --(next)--> (wait for dones to invoke) -> (5) doneTwo -> (6) doneOne -> (7) targetFn\n\nSo what's happening is that:\n\n1. You call `doc.save(...)`\n2. First, your preOne middleware gets executed. It makes a remote call to the validation service and `next()`s to the preTwo middleware.\n3. Now, your preTwo middleware gets executed. It makes a remote call to another validation service and `next()`s to the preThree middleware.\n4. Your preThree middleware gets executed. It immediately `next()`s. But nothing else gets executing until both `doneOne` and `doneTwo` are invoked inside the callbacks handling the response from the two valiation services.\n5. We will suppose that validation remoteServiceTwo returns a response to us first. In this case, we call `doneTwo` inside the callback to remoteServiceTwo.\n6. Some fractions of a second later, remoteServiceOne returns a response to us. In this case, we call `doneOne` inside the callback to remoteServiceOne.\n7. `hooks` implementation keeps track of how many parallel middleware has been defined per target function. It detects that both asynchronous pre middlewares (`preOne` and `preTwo`) have finally called their `done` functions (`doneOne` and `doneTwo`), so the implementation finally invokes our `targetFn` (i.e., our core `save` business logic).\n\n## Removing Pres\n\nYou can remove a particular pre associated with a hook:\n\n Document.pre('set', someFn);\n Document.removePre('set', someFn);\n\nAnd you can also remove all pres associated with a hook:\n Document.removePre('set'); // Removes all declared `pre`s on the hook 'set'\n\n## Tests\nTo run the tests:\n make test\n\n### Contributors\n- [Brian Noguchi](https://github.com/bnoguchi)\n\n### License\nMIT License\n\n---\n### Author\nBrian Noguchi\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/bnoguchi/hooks-js/issues" + }, + "_id": "hooks@0.2.1", + "dist": { + "shasum": "0f591b1b344bdcb3df59773f62fbbaf85bf4028b" + }, + "_from": "hooks@0.2.1", + "_resolved": "https://registry.npmjs.org/hooks/-/hooks-0.2.1.tgz" +} diff --git a/node_modules/mongoose/node_modules/hooks/test.js b/node_modules/mongoose/node_modules/hooks/test.js new file mode 100644 index 0000000..efe2f3e --- /dev/null +++ b/node_modules/mongoose/node_modules/hooks/test.js @@ -0,0 +1,691 @@ +var hooks = require('./hooks') + , should = require('should') + , assert = require('assert') + , _ = require('underscore'); + +// TODO Add in test for making sure all pres get called if pre is defined directly on an instance. +// TODO Test for calling `done` twice or `next` twice in the same function counts only once +module.exports = { + 'should be able to assign multiple hooks at once': function () { + var A = function () {}; + _.extend(A, hooks); + A.hook({ + hook1: function (a) {}, + hook2: function (b) {} + }); + var a = new A(); + assert.equal(typeof a.hook1, 'function'); + assert.equal(typeof a.hook2, 'function'); + }, + 'should run without pres and posts when not present': function () { + var A = function () {}; + _.extend(A, hooks); + A.hook('save', function () { + this.value = 1; + }); + var a = new A(); + a.save(); + a.value.should.equal(1); + }, + 'should run with pres when present': function () { + var A = function () {}; + _.extend(A, hooks); + A.hook('save', function () { + this.value = 1; + }); + A.pre('save', function (next) { + this.preValue = 2; + next(); + }); + var a = new A(); + a.save(); + a.value.should.equal(1); + a.preValue.should.equal(2); + }, + 'should run with posts when present': function () { + var A = function () {}; + _.extend(A, hooks); + A.hook('save', function () { + this.value = 1; + }); + A.post('save', function (next) { + this.value = 2; + next(); + }); + var a = new A(); + a.save(); + a.value.should.equal(2); + }, + 'should run pres and posts when present': function () { + var A = function () {}; + _.extend(A, hooks); + A.hook('save', function () { + this.value = 1; + }); + A.pre('save', function (next) { + this.preValue = 2; + next(); + }); + A.post('save', function (next) { + this.value = 3; + next(); + }); + var a = new A(); + a.save(); + a.value.should.equal(3); + a.preValue.should.equal(2); + }, + 'should run posts after pres': function () { + var A = function () {}; + _.extend(A, hooks); + A.hook('save', function () { + this.value = 1; + }); + A.pre('save', function (next) { + this.override = 100; + next(); + }); + A.post('save', function (next) { + this.override = 200; + next(); + }); + var a = new A(); + a.save(); + a.value.should.equal(1); + a.override.should.equal(200); + }, + 'should not run a hook if a pre fails': function () { + var A = function () {}; + _.extend(A, hooks); + var counter = 0; + A.hook('save', function () { + this.value = 1; + }, function (err) { + counter++; + }); + A.pre('save', true, function (next, done) { + next(new Error()); + }); + var a = new A(); + a.save(); + counter.should.equal(1); + assert.equal(typeof a.value, 'undefined'); + }, + 'should be able to run multiple pres': function () { + var A = function () {}; + _.extend(A, hooks); + A.hook('save', function () { + this.value = 1; + }); + A.pre('save', function (next) { + this.v1 = 1; + next(); + }).pre('save', function (next) { + this.v2 = 2; + next(); + }); + var a = new A(); + a.save(); + a.v1.should.equal(1); + a.v2.should.equal(2); + }, + 'should run multiple pres until a pre fails and not call the hook': function () { + var A = function () {}; + _.extend(A, hooks); + A.hook('save', function () { + this.value = 1; + }, function (err) {}); + A.pre('save', function (next) { + this.v1 = 1; + next(); + }).pre('save', function (next) { + next(new Error()); + }).pre('save', function (next) { + this.v3 = 3; + next(); + }); + var a = new A(); + a.save(); + a.v1.should.equal(1); + assert.equal(typeof a.v3, 'undefined'); + assert.equal(typeof a.value, 'undefined'); + }, + 'should be able to run multiple posts': function () { + var A = function () {}; + _.extend(A, hooks); + A.hook('save', function () { + this.value = 1; + }); + A.post('save', function (next) { + this.value = 2; + next(); + }).post('save', function (next) { + this.value = 3.14; + next(); + }).post('save', function (next) { + this.v3 = 3; + next(); + }); + var a = new A(); + a.save(); + assert.equal(a.value, 3.14); + assert.equal(a.v3, 3); + }, + 'should run only posts up until an error': function () { + var A = function () {}; + _.extend(A, hooks); + A.hook('save', function () { + this.value = 1; + }, function (err) {}); + A.post('save', function (next) { + this.value = 2; + next(); + }).post('save', function (next) { + this.value = 3; + next(new Error()); + }).post('save', function (next) { + this.value = 4; + next(); + }); + var a = new A(); + a.save(); + a.value.should.equal(3); + }, + "should fall back first to the hook method's last argument as the error handler if it is a function of arity 1 or 2": function () { + var A = function () {}; + _.extend(A, hooks); + var counter = 0; + A.hook('save', function (callback) { + this.value = 1; + }); + A.pre('save', true, function (next, done) { + next(new Error()); + }); + var a = new A(); + a.save( function (err) { + if (err instanceof Error) counter++; + }); + counter.should.equal(1); + should.deepEqual(undefined, a.value); + }, + 'should fall back second to the default error handler if specified': function () { + var A = function () {}; + _.extend(A, hooks); + var counter = 0; + A.hook('save', function (callback) { + this.value = 1; + }, function (err) { + if (err instanceof Error) counter++; + }); + A.pre('save', true, function (next, done) { + next(new Error()); + }); + var a = new A(); + a.save(); + counter.should.equal(1); + should.deepEqual(undefined, a.value); + }, + 'fallback default error handler should scope to the object': function () { + var A = function () { + this.counter = 0; + }; + _.extend(A, hooks); + var counter = 0; + A.hook('save', function (callback) { + this.value = 1; + }, function (err) { + if (err instanceof Error) this.counter++; + }); + A.pre('save', true, function (next, done) { + next(new Error()); + }); + var a = new A(); + a.save(); + a.counter.should.equal(1); + should.deepEqual(undefined, a.value); + }, + 'should fall back last to throwing the error': function () { + var A = function () {}; + _.extend(A, hooks); + var counter = 0; + A.hook('save', function (err) { + if (err instanceof Error) return counter++; + this.value = 1; + }); + A.pre('save', true, function (next, done) { + next(new Error()); + }); + var a = new A(); + var didCatch = false; + try { + a.save(); + } catch (e) { + didCatch = true; + e.should.be.an.instanceof(Error); + counter.should.equal(0); + assert.equal(typeof a.value, 'undefined'); + } + didCatch.should.be.true; + }, + "should proceed without mutating arguments if `next(null|undefined)` is called in a serial pre, and the last argument of the target method is a callback with node-like signature function (err, obj) {...} or function (err) {...}": function () { + var A = function () {}; + _.extend(A, hooks); + var counter = 0; + A.prototype.save = function (callback) { + this.value = 1; + callback(); + }; + A.pre('save', function (next) { + next(null); + }); + A.pre('save', function (next) { + next(undefined); + }); + var a = new A(); + a.save( function (err) { + if (err instanceof Error) counter++; + else counter--; + }); + counter.should.equal(-1); + a.value.should.eql(1); + }, + "should proceed with mutating arguments if `next(null|undefined)` is callback in a serial pre, and the last argument of the target method is not a function": function () { + var A = function () {}; + _.extend(A, hooks); + A.prototype.set = function (v) { + this.value = v; + }; + A.pre('set', function (next) { + next(undefined); + }); + A.pre('set', function (next) { + next(null); + }); + var a = new A(); + a.set(1); + should.strictEqual(null, a.value); + }, + 'should not run any posts if a pre fails': function () { + var A = function () {}; + _.extend(A, hooks); + A.hook('save', function () { + this.value = 2; + }, function (err) {}); + A.pre('save', function (next) { + this.value = 1; + next(new Error()); + }).post('save', function (next) { + this.value = 3; + next(); + }); + var a = new A(); + a.save(); + a.value.should.equal(1); + }, + + "can pass the hook's arguments verbatim to pres": function () { + var A = function () {}; + _.extend(A, hooks); + A.hook('set', function (path, val) { + this[path] = val; + }); + A.pre('set', function (next, path, val) { + path.should.equal('hello'); + val.should.equal('world'); + next(); + }); + var a = new A(); + a.set('hello', 'world'); + a.hello.should.equal('world'); + }, +// "can pass the hook's arguments as an array to pres": function () { +// // Great for dynamic arity - e.g., slice(...) +// var A = function () {}; +// _.extend(A, hooks); +// A.hook('set', function (path, val) { +// this[path] = val; +// }); +// A.pre('set', function (next, hello, world) { +// hello.should.equal('hello'); +// world.should.equal('world'); +// next(); +// }); +// var a = new A(); +// a.set('hello', 'world'); +// assert.equal(a.hello, 'world'); +// }, + "can pass the hook's arguments verbatim to posts": function () { + var A = function () {}; + _.extend(A, hooks); + A.hook('set', function (path, val) { + this[path] = val; + }); + A.post('set', function (next, path, val) { + path.should.equal('hello'); + val.should.equal('world'); + next(); + }); + var a = new A(); + a.set('hello', 'world'); + assert.equal(a.hello, 'world'); + }, +// "can pass the hook's arguments as an array to posts": function () { +// var A = function () {}; +// _.extend(A, hooks); +// A.hook('set', function (path, val) { +// this[path] = val; +// }); +// A.post('set', function (next, halt, args) { +// assert.equal(args[0], 'hello'); +// assert.equal(args[1], 'world'); +// next(); +// }); +// var a = new A(); +// a.set('hello', 'world'); +// assert.equal(a.hello, 'world'); +// }, + "pres should be able to modify and pass on a modified version of the hook's arguments": function () { + var A = function () {}; + _.extend(A, hooks); + A.hook('set', function (path, val) { + this[path] = val; + assert.equal(arguments[2], 'optional'); + }); + A.pre('set', function (next, path, val) { + next('foo', 'bar'); + }); + A.pre('set', function (next, path, val) { + assert.equal(path, 'foo'); + assert.equal(val, 'bar'); + next('rock', 'says', 'optional'); + }); + A.pre('set', function (next, path, val, opt) { + assert.equal(path, 'rock'); + assert.equal(val, 'says'); + assert.equal(opt, 'optional'); + next(); + }); + var a = new A(); + a.set('hello', 'world'); + assert.equal(typeof a.hello, 'undefined'); + a.rock.should.equal('says'); + }, + 'posts should see the modified version of arguments if the pres modified them': function () { + var A = function () {}; + _.extend(A, hooks); + A.hook('set', function (path, val) { + this[path] = val; + }); + A.pre('set', function (next, path, val) { + next('foo', 'bar'); + }); + A.post('set', function (next, path, val) { + path.should.equal('foo'); + val.should.equal('bar'); + }); + var a = new A(); + a.set('hello', 'world'); + assert.equal(typeof a.hello, 'undefined'); + a.foo.should.equal('bar'); + }, + 'should pad missing arguments (relative to expected arguments of the hook) with null': function () { + // Otherwise, with hookFn = function (a, b, next, ), + // if we use hookFn(a), then because the pre functions are of the form + // preFn = function (a, b, next, ), then it actually gets executed with + // preFn(a, next, ), so when we call next() from within preFn, we are actually + // calling () + + var A = function () {}; + _.extend(A, hooks); + A.hook('set', function (path, val, opts) { + this[path] = val; + }); + A.pre('set', function (next, path, val, opts) { + next('foo', 'bar'); + assert.equal(typeof opts, 'undefined'); + }); + var a = new A(); + a.set('hello', 'world'); + }, + + 'should not invoke the target method until all asynchronous middleware have invoked dones': function () { + var counter = 0; + var A = function () {}; + _.extend(A, hooks); + A.hook('set', function (path, val) { + counter++; + this[path] = val; + counter.should.equal(7); + }); + A.pre('set', function (next, path, val) { + counter++; + next(); + }); + A.pre('set', true, function (next, done, path, val) { + counter++; + setTimeout(function () { + counter++; + done(); + }, 1000); + next(); + }); + A.pre('set', function (next, path, val) { + counter++; + next(); + }); + A.pre('set', true, function (next, done, path, val) { + counter++; + setTimeout(function () { + counter++; + done(); + }, 500); + next(); + }); + var a = new A(); + a.set('hello', 'world'); + }, + + 'invoking a method twice should run its async middleware twice': function () { + var counter = 0; + var A = function () {}; + _.extend(A, hooks); + A.hook('set', function (path, val) { + this[path] = val; + if (path === 'hello') counter.should.equal(1); + if (path === 'foo') counter.should.equal(2); + }); + A.pre('set', true, function (next, done, path, val) { + setTimeout(function () { + counter++; + done(); + }, 1000); + next(); + }); + var a = new A(); + a.set('hello', 'world'); + a.set('foo', 'bar'); + }, + + 'calling the same done multiple times should have the effect of only calling it once': function () { + var A = function () { + this.acked = false; + }; + _.extend(A, hooks); + A.hook('ack', function () { + console.log("UH OH, YOU SHOULD NOT BE SEEING THIS"); + this.acked = true; + }); + A.pre('ack', true, function (next, done) { + next(); + done(); + done(); + }); + A.pre('ack', true, function (next, done) { + next(); + // Notice that done() is not invoked here + }); + var a = new A(); + a.ack(); + setTimeout( function () { + a.acked.should.be.false; + }, 1000); + }, + + 'calling the same next multiple times should have the effect of only calling it once': function (beforeExit) { + var A = function () { + this.acked = false; + }; + _.extend(A, hooks); + A.hook('ack', function () { + console.log("UH OH, YOU SHOULD NOT BE SEEING THIS"); + this.acked = true; + }); + A.pre('ack', function (next) { + // force a throw to re-exec next() + try { + next(new Error('bam')); + } catch (err) { + next(); + } + }); + A.pre('ack', function (next) { + next(); + }); + var a = new A(); + a.ack(); + beforeExit( function () { + a.acked.should.be.false; + }); + }, + + 'asynchronous middleware should be able to pass an error via `done`, stopping the middleware chain': function () { + var counter = 0; + var A = function () {}; + _.extend(A, hooks); + A.hook('set', function (path, val, fn) { + counter++; + this[path] = val; + fn(null); + }); + A.pre('set', true, function (next, done, path, val, fn) { + setTimeout(function () { + counter++; + done(new Error); + }, 1000); + next(); + }); + var a = new A(); + a.set('hello', 'world', function (err) { + err.should.be.an.instanceof(Error); + should.strictEqual(undefined, a['hello']); + counter.should.eql(1); + }); + }, + + 'should be able to remove a particular pre': function () { + var A = function () {} + , preTwo; + _.extend(A, hooks); + A.hook('save', function () { + this.value = 1; + }); + A.pre('save', function (next) { + this.preValueOne = 2; + next(); + }); + A.pre('save', preTwo = function (next) { + this.preValueTwo = 4; + next(); + }); + A.removePre('save', preTwo); + var a = new A(); + a.save(); + a.value.should.equal(1); + a.preValueOne.should.equal(2); + should.strictEqual(undefined, a.preValueTwo); + }, + + 'should be able to remove all pres associated with a hook': function () { + var A = function () {}; + _.extend(A, hooks); + A.hook('save', function () { + this.value = 1; + }); + A.pre('save', function (next) { + this.preValueOne = 2; + next(); + }); + A.pre('save', function (next) { + this.preValueTwo = 4; + next(); + }); + A.removePre('save'); + var a = new A(); + a.save(); + a.value.should.equal(1); + should.strictEqual(undefined, a.preValueOne); + should.strictEqual(undefined, a.preValueTwo); + }, + + '#pre should lazily make a method hookable': function () { + var A = function () {}; + _.extend(A, hooks); + A.prototype.save = function () { + this.value = 1; + }; + A.pre('save', function (next) { + this.preValue = 2; + next(); + }); + var a = new A(); + a.save(); + a.value.should.equal(1); + a.preValue.should.equal(2); + }, + + '#pre lazily making a method hookable should be able to provide a default errorHandler as the last argument': function () { + var A = function () {}; + var preValue = ""; + _.extend(A, hooks); + A.prototype.save = function () { + this.value = 1; + }; + A.pre('save', function (next) { + next(new Error); + }, function (err) { + preValue = 'ERROR'; + }); + var a = new A(); + a.save(); + should.strictEqual(undefined, a.value); + preValue.should.equal('ERROR'); + }, + + '#post should lazily make a method hookable': function () { + var A = function () {}; + _.extend(A, hooks); + A.prototype.save = function () { + this.value = 1; + }; + A.post('save', function (next) { + this.value = 2; + next(); + }); + var a = new A(); + a.save(); + a.value.should.equal(2); + }, + + "a lazy hooks setup should handle errors via a method's last argument, if it's a callback": function () { + var A = function () {}; + _.extend(A, hooks); + A.prototype.save = function (fn) {}; + A.pre('save', function (next) { + next(new Error("hi there")); + }); + var a = new A(); + a.save( function (err) { + err.should.be.an.instanceof(Error); + }); + } +}; diff --git a/node_modules/mongoose/node_modules/mongodb/.travis.yml b/node_modules/mongoose/node_modules/mongodb/.travis.yml new file mode 100644 index 0000000..0140117 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - 0.6 + - 0.8 + - 0.10 # development version of 0.8, may be unstable \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/CONTRIBUTING.md b/node_modules/mongoose/node_modules/mongodb/CONTRIBUTING.md new file mode 100644 index 0000000..2a1c52e --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/CONTRIBUTING.md @@ -0,0 +1,23 @@ +## Contributing to the driver + +### Bugfixes + +- Before starting to write code, look for existing [tickets](https://github.com/mongodb/node-mongodb-native/issues) or [create one](https://github.com/mongodb/node-mongodb-native/issues/new) for your specific issue. That way you avoid working on something that might not be of interest or that has been addressed already in a different branch. +- Fork the [repo](https://github.com/mongodb/node-mongodb-native) _or_ for small documentation changes, navigate to the source on github and click the [Edit](https://github.com/blog/844-forking-with-the-edit-button) button. +- Follow the general coding style of the rest of the project: + - 2 space tabs + - no trailing whitespace + - comma last + - inline documentation for new methods, class members, etc + - 0 space between conditionals/functions, and their parenthesis and curly braces + - `if(..) {` + - `for(..) {` + - `while(..) {` + - `function(err) {` +- Write tests and make sure they pass (execute `make test` from the cmd line to run the test suite). + +### Documentation + +To contribute to the [API documentation](http://mongodb.github.com/node-mongodb-native/) just make your changes to the inline documentation of the appropriate [source code](https://github.com/mongodb/node-mongodb-native/tree/master/docs) in the master branch and submit a [pull request](https://help.github.com/articles/using-pull-requests/). You might also use the github [Edit](https://github.com/blog/844-forking-with-the-edit-button) button. + +If you'd like to preview your documentation changes, first commit your changes to your local master branch, then execute `make generate_docs`. Make sure you have the python documentation framework sphinx installed `easy_install sphinx`. The docs are generated under `docs/build'. If all looks good, submit a [pull request](https://help.github.com/articles/using-pull-requests/) to the master branch with your changes. \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/LICENSE b/node_modules/mongoose/node_modules/mongodb/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/node_modules/mongoose/node_modules/mongodb/Makefile b/node_modules/mongoose/node_modules/mongodb/Makefile new file mode 100644 index 0000000..59d2bfe --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/Makefile @@ -0,0 +1,28 @@ +NODE = node +NPM = npm +NODEUNIT = node_modules/nodeunit/bin/nodeunit +DOX = node_modules/dox/bin/dox +name = all + +total: build_native + +test_functional: + node test/runner.js -t functional + +test_ssl: + node test/runner.js -t ssl + +test_replicaset: + node test/runner.js -t replicaset + +test_sharded: + node test/runner.js -t sharded + +test_auth: + node test/runner.js -t auth + +generate_docs: + $(NODE) dev/tools/build-docs.js + make --directory=./docs/sphinx-docs --file=Makefile html + +.PHONY: total diff --git a/node_modules/mongoose/node_modules/mongodb/Readme.md b/node_modules/mongoose/node_modules/mongodb/Readme.md new file mode 100644 index 0000000..0d4830f --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/Readme.md @@ -0,0 +1,421 @@ +Up to date documentation +======================== + +[Documentation](http://mongodb.github.com/node-mongodb-native/) + +Install +======= + +To install the most recent release from npm, run: + + npm install mongodb + +That may give you a warning telling you that bugs['web'] should be bugs['url'], it would be safe to ignore it (this has been fixed in the development version) + +To install the latest from the repository, run:: + + npm install path/to/node-mongodb-native + +Community +========= +Check out the google group [node-mongodb-native](http://groups.google.com/group/node-mongodb-native) for questions/answers from users of the driver. + +Live Examples +============ + + +Introduction +============ + +This is a node.js driver for MongoDB. It's a port (or close to a port) of the library for ruby at http://github.com/mongodb/mongo-ruby-driver/. + +A simple example of inserting a document. + +```javascript + var MongoClient = require('mongodb').MongoClient + , format = require('util').format; + + MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) { + if(err) throw err; + + var collection = db.collection('test_insert'); + collection.insert({a:2}, function(err, docs) { + + collection.count(function(err, count) { + console.log(format("count = %s", count)); + }); + + // Locate all the entries using find + collection.find().toArray(function(err, results) { + console.dir(results); + // Let's close the db + db.close(); + }); + }); + }) +``` + +Data types +========== + +To store and retrieve the non-JSON MongoDb primitives ([ObjectID](http://www.mongodb.org/display/DOCS/Object+IDs), Long, Binary, [Timestamp](http://www.mongodb.org/display/DOCS/Timestamp+data+type), [DBRef](http://www.mongodb.org/display/DOCS/Database+References#DatabaseReferences-DBRef), Code). + +In particular, every document has a unique `_id` which can be almost any type, and by default a 12-byte ObjectID is created. ObjectIDs can be represented as 24-digit hexadecimal strings, but you must convert the string back into an ObjectID before you can use it in the database. For example: + +```javascript + // Get the objectID type + var ObjectID = require('mongodb').ObjectID; + + var idString = '4e4e1638c85e808431000003'; + collection.findOne({_id: new ObjectID(idString)}, console.log) // ok + collection.findOne({_id: idString}, console.log) // wrong! callback gets undefined +``` + +Here are the constructors the non-Javascript BSON primitive types: + +```javascript + // Fetch the library + var mongo = require('mongodb'); + // Create new instances of BSON types + new mongo.Long(numberString) + new mongo.ObjectID(hexString) + new mongo.Timestamp() // the actual unique number is generated on insert. + new mongo.DBRef(collectionName, id, dbName) + new mongo.Binary(buffer) // takes a string or Buffer + new mongo.Code(code, [context]) + new mongo.Symbol(string) + new mongo.MinKey() + new mongo.MaxKey() + new mongo.Double(number) // Force double storage +``` + +The C/C++ bson parser/serializer +-------------------------------- + +If you are running a version of this library has the C/C++ parser compiled, to enable the driver to use the C/C++ bson parser pass it the option native_parser:true like below + +```javascript + // using native_parser: + MongoClient.connect('mongodb://127.0.0.1:27017/test' + , {db: {native_parser: true}}, function(err, db) {}) +``` + +The C++ parser uses the js objects both for serialization and deserialization. + +GitHub information +================== + +The source code is available at http://github.com/mongodb/node-mongodb-native. +You can either clone the repository or download a tarball of the latest release. + +Once you have the source you can test the driver by running + + $ make test + +in the main directory. You will need to have a mongo instance running on localhost for the integration tests to pass. + +Examples +======== + +For examples look in the examples/ directory. You can execute the examples using node. + + $ cd examples + $ node queries.js + +GridStore +========= + +The GridStore class allows for storage of binary files in mongoDB using the mongoDB defined files and chunks collection definition. + +For more information have a look at [Gridstore](https://github.com/mongodb/node-mongodb-native/blob/master/docs/gridfs.md) + +Replicasets +=========== +For more information about how to connect to a replicaset have a look at the extensive documentation [Documentation](http://mongodb.github.com/node-mongodb-native/) + +Primary Key Factories +--------------------- + +Defining your own primary key factory allows you to generate your own series of id's +(this could f.ex be to use something like ISBN numbers). The generated the id needs to be a 12 byte long "string". + +Simple example below + +```javascript + var MongoClient = require('mongodb').MongoClient + , format = require('util').format; + + // Custom factory (need to provide a 12 byte array); + CustomPKFactory = function() {} + CustomPKFactory.prototype = new Object(); + CustomPKFactory.createPk = function() { + return new ObjectID("aaaaaaaaaaaa"); + } + + MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) { + if(err) throw err; + + db.dropDatabase(function(err, done) { + + db.createCollection('test_custom_key', function(err, collection) { + + collection.insert({'a':1}, function(err, docs) { + + collection.find({'_id':new ObjectID("aaaaaaaaaaaa")}).toArray(function(err, items) { + console.dir(items); + // Let's close the db + db.close(); + }); + }); + }); + }); + }); +``` + +Documentation +============= + +If this document doesn't answer your questions, see the source of +[Collection](https://github.com/mongodb/node-mongodb-native/blob/master/lib/mongodb/collection.js) +or [Cursor](https://github.com/mongodb/node-mongodb-native/blob/master/lib/mongodb/cursor.js), +or the documentation at MongoDB for query and update formats. + +Find +---- + +The find method is actually a factory method to create +Cursor objects. A Cursor lazily uses the connection the first time +you call `nextObject`, `each`, or `toArray`. + +The basic operation on a cursor is the `nextObject` method +that fetches the next matching document from the database. The convenience +methods `each` and `toArray` call `nextObject` until the cursor is exhausted. + +Signatures: + +```javascript + var cursor = collection.find(query, [fields], options); + cursor.sort(fields).limit(n).skip(m). + + cursor.nextObject(function(err, doc) {}); + cursor.each(function(err, doc) {}); + cursor.toArray(function(err, docs) {}); + + cursor.rewind() // reset the cursor to its initial state. +``` + +Useful chainable methods of cursor. These can optionally be options of `find` instead of method calls: + + * `.limit(n).skip(m)` to control paging. + * `.sort(fields)` Order by the given fields. There are several equivalent syntaxes: + * `.sort({field1: -1, field2: 1})` descending by field1, then ascending by field2. + * `.sort([['field1', 'desc'], ['field2', 'asc']])` same as above + * `.sort([['field1', 'desc'], 'field2'])` same as above + * `.sort('field1')` ascending by field1 + +Other options of `find`: + +* `fields` the fields to fetch (to avoid transferring the entire document) +* `tailable` if true, makes the cursor [tailable](http://www.mongodb.org/display/DOCS/Tailable+Cursors). +* `batchSize` The number of the subset of results to request the database +to return for every request. This should initially be greater than 1 otherwise +the database will automatically close the cursor. The batch size can be set to 1 +with `batchSize(n, function(err){})` after performing the initial query to the database. +* `hint` See [Optimization: hint](http://www.mongodb.org/display/DOCS/Optimization#Optimization-Hint). +* `explain` turns this into an explain query. You can also call +`explain()` on any cursor to fetch the explanation. +* `snapshot` prevents documents that are updated while the query is active +from being returned multiple times. See more +[details about query snapshots](http://www.mongodb.org/display/DOCS/How+to+do+Snapshotted+Queries+in+the+Mongo+Database). +* `timeout` if false, asks MongoDb not to time out this cursor after an +inactivity period. + + +For information on how to create queries, see the +[MongoDB section on querying](http://www.mongodb.org/display/DOCS/Querying). + +```javascript + var MongoClient = require('mongodb').MongoClient + , format = require('util').format; + + MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) { + if(err) throw err; + + var collection = db + .collection('test') + .find({}) + .limit(10) + .toArray(function(err, docs) { + console.dir(docs); + }); + }); +``` + +Insert +------ + +Signature: + +```javascript + collection.insert(docs, options, [callback]); +``` + +where `docs` can be a single document or an array of documents. + +Useful options: + +* `safe:true` Should always set if you have a callback. + +See also: [MongoDB docs for insert](http://www.mongodb.org/display/DOCS/Inserting). + +```javascript + var MongoClient = require('mongodb').MongoClient + , format = require('util').format; + + MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) { + if(err) throw err; + + db.collection('test').insert({hello: 'world'}, {w:1}, function(err, objects) { + if (err) console.warn(err.message); + if (err && err.message.indexOf('E11000 ') !== -1) { + // this _id was already inserted in the database + } + }); + }); +``` + +Note that there's no reason to pass a callback to the insert or update commands +unless you use the `safe:true` option. If you don't specify `safe:true`, then +your callback will be called immediately. + +Update; update and insert (upsert) +---------------------------------- + +The update operation will update the first document that matches your query +(or all documents that match if you use `multi:true`). +If `safe:true`, `upsert` is not set, and no documents match, your callback will return 0 documents updated. + +See the [MongoDB docs](http://www.mongodb.org/display/DOCS/Updating) for +the modifier (`$inc`, `$set`, `$push`, etc.) formats. + +Signature: + +```javascript + collection.update(criteria, objNew, options, [callback]); +``` + +Useful options: + +* `safe:true` Should always set if you have a callback. +* `multi:true` If set, all matching documents are updated, not just the first. +* `upsert:true` Atomically inserts the document if no documents matched. + +Example for `update`: + +```javascript + var MongoClient = require('mongodb').MongoClient + , format = require('util').format; + + MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) { + if(err) throw err; + + db.collection('test').update({hi: 'here'}, {$set: {hi: 'there'}}, {w:1}, function(err) { + if (err) console.warn(err.message); + else console.log('successfully updated'); + }); + }); +``` + +Find and modify +--------------- + +`findAndModify` is like `update`, but it also gives the updated document to +your callback. But there are a few key differences between findAndModify and +update: + + 1. The signatures differ. + 2. You can only findAndModify a single item, not multiple items. + +Signature: + +```javascript + collection.findAndModify(query, sort, update, options, callback) +``` + +The sort parameter is used to specify which object to operate on, if more than +one document matches. It takes the same format as the cursor sort (see +Connection.find above). + +See the +[MongoDB docs for findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) +for more details. + +Useful options: + +* `remove:true` set to a true to remove the object before returning +* `new:true` set to true if you want to return the modified object rather than the original. Ignored for remove. +* `upsert:true` Atomically inserts the document if no documents matched. + +Example for `findAndModify`: + +```javascript + var MongoClient = require('mongodb').MongoClient + , format = require('util').format; + + MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) { + if(err) throw err; + db.collection('test').findAndModify({hello: 'world'}, [['_id','asc']], {$set: {hi: 'there'}}, {}, function(err, object) { + if (err) console.warn(err.message); + else console.dir(object); // undefined if no matching object exists. + }); + }); +``` + +Save +---- + +The `save` method is a shorthand for upsert if the document contains an +`_id`, or an insert if there is no `_id`. + +Sponsors +======== +Just as Felix Geisendörfer I'm also working on the driver for my own startup and this driver is a big project that also benefits other companies who are using MongoDB. + +If your company could benefit from a even better-engineered node.js mongodb driver I would appreciate any type of sponsorship you may be able to provide. All the sponsors will get a lifetime display in this readme, priority support and help on problems and votes on the roadmap decisions for the driver. If you are interested contact me on [christkv AT g m a i l.com](mailto:christkv@gmail.com) for details. + +And I'm very thankful for code contributions. If you are interested in working on features please contact me so we can discuss API design and testing. + +Release Notes +============= + +See HISTORY + +Credits +======= + +1. [10gen](http://github.com/mongodb/mongo-ruby-driver/) +2. [Google Closure Library](http://code.google.com/closure/library/) +3. [Jonas Raoni Soares Silva](http://jsfromhell.com/classes/binary-parser) + +Contributors +============ + +Aaron Heckmann, Christoph Pojer, Pau Ramon Revilla, Nathan White, Emmerman, Seth LaForge, Boris Filipov, Stefan Schärmeli, Tedde Lundgren, renctan, Sergey Ukustov, Ciaran Jessup, kuno, srimonti, Erik Abele, Pratik Daga, Slobodan Utvic, Kristina Chodorow, Yonathan Randolph, Brian Noguchi, Sam Epstein, James Harrison Fisher, Vladimir Dronnikov, Ben Hockey, Henrik Johansson, Simon Weare, Alex Gorbatchev, Shimon Doodkin, Kyle Mueller, Eran Hammer-Lahav, Marcin Ciszak, François de Metz, Vinay Pulim, nstielau, Adam Wiggins, entrinzikyl, Jeremy Selier, Ian Millington, Public Keating, andrewjstone, Christopher Stott, Corey Jewett, brettkiefer, Rob Holland, Senmiao Liu, heroic, gitfy + +License +======= + + Copyright 2009 - 2012 Christian Amor Kvalheim. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/node_modules/mongoose/node_modules/mongodb/index.js b/node_modules/mongoose/node_modules/mongodb/index.js new file mode 100755 index 0000000..4f59e9d --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/mongodb'); diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/admin.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/admin.js new file mode 100644 index 0000000..6e9cd30 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/admin.js @@ -0,0 +1,339 @@ +/*! + * Module dependencies. + */ +var Collection = require('./collection').Collection, + Cursor = require('./cursor').Cursor, + DbCommand = require('./commands/db_command').DbCommand, + utils = require('./utils'); + +/** + * Allows the user to access the admin functionality of MongoDB + * + * @class Represents the Admin methods of MongoDB. + * @param {Object} db Current db instance we wish to perform Admin operations on. + * @return {Function} Constructor for Admin type. + */ +function Admin(db) { + if(!(this instanceof Admin)) return new Admin(db); + this.db = db; +}; + +/** + * Retrieve the server information for the current + * instance of the db client + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from buildInfo or null if an error occured. + * @return {null} Returns no result + * @api public + */ +Admin.prototype.buildInfo = function(callback) { + this.serverInfo(callback); +} + +/** + * Retrieve the server information for the current + * instance of the db client + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from serverInfo or null if an error occured. + * @return {null} Returns no result + * @api private + */ +Admin.prototype.serverInfo = function(callback) { + this.db.executeDbAdminCommand({buildinfo:1}, function(err, doc) { + if(err != null) return callback(err, null); + return callback(null, doc.documents[0]); + }); +} + +/** + * Retrieve this db's server status. + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from serverStatus or null if an error occured. + * @return {null} + * @api public + */ +Admin.prototype.serverStatus = function(callback) { + var self = this; + + this.db.executeDbAdminCommand({serverStatus: 1}, function(err, doc) { + if(err == null && doc.documents[0].ok === 1) { + callback(null, doc.documents[0]); + } else { + if(err) return callback(err, false); + return callback(utils.toError(doc.documents[0]), false); + } + }); +}; + +/** + * Retrieve the current profiling Level for MongoDB + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from profilingLevel or null if an error occured. + * @return {null} Returns no result + * @api public + */ +Admin.prototype.profilingLevel = function(callback) { + var self = this; + + this.db.executeDbAdminCommand({profile:-1}, function(err, doc) { + doc = doc.documents[0]; + + if(err == null && doc.ok === 1) { + var was = doc.was; + if(was == 0) return callback(null, "off"); + if(was == 1) return callback(null, "slow_only"); + if(was == 2) return callback(null, "all"); + return callback(new Error("Error: illegal profiling level value " + was), null); + } else { + err != null ? callback(err, null) : callback(new Error("Error with profile command"), null); + } + }); +}; + +/** + * Ping the MongoDB server and retrieve results + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from ping or null if an error occured. + * @return {null} Returns no result + * @api public + */ +Admin.prototype.ping = function(options, callback) { + // Unpack calls + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + + this.db.executeDbAdminCommand({ping: 1}, callback); +} + +/** + * Authenticate against MongoDB + * + * @param {String} username The user name for the authentication. + * @param {String} password The password for the authentication. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from authenticate or null if an error occured. + * @return {null} Returns no result + * @api public + */ +Admin.prototype.authenticate = function(username, password, callback) { + this.db.authenticate(username, password, {authdb: 'admin'}, function(err, doc) { + return callback(err, doc); + }) +} + +/** + * Logout current authenticated user + * + * @param {Object} [options] Optional parameters to the command. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from logout or null if an error occured. + * @return {null} Returns no result + * @api public + */ +Admin.prototype.logout = function(callback) { + this.db.logout({authdb: 'admin'}, function(err, doc) { + return callback(err, doc); + }) +} + +/** + * Add a user to the MongoDB server, if the user exists it will + * overwrite the current password + * + * Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @param {String} username The user name for the authentication. + * @param {String} password The password for the authentication. + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from addUser or null if an error occured. + * @return {null} Returns no result + * @api public + */ +Admin.prototype.addUser = function(username, password, options, callback) { + var args = Array.prototype.slice.call(arguments, 2); + callback = args.pop(); + options = args.length ? args.shift() : {}; + + options.dbName = 'admin'; + // Add user + this.db.addUser(username, password, options, function(err, doc) { + return callback(err, doc); + }) +} + +/** + * Remove a user from the MongoDB server + * + * Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @param {String} username The user name for the authentication. + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from removeUser or null if an error occured. + * @return {null} Returns no result + * @api public + */ +Admin.prototype.removeUser = function(username, options, callback) { + var self = this; + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + options = args.length ? args.shift() : {}; + options.dbName = 'admin'; + + this.db.removeUser(username, options, function(err, doc) { + return callback(err, doc); + }) +} + +/** + * Set the current profiling level of MongoDB + * + * @param {String} level The new profiling level (off, slow_only, all) + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from setProfilingLevel or null if an error occured. + * @return {null} Returns no result + * @api public + */ +Admin.prototype.setProfilingLevel = function(level, callback) { + var self = this; + var command = {}; + var profile = 0; + + if(level == "off") { + profile = 0; + } else if(level == "slow_only") { + profile = 1; + } else if(level == "all") { + profile = 2; + } else { + return callback(new Error("Error: illegal profiling level value " + level)); + } + + // Set up the profile number + command['profile'] = profile; + + this.db.executeDbAdminCommand(command, function(err, doc) { + doc = doc.documents[0]; + + if(err == null && doc.ok === 1) + return callback(null, level); + return err != null ? callback(err, null) : callback(new Error("Error with profile command"), null); + }); +}; + +/** + * Retrive the current profiling information for MongoDB + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from profilingInfo or null if an error occured. + * @return {null} Returns no result + * @api public + */ +Admin.prototype.profilingInfo = function(callback) { + try { + new Cursor(this.db, new Collection(this.db, DbCommand.SYSTEM_PROFILE_COLLECTION), {}, {}, {dbName: 'admin'}).toArray(function(err, items) { + return callback(err, items); + }); + } catch (err) { + return callback(err, null); + } +}; + +/** + * Execute a db command against the Admin database + * + * @param {Object} command A command object `{ping:1}`. + * @param {Object} [options] Optional parameters to the command. + * @param {Function} callback this will be called after executing this method. The command always return the whole result of the command as the second parameter. + * @return {null} Returns no result + * @api public + */ +Admin.prototype.command = function(command, options, callback) { + var self = this; + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + options = args.length ? args.shift() : {}; + + // Execute a command + this.db.executeDbAdminCommand(command, options, function(err, doc) { + // Ensure change before event loop executes + return callback != null ? callback(err, doc) : null; + }); +} + +/** + * Validate an existing collection + * + * @param {String} collectionName The name of the collection to validate. + * @param {Object} [options] Optional parameters to the command. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from validateCollection or null if an error occured. + * @return {null} Returns no result + * @api public + */ +Admin.prototype.validateCollection = function(collectionName, options, callback) { + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + options = args.length ? args.shift() : {}; + + var self = this; + var command = {validate: collectionName}; + var keys = Object.keys(options); + + // Decorate command with extra options + for(var i = 0; i < keys.length; i++) { + if(options.hasOwnProperty(keys[i])) { + command[keys[i]] = options[keys[i]]; + } + } + + this.db.executeDbCommand(command, function(err, doc) { + if(err != null) return callback(err, null); + doc = doc.documents[0]; + + if(doc.ok === 0) + return callback(new Error("Error with validate command"), null); + if(doc.result != null && doc.result.constructor != String) + return callback(new Error("Error with validation data"), null); + if(doc.result != null && doc.result.match(/exception|corrupt/) != null) + return callback(new Error("Error: invalid collection " + collectionName), null); + if(doc.valid != null && !doc.valid) + return callback(new Error("Error: invalid collection " + collectionName), null); + + return callback(null, doc); + }); +}; + +/** + * List the available databases + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from listDatabases or null if an error occured. + * @return {null} Returns no result + * @api public + */ +Admin.prototype.listDatabases = function(callback) { + // Execute the listAllDatabases command + this.db.executeDbAdminCommand({listDatabases:1}, {}, function(err, doc) { + if(err != null) return callback(err, null); + return callback(null, doc.documents[0]); + }); +} + +/** + * Get ReplicaSet status + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from replSetGetStatus or null if an error occured. + * @return {null} + * @api public + */ +Admin.prototype.replSetGetStatus = function(callback) { + var self = this; + + this.db.executeDbAdminCommand({replSetGetStatus:1}, function(err, doc) { + if(err == null && doc.documents[0].ok === 1) + return callback(null, doc.documents[0]); + if(err) return callback(err, false); + return callback(utils.toError(doc.documents[0]), false); + }); +}; + +/** + * @ignore + */ +exports.Admin = Admin; diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/auth/mongodb_cr.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/auth/mongodb_cr.js new file mode 100644 index 0000000..0955896 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/auth/mongodb_cr.js @@ -0,0 +1,57 @@ +var DbCommand = require('../commands/db_command').DbCommand + , utils = require('../utils'); + +var authenticate = function(db, username, password, authdb, options, callback) { + var numberOfConnections = 0; + var errorObject = null; + + if(options['connection'] != null) { + //if a connection was explicitly passed on options, then we have only one... + numberOfConnections = 1; + } else { + // Get the amount of connections in the pool to ensure we have authenticated all comments + numberOfConnections = db.serverConfig.allRawConnections().length; + options['onAll'] = true; + } + + // Execute all four + db._executeQueryCommand(DbCommand.createGetNonceCommand(db), options, function(err, result, connection) { + // Execute on all the connections + if(err == null) { + // Nonce used to make authentication request with md5 hash + var nonce = result.documents[0].nonce; + // Execute command + db._executeQueryCommand(DbCommand.createAuthenticationCommand(db, username, password, nonce, authdb), {connection:connection}, function(err, result) { + // Count down + numberOfConnections = numberOfConnections - 1; + // Ensure we save any error + if(err) { + errorObject = err; + } else if(result + && Array.isArray(result.documents) + && result.documents.length > 0 + && (result.documents[0].err != null || result.documents[0].errmsg != null)) { + errorObject = utils.toError(result.documents[0]); + } + + // Work around the case where the number of connections are 0 + if(numberOfConnections <= 0 && typeof callback == 'function') { + var internalCallback = callback; + callback = null; + + if(errorObject == null + && result && Array.isArray(result.documents) && result.documents.length > 0 + && result.documents[0].ok == 1) { // We authenticated correctly save the credentials + db.serverConfig.auth.add('MONGODB-CR', db.databaseName, username, password, authdb); + // Return callback + internalCallback(errorObject, true); + } else { + internalCallback(errorObject, false); + } + } + }); + } + }); +} + +exports.authenticate = authenticate; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/auth/mongodb_gssapi.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/auth/mongodb_gssapi.js new file mode 100644 index 0000000..47b5155 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/auth/mongodb_gssapi.js @@ -0,0 +1,149 @@ +var DbCommand = require('../commands/db_command').DbCommand + , utils = require('../utils') + , format = require('util').format; + +// Kerberos class +var Kerberos = null; +var MongoAuthProcess = null; +// Try to grab the Kerberos class +try { + Kerberos = require('kerberos').Kerberos + // Authentication process for Mongo + MongoAuthProcess = require('kerberos').processes.MongoAuthProcess +} catch(err) {} + +var authenticate = function(db, username, password, authdb, options, callback) { + var numberOfConnections = 0; + var errorObject = null; + // We don't have the Kerberos library + if(Kerberos == null) return callback(new Error("Kerberos library is not installed")); + + if(options['connection'] != null) { + //if a connection was explicitly passed on options, then we have only one... + numberOfConnections = 1; + } else { + // Get the amount of connections in the pool to ensure we have authenticated all comments + numberOfConnections = db.serverConfig.allRawConnections().length; + options['onAll'] = true; + } + + // Grab all the connections + var connections = options['connection'] != null ? [options['connection']] : db.serverConfig.allRawConnections(); + var gssapiServiceName = options['gssapiServiceName'] || 'mongodb'; + var error = null; + // Authenticate all connections + for(var i = 0; i < numberOfConnections; i++) { + + // Start Auth process for a connection + GSSAPIInitialize(db, username, password, authdb, gssapiServiceName, connections[i], function(err, result) { + // Adjust number of connections left to connect + numberOfConnections = numberOfConnections - 1; + // If we have an error save it + if(err) error = err; + + // We are done + if(numberOfConnections == 0) { + if(err) return callback(error, false); + // We authenticated correctly save the credentials + db.serverConfig.auth.add('GSSAPI', db.databaseName, username, password, authdb, gssapiServiceName); + // Return valid callback + return callback(null, true); + } + }); + } +} + +// +// Initialize step +var GSSAPIInitialize = function(db, username, password, authdb, gssapiServiceName, connection, callback) { + // Create authenticator + var mongo_auth_process = new MongoAuthProcess(connection.socketOptions.host, connection.socketOptions.port, gssapiServiceName); + + // Perform initialization + mongo_auth_process.init(username, password, function(err, context) { + if(err) return callback(err, false); + + // Perform the first step + mongo_auth_process.transition('', function(err, payload) { + if(err) return callback(err, false); + + // Call the next db step + MongoDBGSSAPIFirstStep(mongo_auth_process, payload, db, username, password, authdb, connection, callback); + }); + }); +} + +// +// Perform first step against mongodb +var MongoDBGSSAPIFirstStep = function(mongo_auth_process, payload, db, username, password, authdb, connection, callback) { + // Build the sasl start command + var command = { + saslStart: 1 + , mechanism: 'GSSAPI' + , payload: payload + , autoAuthorize: 1 + }; + + // Execute first sasl step + db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) { + if(err) return callback(err, false); + // Get the payload + doc = doc.documents[0]; + var db_payload = doc.payload; + + mongo_auth_process.transition(doc.payload, function(err, payload) { + if(err) return callback(err, false); + + // MongoDB API Second Step + MongoDBGSSAPISecondStep(mongo_auth_process, payload, doc, db, username, password, authdb, connection, callback); + }); + }); +} + +// +// Perform first step against mongodb +var MongoDBGSSAPISecondStep = function(mongo_auth_process, payload, doc, db, username, password, authdb, connection, callback) { + // Build Authentication command to send to MongoDB + var command = { + saslContinue: 1 + , conversationId: doc.conversationId + , payload: payload + }; + + // Execute the command + db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) { + if(err) return callback(err, false); + + // Get the result document + doc = doc.documents[0]; + + // Call next transition for kerberos + mongo_auth_process.transition(doc.payload, function(err, payload) { + if(err) return callback(err, false); + + // Call the last and third step + MongoDBGSSAPIThirdStep(mongo_auth_process, payload, doc, db, username, password, authdb, connection, callback); + }); + }); +} + +var MongoDBGSSAPIThirdStep = function(mongo_auth_process, payload, doc, db, username, password, authdb, connection, callback) { + // Build final command + var command = { + saslContinue: 1 + , conversationId: doc.conversationId + , payload: payload + }; + + // Let's finish the auth process against mongodb + db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) { + if(err) return callback(err, false); + + mongo_auth_process.transition(null, function(err, payload) { + if(err) return callback(err, false); + callback(null, true); + }); + }); +} + +exports.authenticate = authenticate; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/auth/mongodb_plain.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/auth/mongodb_plain.js new file mode 100644 index 0000000..594181d --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/auth/mongodb_plain.js @@ -0,0 +1,66 @@ +var DbCommand = require('../commands/db_command').DbCommand + , utils = require('../utils') + , Binary = require('bson').Binary + , format = require('util').format; + +var authenticate = function(db, username, password, options, callback) { + var numberOfConnections = 0; + var errorObject = null; + + if(options['connection'] != null) { + //if a connection was explicitly passed on options, then we have only one... + numberOfConnections = 1; + } else { + // Get the amount of connections in the pool to ensure we have authenticated all comments + numberOfConnections = db.serverConfig.allRawConnections().length; + options['onAll'] = true; + } + + // Create payload + var payload = new Binary(format("\x00%s\x00%s", username, password)); + + // Let's start the sasl process + var command = { + saslStart: 1 + , mechanism: 'PLAIN' + , payload: payload + , autoAuthorize: 1 + }; + + // Grab all the connections + var connections = options['connection'] != null ? [options['connection']] : db.serverConfig.allRawConnections(); + + // Authenticate all connections + for(var i = 0; i < numberOfConnections; i++) { + var connection = connections[i]; + // Execute first sasl step + db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, result) { + // Count down + numberOfConnections = numberOfConnections - 1; + + // Ensure we save any error + if(err) { + errorObject = err; + } else if(result.documents[0].err != null || result.documents[0].errmsg != null){ + errorObject = utils.toError(result.documents[0]); + } + + // Work around the case where the number of connections are 0 + if(numberOfConnections <= 0 && typeof callback == 'function') { + var internalCallback = callback; + callback = null; + + if(errorObject == null && result.documents[0].ok == 1) { + // We authenticated correctly save the credentials + db.serverConfig.auth.add('PLAIN', db.databaseName, username, password); + // Return callback + internalCallback(errorObject, true); + } else { + internalCallback(errorObject, false); + } + } + }); + } +} + +exports.authenticate = authenticate; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/auth/mongodb_sspi.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/auth/mongodb_sspi.js new file mode 100644 index 0000000..316fa3a --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/auth/mongodb_sspi.js @@ -0,0 +1,135 @@ +var DbCommand = require('../commands/db_command').DbCommand + , utils = require('../utils') + , format = require('util').format; + +// Kerberos class +var Kerberos = null; +var MongoAuthProcess = null; +// Try to grab the Kerberos class +try { + Kerberos = require('kerberos').Kerberos + // Authentication process for Mongo + MongoAuthProcess = require('kerberos').processes.MongoAuthProcess +} catch(err) {} + +var authenticate = function(db, username, password, authdb, options, callback) { + var numberOfConnections = 0; + var errorObject = null; + // We don't have the Kerberos library + if(Kerberos == null) return callback(new Error("Kerberos library is not installed")); + + if(options['connection'] != null) { + //if a connection was explicitly passed on options, then we have only one... + numberOfConnections = 1; + } else { + // Get the amount of connections in the pool to ensure we have authenticated all comments + numberOfConnections = db.serverConfig.allRawConnections().length; + options['onAll'] = true; + } + + // Set the sspi server name + var gssapiServiceName = options['gssapiServiceName'] || 'mongodb'; + + // Grab all the connections + var connections = db.serverConfig.allRawConnections(); + var error = null; + + // Authenticate all connections + for(var i = 0; i < numberOfConnections; i++) { + // Start Auth process for a connection + SSIPAuthenticate(db, username, password, authdb, gssapiServiceName, connections[i], function(err, result) { + // Adjust number of connections left to connect + numberOfConnections = numberOfConnections - 1; + // If we have an error save it + if(err) error = err; + + // We are done + if(numberOfConnections == 0) { + if(err) return callback(err, false); + // We authenticated correctly save the credentials + db.serverConfig.auth.add('GSSAPI', db.databaseName, username, password, authdb, gssapiServiceName); + // Return valid callback + return callback(null, true); + } + }); + } +} + +var SSIPAuthenticate = function(db, username, password, authdb, service_name, connection, callback) { + // -------------------------------------------------------------- + // Async Version + // -------------------------------------------------------------- + var command = { + saslStart: 1 + , mechanism: 'GSSAPI' + , payload: '' + , autoAuthorize: 1 + }; + + // Create authenticator + var mongo_auth_process = new MongoAuthProcess(connection.socketOptions.host, connection.socketOptions.port, service_name); + + // Execute first sasl step + db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) { + if(err) return callback(err); + doc = doc.documents[0]; + + mongo_auth_process.init(username, password, function(err) { + if(err) return callback(err); + + mongo_auth_process.transition(doc.payload, function(err, payload) { + if(err) return callback(err); + + // Perform the next step against mongod + var command = { + saslContinue: 1 + , conversationId: doc.conversationId + , payload: payload + }; + + // Execute the command + db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) { + if(err) return callback(err); + doc = doc.documents[0]; + + mongo_auth_process.transition(doc.payload, function(err, payload) { + if(err) return callback(err); + + // Perform the next step against mongod + var command = { + saslContinue: 1 + , conversationId: doc.conversationId + , payload: payload + }; + + // Execute the command + db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) { + if(err) return callback(err); + doc = doc.documents[0]; + + mongo_auth_process.transition(doc.payload, function(err, payload) { + // Perform the next step against mongod + var command = { + saslContinue: 1 + , conversationId: doc.conversationId + , payload: payload + }; + + // Execute the command + db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) { + if(err) return callback(err); + doc = doc.documents[0]; + + if(doc.done) return callback(null, true); + callback(new Error("Authentication failed"), false); + }); + }); + }); + }); + }); + }); + }); + }); +} + +exports.authenticate = authenticate; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/collection.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/collection.js new file mode 100644 index 0000000..7c2ae0f --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/collection.js @@ -0,0 +1,1730 @@ +/** + * Module dependencies. + * @ignore + */ +var InsertCommand = require('./commands/insert_command').InsertCommand + , QueryCommand = require('./commands/query_command').QueryCommand + , DeleteCommand = require('./commands/delete_command').DeleteCommand + , UpdateCommand = require('./commands/update_command').UpdateCommand + , DbCommand = require('./commands/db_command').DbCommand + , ObjectID = require('bson').ObjectID + , Code = require('bson').Code + , Cursor = require('./cursor').Cursor + , utils = require('./utils'); + +/** + * Precompiled regexes + * @ignore +**/ +const eErrorMessages = /No matching object found/; + +/** + * toString helper. + * @ignore + */ +var toString = Object.prototype.toString; + +/** + * Create a new Collection instance (INTERNAL TYPE) + * + * Options + * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST). + * - **slaveOk** {Boolean, default:false}, Allow reads from secondaries. + * - **serializeFunctions** {Boolean, default:false}, serialize functions on the document. + * - **raw** {Boolean, default:false}, perform all operations using raw bson objects. + * - **pkFactory** {Object}, object overriding the basic ObjectID primary key generation. + * + * @class Represents a Collection + * @param {Object} db db instance. + * @param {String} collectionName collection name. + * @param {Object} [pkFactory] alternative primary key factory. + * @param {Object} [options] additional options for the collection. + * @return {Object} a collection instance. + */ +function Collection (db, collectionName, pkFactory, options) { + if(!(this instanceof Collection)) return new Collection(db, collectionName, pkFactory, options); + + checkCollectionName(collectionName); + + this.db = db; + this.collectionName = collectionName; + this.internalHint = null; + this.opts = options != null && ('object' === typeof options) ? options : {}; + this.slaveOk = options == null || options.slaveOk == null ? db.slaveOk : options.slaveOk; + this.serializeFunctions = options == null || options.serializeFunctions == null ? db.serializeFunctions : options.serializeFunctions; + this.raw = options == null || options.raw == null ? db.raw : options.raw; + + this.readPreference = options == null || options.readPreference == null ? db.serverConfig.options.readPreference : options.readPreference; + this.readPreference = this.readPreference == null ? 'primary' : this.readPreference; + + this.pkFactory = pkFactory == null + ? ObjectID + : pkFactory; + + var self = this; +} + +/** + * Inserts a single document or a an array of documents into MongoDB. + * + * Options +* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * - **continueOnError/keepGoing** {Boolean, default:false}, keep inserting documents even if one document has an error, *mongodb 1.9.1 >*. + * - **serializeFunctions** {Boolean, default:false}, serialize functions on the document. + * - **forceServerObjectId** {Boolean, default:false}, let server assign ObjectId instead of the driver + * - **checkKeys** {Boolean, default:true}, allows for disabling of document key checking (WARNING OPENS YOU UP TO INJECTION ATTACKS) + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @param {Array|Object} docs + * @param {Object} [options] optional options for insert command + * @param {Function} [callback] optional callback for the function, must be provided when using a writeconcern + * @return {null} + * @api public + */ +Collection.prototype.insert = function insert (docs, options, callback) { + if ('function' === typeof options) callback = options, options = {}; + if(options == null) options = {}; + if(!('function' === typeof callback)) callback = null; + var self = this; + insertAll(self, Array.isArray(docs) ? docs : [docs], options, callback); + return this; +}; + +/** + * @ignore + */ +var checkCollectionName = function checkCollectionName (collectionName) { + if('string' !== typeof collectionName) { + throw Error("collection name must be a String"); + } + + if(!collectionName || collectionName.indexOf('..') != -1) { + throw Error("collection names cannot be empty"); + } + + if(collectionName.indexOf('$') != -1 && + collectionName.match(/((^\$cmd)|(oplog\.\$main))/) == null) { + throw Error("collection names must not contain '$'"); + } + + if(collectionName.match(/^\.|\.$/) != null) { + throw Error("collection names must not start or end with '.'"); + } + + // Validate that we are not passing 0x00 in the colletion name + if(!!~collectionName.indexOf("\x00")) { + throw new Error("collection names cannot contain a null character"); + } +}; + +/** + * Removes documents specified by `selector` from the db. + * + * Options +* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * - **single** {Boolean, default:false}, removes the first document found. + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @param {Object} [selector] optional select, no selector is equivalent to removing all documents. + * @param {Object} [options] additional options during remove. + * @param {Function} [callback] must be provided if you performing a remove with a writeconcern + * @return {null} + * @api public + */ +Collection.prototype.remove = function remove(selector, options, callback) { + if ('function' === typeof selector) { + callback = selector; + selector = options = {}; + } else if ('function' === typeof options) { + callback = options; + options = {}; + } + + // Ensure options + if(options == null) options = {}; + if(!('function' === typeof callback)) callback = null; + // Ensure we have at least an empty selector + selector = selector == null ? {} : selector; + // Set up flags for the command, if we have a single document remove + var flags = 0 | (options.single ? 1 : 0); + + // DbName + var dbName = options['dbName']; + // If no dbname defined use the db one + if(dbName == null) { + dbName = this.db.databaseName; + } + + // Create a delete command + var deleteCommand = new DeleteCommand( + this.db + , dbName + "." + this.collectionName + , selector + , flags); + + var self = this; + var errorOptions = _getWriteConcern(self, options, callback); + // Execute the command, do not add a callback as it's async + if(_hasWriteConcern(errorOptions) && typeof callback == 'function') { + // Insert options + var commandOptions = {read:false}; + // If we have safe set set async to false + if(errorOptions == null) commandOptions['async'] = true; + // Set safe option + commandOptions['safe'] = true; + // If we have an error option + if(typeof errorOptions == 'object') { + var keys = Object.keys(errorOptions); + for(var i = 0; i < keys.length; i++) { + commandOptions[keys[i]] = errorOptions[keys[i]]; + } + } + + // Execute command with safe options (rolls up both command and safe command into one and executes them on the same connection) + this.db._executeRemoveCommand(deleteCommand, commandOptions, function (err, error) { + error = error && error.documents; + if(!callback) return; + + if(err) { + callback(err); + } else if(error[0].err || error[0].errmsg) { + callback(utils.toError(error[0])); + } else { + callback(null, error[0].n); + } + }); + } else if(_hasWriteConcern(errorOptions) && callback == null) { + throw new Error("Cannot use a writeConcern without a provided callback"); + } else { + var result = this.db._executeRemoveCommand(deleteCommand); + // If no callback just return + if (!callback) return; + // If error return error + if (result instanceof Error) { + return callback(result); + } + // Otherwise just return + return callback(); + } +}; + +/** + * Renames the collection. + * + * Options + * - **dropTarget** {Boolean, default:false}, drop the target name collection if it previously exists. + * + * @param {String} newName the new name of the collection. + * @param {Object} [options] returns option results. + * @param {Function} callback the callback accepting the result + * @return {null} + * @api public + */ +Collection.prototype.rename = function rename(newName, options, callback) { + var self = this; + if(typeof options == 'function') { + callback = options; + options = {} + } + + // Ensure the new name is valid + checkCollectionName(newName); + + // Execute the command, return the new renamed collection if successful + self.db._executeQueryCommand(DbCommand.createRenameCollectionCommand(self.db, self.collectionName, newName, options) + , utils.handleSingleCommandResultReturn(true, false, function(err, result) { + if(err) return callback(err, null) + try { + if(options.new_collection) + return callback(null, new Collection(self.db, newName, self.db.pkFactory)); + self.collectionName = newName; + callback(null, self); + } catch(err) { + callback(err, null); + } + })); +} + +/** + * @ignore + */ +var insertAll = function insertAll (self, docs, options, callback) { + if('function' === typeof options) callback = options, options = {}; + if(options == null) options = {}; + if(!('function' === typeof callback)) callback = null; + + // Insert options (flags for insert) + var insertFlags = {}; + // If we have a mongodb version >= 1.9.1 support keepGoing attribute + if(options['keepGoing'] != null) { + insertFlags['keepGoing'] = options['keepGoing']; + } + + // If we have a mongodb version >= 1.9.1 support keepGoing attribute + if(options['continueOnError'] != null) { + insertFlags['continueOnError'] = options['continueOnError']; + } + + // DbName + var dbName = options['dbName']; + // If no dbname defined use the db one + if(dbName == null) { + dbName = self.db.databaseName; + } + + // Either use override on the function, or go back to default on either the collection + // level or db + if(options['serializeFunctions'] != null) { + insertFlags['serializeFunctions'] = options['serializeFunctions']; + } else { + insertFlags['serializeFunctions'] = self.serializeFunctions; + } + + // Get checkKeys value + var checkKeys = typeof options.checkKeys != 'boolean' ? true : options.checkKeys; + + // Pass in options + var insertCommand = new InsertCommand( + self.db + , dbName + "." + self.collectionName, checkKeys, insertFlags); + + // Add the documents and decorate them with id's if they have none + for(var index = 0, len = docs.length; index < len; ++index) { + var doc = docs[index]; + + // Add id to each document if it's not already defined + if (!(Buffer.isBuffer(doc)) + && doc['_id'] == null + && self.db.forceServerObjectId != true + && options.forceServerObjectId != true) { + doc['_id'] = self.pkFactory.createPk(); + } + + insertCommand.add(doc); + } + + // Collect errorOptions + var errorOptions = _getWriteConcern(self, options, callback); + // Default command options + var commandOptions = {}; + // If safe is defined check for error message + if(_hasWriteConcern(errorOptions) && typeof callback == 'function') { + // Insert options + commandOptions['read'] = false; + // If we have safe set set async to false + if(errorOptions == null) commandOptions['async'] = true; + + // Set safe option + commandOptions['safe'] = errorOptions; + // If we have an error option + if(typeof errorOptions == 'object') { + var keys = Object.keys(errorOptions); + for(var i = 0; i < keys.length; i++) { + commandOptions[keys[i]] = errorOptions[keys[i]]; + } + } + + // Execute command with safe options (rolls up both command and safe command into one and executes them on the same connection) + self.db._executeInsertCommand(insertCommand, commandOptions, function (err, error) { + error = error && error.documents; + if(!callback) return; + + if (err) { + callback(err); + } else if(error[0].err || error[0].errmsg) { + callback(utils.toError(error[0])); + } else { + callback(null, docs); + } + }); + } else if(_hasWriteConcern(errorOptions) && callback == null) { + throw new Error("Cannot use a writeConcern without a provided callback"); + } else { + // Execute the call without a write concern + var result = self.db._executeInsertCommand(insertCommand, commandOptions); + // If no callback just return + if(!callback) return; + // If error return error + if(result instanceof Error) { + return callback(result); + } + + // Otherwise just return + return callback(null, docs); + } +}; + +/** + * Save a document. Simple full document replacement function. Not recommended for efficiency, use atomic + * operators and update instead for more efficient operations. + * + * Options +* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @param {Object} [doc] the document to save + * @param {Object} [options] additional options during remove. + * @param {Function} [callback] must be provided if you performing a safe save + * @return {null} + * @api public + */ +Collection.prototype.save = function save(doc, options, callback) { + if('function' === typeof options) callback = options, options = null; + if(options == null) options = {}; + if(!('function' === typeof callback)) callback = null; + // Throw an error if attempting to perform a bulk operation + if(Array.isArray(doc)) throw new Error("doc parameter must be a single document"); + // Extract the id, if we have one we need to do a update command + var id = doc['_id']; + var commandOptions = _getWriteConcern(this, options, callback); + + if(id) { + commandOptions.upsert = true; + this.update({ _id: id }, doc, commandOptions, callback); + } else { + this.insert(doc, commandOptions, callback && function (err, docs) { + if(err) return callback(err, null); + + if(Array.isArray(docs)) { + callback(err, docs[0]); + } else { + callback(err, docs); + } + }); + } +}; + +/** + * Updates documents. + * + * Options +* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * - **upsert** {Boolean, default:false}, perform an upsert operation. + * - **multi** {Boolean, default:false}, update all documents matching the selector. + * - **serializeFunctions** {Boolean, default:false}, serialize functions on the document. + * - **checkKeys** {Boolean, default:true}, allows for disabling of document key checking (WARNING OPENS YOU UP TO INJECTION ATTACKS) + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @param {Object} selector the query to select the document/documents to be updated + * @param {Object} document the fields/vals to be updated, or in the case of an upsert operation, inserted. + * @param {Object} [options] additional options during update. + * @param {Function} [callback] must be provided if you performing an update with a writeconcern + * @return {null} + * @api public + */ +Collection.prototype.update = function update(selector, document, options, callback) { + if('function' === typeof options) callback = options, options = null; + if(options == null) options = {}; + if(!('function' === typeof callback)) callback = null; + + // DbName + var dbName = options['dbName']; + // If no dbname defined use the db one + if(dbName == null) { + dbName = this.db.databaseName; + } + + // If we are not providing a selector or document throw + if(selector == null || typeof selector != 'object') return callback(new Error("selector must be a valid JavaScript object")); + if(document == null || typeof document != 'object') return callback(new Error("document must be a valid JavaScript object")); + + // Either use override on the function, or go back to default on either the collection + // level or db + if(options['serializeFunctions'] != null) { + options['serializeFunctions'] = options['serializeFunctions']; + } else { + options['serializeFunctions'] = this.serializeFunctions; + } + + // Build the options command + var updateCommand = new UpdateCommand( + this.db + , dbName + "." + this.collectionName + , selector + , document + , options); + + var self = this; + // Unpack the error options if any + var errorOptions = _getWriteConcern(this, options, callback); + // If safe is defined check for error message + if(_hasWriteConcern(errorOptions) && typeof callback == 'function') { + // Insert options + var commandOptions = {read:false}; + // If we have safe set set async to false + if(errorOptions == null) commandOptions['async'] = true; + // Set safe option + commandOptions['safe'] = errorOptions; + // If we have an error option + if(typeof errorOptions == 'object') { + var keys = Object.keys(errorOptions); + for(var i = 0; i < keys.length; i++) { + commandOptions[keys[i]] = errorOptions[keys[i]]; + } + } + + // Execute command with safe options (rolls up both command and safe command into one and executes them on the same connection) + this.db._executeUpdateCommand(updateCommand, commandOptions, function (err, error) { + error = error && error.documents; + if(!callback) return; + + if(err) { + callback(err); + } else if(error[0].err || error[0].errmsg) { + callback(utils.toError(error[0])); + } else { + // Perform the callback + callback(null, error[0].n, error[0]); + } + }); + } else if(_hasWriteConcern(errorOptions) && callback == null) { + throw new Error("Cannot use a writeConcern without a provided callback"); + } else { + // Execute update + var result = this.db._executeUpdateCommand(updateCommand); + // If no callback just return + if (!callback) return; + // If error return error + if (result instanceof Error) { + return callback(result); + } + // Otherwise just return + return callback(); + } +}; + +/** + * The distinct command returns returns a list of distinct values for the given key across a collection. + * + * Options + * - **readPreference** {String}, the preferred read preference (Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST). + * + * @param {String} key key to run distinct against. + * @param {Object} [query] option query to narrow the returned objects. + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from distinct or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.distinct = function distinct(key, query, options, callback) { + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + query = args.length ? args.shift() || {} : {}; + options = args.length ? args.shift() || {} : {}; + + var mapCommandHash = { + 'distinct': this.collectionName + , 'query': query + , 'key': key + }; + + // Set read preference if we set one + var readPreference = options['readPreference'] ? options['readPreference'] : false; + // Execute the command + this.db._executeQueryCommand(DbCommand.createDbSlaveOkCommand(this.db, mapCommandHash) + , {read:readPreference} + , utils.handleSingleCommandResultReturn(null, null, function(err, result) { + if(err) return callback(err, null); + callback(null, result.values); + })); +}; + +/** + * Count number of matching documents in the db to a query. + * + * Options + * - **skip** {Number}, The number of documents to skip for the count. + * - **limit** {Number}, The limit of documents to count. + * - **readPreference** {String}, the preferred read preference (Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST). + * + * @param {Object} [query] query to filter by before performing count. + * @param {Object} [options] additional options during count. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the count method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.count = function count (query, options, callback) { + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + query = args.length ? args.shift() || {} : {}; + options = args.length ? args.shift() || {} : {}; + var skip = options.skip; + var limit = options.limit; + + // Final query + var commandObject = { + 'count': this.collectionName + , 'query': query + , 'fields': null + }; + + // Add limit and skip if defined + if(typeof skip == 'number') commandObject.skip = skip; + if(typeof limit == 'number') commandObject.limit = limit; + + // Set read preference if we set one + var readPreference = _getReadConcern(this, options); + + // Execute the command + this.db._executeQueryCommand(DbCommand.createDbSlaveOkCommand(this.db, commandObject) + , {read: readPreference} + , utils.handleSingleCommandResultReturn(null, null, function(err, result) { + if(err) return callback(err, null); + if(result == null) return callback(new Error("no result returned for count"), null); + callback(null, result.n); + })); +}; + + +/** + * Drop the collection + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the drop method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.drop = function drop(callback) { + this.db.dropCollection(this.collectionName, callback); +}; + +/** + * Find and update a document. + * + * Options + * - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * - **remove** {Boolean, default:false}, set to true to remove the object before returning. + * - **upsert** {Boolean, default:false}, perform an upsert operation. + * - **new** {Boolean, default:false}, set to true if you want to return the modified object rather than the original. Ignored for remove. + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @param {Object} query query object to locate the object to modify + * @param {Array} sort - if multiple docs match, choose the first one in the specified sort order as the object to manipulate + * @param {Object} doc - the fields/vals to be updated + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the findAndModify method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.findAndModify = function findAndModify (query, sort, doc, options, callback) { + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + sort = args.length ? args.shift() || [] : []; + doc = args.length ? args.shift() : null; + options = args.length ? args.shift() || {} : {}; + var self = this; + + var queryObject = { + 'findandmodify': this.collectionName + , 'query': query + , 'sort': utils.formattedOrderClause(sort) + }; + + queryObject.new = options.new ? 1 : 0; + queryObject.remove = options.remove ? 1 : 0; + queryObject.upsert = options.upsert ? 1 : 0; + + if (options.fields) { + queryObject.fields = options.fields; + } + + if (doc && !options.remove) { + queryObject.update = doc; + } + + // Either use override on the function, or go back to default on either the collection + // level or db + if(options['serializeFunctions'] != null) { + options['serializeFunctions'] = options['serializeFunctions']; + } else { + options['serializeFunctions'] = this.serializeFunctions; + } + + // Only run command and rely on getLastError command + var command = DbCommand.createDbCommand(this.db, queryObject, options) + // Execute command + this.db._executeQueryCommand(command + , {read:false}, utils.handleSingleCommandResultReturn(null, null, function(err, result) { + if(err) return callback(err, null); + return callback(null, result.value, result); + })); +} + +/** + * Find and remove a document + * + * Options +* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @param {Object} query query object to locate the object to modify + * @param {Array} sort - if multiple docs match, choose the first one in the specified sort order as the object to manipulate + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the findAndRemove method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.findAndRemove = function(query, sort, options, callback) { + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + sort = args.length ? args.shift() || [] : []; + options = args.length ? args.shift() || {} : {}; + // Add the remove option + options['remove'] = true; + // Execute the callback + this.findAndModify(query, sort, null, options, callback); +} + +var testForFields = { + limit: 1, sort: 1, fields:1, skip: 1, hint: 1, explain: 1, snapshot: 1, timeout: 1, tailable: 1, tailableRetryInterval: 1 + , numberOfRetries: 1, awaitdata: 1, exhaust: 1, batchSize: 1, returnKey: 1, maxScan: 1, min: 1, max: 1, showDiskLoc: 1 + , comment: 1, raw: 1, readPreference: 1, partial: 1, read: 1, dbName: 1 +}; + +/** + * Creates a cursor for a query that can be used to iterate over results from MongoDB + * + * Various argument possibilities + * - callback? + * - selector, callback?, + * - selector, fields, callback? + * - selector, options, callback? + * - selector, fields, options, callback? + * - selector, fields, skip, limit, callback? + * - selector, fields, skip, limit, timeout, callback? + * + * Options + * - **limit** {Number, default:0}, sets the limit of documents returned in the query. + * - **sort** {Array | Object}, set to sort the documents coming back from the query. Array of indexes, [['a', 1]] etc. + * - **fields** {Object}, the fields to return in the query. Object of fields to include or exclude (not both), {'a':1} + * - **skip** {Number, default:0}, set to skip N documents ahead in your query (useful for pagination). + * - **hint** {Object}, tell the query to use specific indexes in the query. Object of indexes to use, {'_id':1} + * - **explain** {Boolean, default:false}, explain the query instead of returning the data. + * - **snapshot** {Boolean, default:false}, snapshot query. + * - **timeout** {Boolean, default:false}, specify if the cursor can timeout. + * - **tailable** {Boolean, default:false}, specify if the cursor is tailable. + * - **tailableRetryInterval** {Number, default:100}, specify the miliseconds between getMores on tailable cursor. + * - **numberOfRetries** {Number, default:5}, specify the number of times to retry the tailable cursor. + * - **awaitdata** {Boolean, default:false} allow the cursor to wait for data, only applicable for tailable cursor. + * - **exhaust** {Boolean, default:false} have the server send all the documents at once as getMore packets, not recommended. + * - **batchSize** {Number, default:0}, set the batchSize for the getMoreCommand when iterating over the query results. + * - **returnKey** {Boolean, default:false}, only return the index key. + * - **maxScan** {Number}, Limit the number of items to scan. + * - **min** {Number}, Set index bounds. + * - **max** {Number}, Set index bounds. + * - **showDiskLoc** {Boolean, default:false}, Show disk location of results. + * - **comment** {String}, You can put a $comment field on a query to make looking in the profiler logs simpler. + * - **raw** {Boolean, default:false}, Return all BSON documents as Raw Buffer documents. + * - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST). + * - **numberOfRetries** {Number, default:5}, if using awaidata specifies the number of times to retry on timeout. + * - **partial** {Boolean, default:false}, specify if the cursor should return partial results when querying against a sharded system + * + * @param {Object|ObjectID} query query object to locate the object to modify + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the find method or null if an error occured. + * @return {Cursor} returns a cursor to the query + * @api public + */ +Collection.prototype.find = function find () { + var options + , args = Array.prototype.slice.call(arguments, 0) + , has_callback = typeof args[args.length - 1] === 'function' + , has_weird_callback = typeof args[0] === 'function' + , callback = has_callback ? args.pop() : (has_weird_callback ? args.shift() : null) + , len = args.length + , selector = len >= 1 ? args[0] : {} + , fields = len >= 2 ? args[1] : undefined; + + if(len === 1 && has_weird_callback) { + // backwards compat for callback?, options case + selector = {}; + options = args[0]; + } + + if(len === 2 && !Array.isArray(fields)) { + var fieldKeys = Object.getOwnPropertyNames(fields); + var is_option = false; + + for(var i = 0; i < fieldKeys.length; i++) { + if(testForFields[fieldKeys[i]] != null) { + is_option = true; + break; + } + } + + if(is_option) { + options = fields; + fields = undefined; + } else { + options = {}; + } + } else if(len === 2 && Array.isArray(fields) && !Array.isArray(fields[0])) { + var newFields = {}; + // Rewrite the array + for(var i = 0; i < fields.length; i++) { + newFields[fields[i]] = 1; + } + // Set the fields + fields = newFields; + } + + if(3 === len) { + options = args[2]; + } + + // Ensure selector is not null + selector = selector == null ? {} : selector; + // Validate correctness off the selector + var object = selector; + if(Buffer.isBuffer(object)) { + var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24; + if(object_size != object.length) { + var error = new Error("query selector raw message size does not match message header size [" + object.length + "] != [" + object_size + "]"); + error.name = 'MongoError'; + throw error; + } + } + + // Validate correctness of the field selector + var object = fields; + if(Buffer.isBuffer(object)) { + var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24; + if(object_size != object.length) { + var error = new Error("query fields raw message size does not match message header size [" + object.length + "] != [" + object_size + "]"); + error.name = 'MongoError'; + throw error; + } + } + + // Check special case where we are using an objectId + if(selector instanceof ObjectID || (selector != null && selector._bsontype == 'ObjectID')) { + selector = {_id:selector}; + } + + // If it's a serialized fields field we need to just let it through + // user be warned it better be good + if(options && options.fields && !(Buffer.isBuffer(options.fields))) { + fields = {}; + + if(Array.isArray(options.fields)) { + if(!options.fields.length) { + fields['_id'] = 1; + } else { + for (var i = 0, l = options.fields.length; i < l; i++) { + fields[options.fields[i]] = 1; + } + } + } else { + fields = options.fields; + } + } + + if (!options) options = {}; + options.skip = len > 3 ? args[2] : options.skip ? options.skip : 0; + options.limit = len > 3 ? args[3] : options.limit ? options.limit : 0; + options.raw = options.raw != null && typeof options.raw === 'boolean' ? options.raw : this.raw; + options.hint = options.hint != null ? normalizeHintField(options.hint) : this.internalHint; + options.timeout = len == 5 ? args[4] : typeof options.timeout === 'undefined' ? undefined : options.timeout; + // If we have overridden slaveOk otherwise use the default db setting + options.slaveOk = options.slaveOk != null ? options.slaveOk : this.db.slaveOk; + + // Set option + var o = options; + // Support read/readPreference + if(o["read"] != null) o["readPreference"] = o["read"]; + // Set the read preference + o.read = o["readPreference"] ? o.readPreference : this.readPreference; + // Adjust slave ok if read preference is secondary or secondary only + if(o.read == "secondary" || o.read == "secondaryOnly") options.slaveOk = true; + + // callback for backward compatibility + if(callback) { + // TODO refactor Cursor args + callback(null, new Cursor(this.db, this, selector, fields, o)); + } else { + return new Cursor(this.db, this, selector, fields, o); + } +}; + +/** + * Normalizes a `hint` argument. + * + * @param {String|Object|Array} hint + * @return {Object} + * @api private + */ +var normalizeHintField = function normalizeHintField(hint) { + var finalHint = null; + + if(typeof hint == 'string') { + finalHint = hint; + } else if(Array.isArray(hint)) { + finalHint = {}; + + hint.forEach(function(param) { + finalHint[param] = 1; + }); + } else if(hint != null && typeof hint == 'object') { + finalHint = {}; + for (var name in hint) { + finalHint[name] = hint[name]; + } + } + + return finalHint; +}; + +/** + * Finds a single document based on the query + * + * Various argument possibilities + * - callback? + * - selector, callback?, + * - selector, fields, callback? + * - selector, options, callback? + * - selector, fields, options, callback? + * - selector, fields, skip, limit, callback? + * - selector, fields, skip, limit, timeout, callback? + * + * Options + * - **limit** {Number, default:0}, sets the limit of documents returned in the query. + * - **sort** {Array | Object}, set to sort the documents coming back from the query. Array of indexes, [['a', 1]] etc. + * - **fields** {Object}, the fields to return in the query. Object of fields to include or exclude (not both), {'a':1} + * - **skip** {Number, default:0}, set to skip N documents ahead in your query (useful for pagination). + * - **hint** {Object}, tell the query to use specific indexes in the query. Object of indexes to use, {'_id':1} + * - **explain** {Boolean, default:false}, explain the query instead of returning the data. + * - **snapshot** {Boolean, default:false}, snapshot query. + * - **timeout** {Boolean, default:false}, specify if the cursor can timeout. + * - **tailable** {Boolean, default:false}, specify if the cursor is tailable. + * - **batchSize** {Number, default:0}, set the batchSize for the getMoreCommand when iterating over the query results. + * - **returnKey** {Boolean, default:false}, only return the index key. + * - **maxScan** {Number}, Limit the number of items to scan. + * - **min** {Number}, Set index bounds. + * - **max** {Number}, Set index bounds. + * - **showDiskLoc** {Boolean, default:false}, Show disk location of results. + * - **comment** {String}, You can put a $comment field on a query to make looking in the profiler logs simpler. + * - **raw** {Boolean, default:false}, Return all BSON documents as Raw Buffer documents. + * - **readPreference** {String}, the preferred read preference (Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST). + * - **partial** {Boolean, default:false}, specify if the cursor should return partial results when querying against a sharded system + * + * @param {Object|ObjectID} query query object to locate the object to modify + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the findOne method or null if an error occured. + * @return {Cursor} returns a cursor to the query + * @api public + */ +Collection.prototype.findOne = function findOne () { + var self = this; + var args = Array.prototype.slice.call(arguments, 0); + var callback = args.pop(); + var cursor = this.find.apply(this, args).limit(-1).batchSize(1); + // Return the item + cursor.nextObject(function(err, item) { + if(err != null) return callback(utils.toError(err), null); + callback(null, item); + }); +}; + +/** + * Creates an index on the collection. + * + * Options +* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * - **unique** {Boolean, default:false}, creates an unique index. + * - **sparse** {Boolean, default:false}, creates a sparse index. + * - **background** {Boolean, default:false}, creates the index in the background, yielding whenever possible. + * - **dropDups** {Boolean, default:false}, a unique index cannot be created on a key that has pre-existing duplicate values. If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value + * - **min** {Number}, for geospatial indexes set the lower bound for the co-ordinates. + * - **max** {Number}, for geospatial indexes set the high bound for the co-ordinates. + * - **v** {Number}, specify the format version of the indexes. + * - **expireAfterSeconds** {Number}, allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher) + * - **name** {String}, override the autogenerated index name (useful if the resulting name is larger than 128 bytes) + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @param {Object} fieldOrSpec fieldOrSpec that defines the index. + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the createIndex method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.createIndex = function createIndex (fieldOrSpec, options, callback) { + // Clean up call + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + options = args.length ? args.shift() || {} : {}; + options = typeof callback === 'function' ? options : callback; + options = options == null ? {} : options; + + // Collect errorOptions + var errorOptions = _getWriteConcern(this, options, callback); + // Execute create index + this.db.createIndex(this.collectionName, fieldOrSpec, options, callback); +}; + +/** + * Ensures that an index exists, if it does not it creates it + * + * Options +* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * - **unique** {Boolean, default:false}, creates an unique index. + * - **sparse** {Boolean, default:false}, creates a sparse index. + * - **background** {Boolean, default:false}, creates the index in the background, yielding whenever possible. + * - **dropDups** {Boolean, default:false}, a unique index cannot be created on a key that has pre-existing duplicate values. If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value + * - **min** {Number}, for geospatial indexes set the lower bound for the co-ordinates. + * - **max** {Number}, for geospatial indexes set the high bound for the co-ordinates. + * - **v** {Number}, specify the format version of the indexes. + * - **expireAfterSeconds** {Number}, allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher) + * - **name** {String}, override the autogenerated index name (useful if the resulting name is larger than 128 bytes) + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @param {Object} fieldOrSpec fieldOrSpec that defines the index. + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the ensureIndex method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.ensureIndex = function ensureIndex (fieldOrSpec, options, callback) { + // Clean up call + if (typeof callback === 'undefined' && typeof options === 'function') { + callback = options; + options = {}; + } + + if (options == null) { + options = {}; + } + + // Execute create index + this.db.ensureIndex(this.collectionName, fieldOrSpec, options, callback); +}; + +/** + * Retrieves this collections index info. + * + * Options + * - **full** {Boolean, default:false}, returns the full raw index information. + * + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the indexInformation method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.indexInformation = function indexInformation (options, callback) { + // Unpack calls + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + options = args.length ? args.shift() || {} : {}; + // Call the index information + this.db.indexInformation(this.collectionName, options, callback); +}; + +/** + * Drops an index from this collection. + * + * @param {String} name + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the dropIndex method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.dropIndex = function dropIndex (name, callback) { + this.db.dropIndex(this.collectionName, name, callback); +}; + +/** + * Drops all indexes from this collection. + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the dropAllIndexes method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.dropAllIndexes = function dropIndexes (callback) { + this.db.dropIndex(this.collectionName, '*', function (err, result) { + if(err) return callback(err, false); + callback(null, true); + }); +} + +/** + * Drops all indexes from this collection. + * + * @deprecated + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the dropIndexes method or null if an error occured. + * @return {null} + * @api private + */ +Collection.prototype.dropIndexes = Collection.prototype.dropAllIndexes; + +/** + * Reindex all indexes on the collection + * Warning: reIndex is a blocking operation (indexes are rebuilt in the foreground) and will be slow for large collections. + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the reIndex method or null if an error occured. + * @return {null} + * @api public +**/ +Collection.prototype.reIndex = function(callback) { + this.db.reIndex(this.collectionName, callback); +} + +/** + * Run Map Reduce across a collection. Be aware that the inline option for out will return an array of results not a collection. + * + * Options + * - **out** {Object}, sets the output target for the map reduce job. *{inline:1} | {replace:'collectionName'} | {merge:'collectionName'} | {reduce:'collectionName'}* + * - **query** {Object}, query filter object. + * - **sort** {Object}, sorts the input objects using this key. Useful for optimization, like sorting by the emit key for fewer reduces. + * - **limit** {Number}, number of objects to return from collection. + * - **keeptemp** {Boolean, default:false}, keep temporary data. + * - **finalize** {Function | String}, finalize function. + * - **scope** {Object}, can pass in variables that can be access from map/reduce/finalize. + * - **jsMode** {Boolean, default:false}, it is possible to make the execution stay in JS. Provided in MongoDB > 2.0.X. + * - **verbose** {Boolean, default:false}, provide statistics on job execution time. + * - **readPreference** {String, only for inline results}, the preferred read preference (Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST). + * + * @param {Function|String} map the mapping function. + * @param {Function|String} reduce the reduce function. + * @param {Objects} [options] options for the map reduce job. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the mapReduce method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.mapReduce = function mapReduce (map, reduce, options, callback) { + if ('function' === typeof options) callback = options, options = {}; + // Out must allways be defined (make sure we don't break weirdly on pre 1.8+ servers) + if(null == options.out) { + throw new Error("the out option parameter must be defined, see mongodb docs for possible values"); + } + + if ('function' === typeof map) { + map = map.toString(); + } + + if ('function' === typeof reduce) { + reduce = reduce.toString(); + } + + if ('function' === typeof options.finalize) { + options.finalize = options.finalize.toString(); + } + + var mapCommandHash = { + mapreduce: this.collectionName + , map: map + , reduce: reduce + }; + + // Add any other options passed in + for (var name in options) { + if ('scope' == name) { + mapCommandHash[name] = processScope(options[name]); + } else { + mapCommandHash[name] = options[name]; + } + } + + // Set read preference if we set one + var readPreference = _getReadConcern(this, options); + + // If we have a read preference and inline is not set as output fail hard + if((readPreference != false && readPreference != 'primary') + && options['out'] && (options['out'].inline != 1 && options['out'] != 'inline')) { + throw new Error("a readPreference can only be provided when performing an inline mapReduce"); + } + + // self + var self = this; + var cmd = DbCommand.createDbCommand(this.db, mapCommandHash); + + this.db._executeQueryCommand(cmd, {read:readPreference}, function (err, result) { + if(err) return callback(err); + if(!result || !result.documents || result.documents.length == 0) + return callback(Error("command failed to return results"), null) + + // Check if we have an error + if(1 != result.documents[0].ok || result.documents[0].err || result.documents[0].errmsg) { + return callback(utils.toError(result.documents[0])); + } + + // Create statistics value + var stats = {}; + if(result.documents[0].timeMillis) stats['processtime'] = result.documents[0].timeMillis; + if(result.documents[0].counts) stats['counts'] = result.documents[0].counts; + if(result.documents[0].timing) stats['timing'] = result.documents[0].timing; + + // invoked with inline? + if(result.documents[0].results) { + return callback(null, result.documents[0].results, stats); + } + + // The returned collection + var collection = null; + + // If we have an object it's a different db + if(result.documents[0].result != null && typeof result.documents[0].result == 'object') { + var doc = result.documents[0].result; + collection = self.db.db(doc.db).collection(doc.collection); + } else { + // Create a collection object that wraps the result collection + collection = self.db.collection(result.documents[0].result) + } + + // If we wish for no verbosity + if(options['verbose'] == null || !options['verbose']) { + return callback(err, collection); + } + + // Return stats as third set of values + callback(err, collection, stats); + }); +}; + +/** + * Functions that are passed as scope args must + * be converted to Code instances. + * @ignore + */ +function processScope (scope) { + if (!utils.isObject(scope)) { + return scope; + } + + var keys = Object.keys(scope); + var i = keys.length; + var key; + + while (i--) { + key = keys[i]; + if ('function' == typeof scope[key]) { + scope[key] = new Code(String(scope[key])); + } + } + + return scope; +} + +/** + * Group function helper + * @ignore + */ +var groupFunction = function () { + var c = db[ns].find(condition); + var map = new Map(); + var reduce_function = reduce; + + while (c.hasNext()) { + var obj = c.next(); + var key = {}; + + for (var i = 0, len = keys.length; i < len; ++i) { + var k = keys[i]; + key[k] = obj[k]; + } + + var aggObj = map.get(key); + + if (aggObj == null) { + var newObj = Object.extend({}, key); + aggObj = Object.extend(newObj, initial); + map.put(key, aggObj); + } + + reduce_function(obj, aggObj); + } + + return { "result": map.values() }; +}.toString(); + +/** + * Run a group command across a collection + * + * Options + * - **readPreference** {String}, the preferred read preference (Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST). + * + * @param {Object|Array|Function|Code} keys an object, array or function expressing the keys to group by. + * @param {Object} condition an optional condition that must be true for a row to be considered. + * @param {Object} initial initial value of the aggregation counter object. + * @param {Function|Code} reduce the reduce function aggregates (reduces) the objects iterated + * @param {Function|Code} finalize an optional function to be run on each item in the result set just before the item is returned. + * @param {Boolean} command specify if you wish to run using the internal group command or using eval, default is true. + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the group method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.group = function group(keys, condition, initial, reduce, finalize, command, options, callback) { + var args = Array.prototype.slice.call(arguments, 3); + callback = args.pop(); + // Fetch all commands + reduce = args.length ? args.shift() : null; + finalize = args.length ? args.shift() : null; + command = args.length ? args.shift() : null; + options = args.length ? args.shift() || {} : {}; + + // Make sure we are backward compatible + if(!(typeof finalize == 'function')) { + command = finalize; + finalize = null; + } + + if (!Array.isArray(keys) && keys instanceof Object && typeof(keys) !== 'function' && !(keys instanceof Code)) { + keys = Object.keys(keys); + } + + if(typeof reduce === 'function') { + reduce = reduce.toString(); + } + + if(typeof finalize === 'function') { + finalize = finalize.toString(); + } + + // Set up the command as default + command = command == null ? true : command; + + // Execute using the command + if(command) { + var reduceFunction = reduce instanceof Code + ? reduce + : new Code(reduce); + + var selector = { + group: { + 'ns': this.collectionName + , '$reduce': reduceFunction + , 'cond': condition + , 'initial': initial + , 'out': "inline" + } + }; + + // if finalize is defined + if(finalize != null) selector.group['finalize'] = finalize; + // Set up group selector + if ('function' === typeof keys || keys instanceof Code) { + selector.group.$keyf = keys instanceof Code + ? keys + : new Code(keys); + } else { + var hash = {}; + keys.forEach(function (key) { + hash[key] = 1; + }); + selector.group.key = hash; + } + + var cmd = DbCommand.createDbSlaveOkCommand(this.db, selector); + // Set read preference if we set one + var readPreference = _getReadConcern(this, options); + // Execute the command + this.db._executeQueryCommand(cmd + , {read:readPreference} + , utils.handleSingleCommandResultReturn(null, null, function(err, result) { + if(err) return callback(err, null); + callback(null, result.retval); + })); + } else { + // Create execution scope + var scope = reduce != null && reduce instanceof Code + ? reduce.scope + : {}; + + scope.ns = this.collectionName; + scope.keys = keys; + scope.condition = condition; + scope.initial = initial; + + // Pass in the function text to execute within mongodb. + var groupfn = groupFunction.replace(/ reduce;/, reduce.toString() + ';'); + + this.db.eval(new Code(groupfn, scope), function (err, results) { + if (err) return callback(err, null); + callback(null, results.result || results); + }); + } +}; + +/** + * Returns the options of the collection. + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the options method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.options = function options(callback) { + this.db.collectionsInfo(this.collectionName, function (err, cursor) { + if (err) return callback(err); + cursor.nextObject(function (err, document) { + callback(err, document && document.options || null); + }); + }); +}; + +/** + * Returns if the collection is a capped collection + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the isCapped method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.isCapped = function isCapped(callback) { + this.options(function(err, document) { + if(err != null) { + callback(err); + } else { + callback(null, document && document.capped); + } + }); +}; + +/** + * Checks if one or more indexes exist on the collection + * + * @param {String|Array} indexNames check if one or more indexes exist on the collection. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the indexExists method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.indexExists = function indexExists(indexes, callback) { + this.indexInformation(function(err, indexInformation) { + // If we have an error return + if(err != null) return callback(err, null); + // Let's check for the index names + if(Array.isArray(indexes)) { + for(var i = 0; i < indexes.length; i++) { + if(indexInformation[indexes[i]] == null) { + return callback(null, false); + } + } + + // All keys found return true + return callback(null, true); + } else { + return callback(null, indexInformation[indexes] != null); + } + }); +} + +/** + * Execute the geoNear command to search for items in the collection + * + * Options + * - **num** {Number}, max number of results to return. + * - **maxDistance** {Number}, include results up to maxDistance from the point. + * - **distanceMultiplier** {Number}, include a value to multiply the distances with allowing for range conversions. + * - **query** {Object}, filter the results by a query. + * - **spherical** {Boolean, default:false}, perform query using a spherical model. + * - **uniqueDocs** {Boolean, default:false}, the closest location in a document to the center of the search region will always be returned MongoDB > 2.X. + * - **includeLocs** {Boolean, default:false}, include the location data fields in the top level of the results MongoDB > 2.X. + * - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST). + * + * @param {Number} x point to search on the x axis, ensure the indexes are ordered in the same order. + * @param {Number} y point to search on the y axis, ensure the indexes are ordered in the same order. + * @param {Objects} [options] options for the map reduce job. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the geoNear method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.geoNear = function geoNear(x, y, options, callback) { + var args = Array.prototype.slice.call(arguments, 2); + callback = args.pop(); + // Fetch all commands + options = args.length ? args.shift() || {} : {}; + + // Build command object + var commandObject = { + geoNear:this.collectionName, + near: [x, y] + } + + // Decorate object if any with known properties + if(options['num'] != null) commandObject['num'] = options['num']; + if(options['maxDistance'] != null) commandObject['maxDistance'] = options['maxDistance']; + if(options['distanceMultiplier'] != null) commandObject['distanceMultiplier'] = options['distanceMultiplier']; + if(options['query'] != null) commandObject['query'] = options['query']; + if(options['spherical'] != null) commandObject['spherical'] = options['spherical']; + if(options['uniqueDocs'] != null) commandObject['uniqueDocs'] = options['uniqueDocs']; + if(options['includeLocs'] != null) commandObject['includeLocs'] = options['includeLocs']; + + // Ensure we have the right read preference inheritance + options.readPreference = _getReadConcern(this, options); + + // Execute the command + this.db.command(commandObject, options, function (err, res) { + if (err) { + callback(err); + } else if (res.err || res.errmsg) { + callback(utils.toError(res)); + } else { + // should we only be returning res.results here? Not sure if the user + // should see the other return information + callback(null, res); + } + }); +} + +/** + * Execute a geo search using a geo haystack index on a collection. + * + * Options + * - **maxDistance** {Number}, include results up to maxDistance from the point. + * - **search** {Object}, filter the results by a query. + * - **limit** {Number}, max number of results to return. + * - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST). + * + * @param {Number} x point to search on the x axis, ensure the indexes are ordered in the same order. + * @param {Number} y point to search on the y axis, ensure the indexes are ordered in the same order. + * @param {Objects} [options] options for the map reduce job. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the geoHaystackSearch method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.geoHaystackSearch = function geoHaystackSearch(x, y, options, callback) { + var args = Array.prototype.slice.call(arguments, 2); + callback = args.pop(); + // Fetch all commands + options = args.length ? args.shift() || {} : {}; + + // Build command object + var commandObject = { + geoSearch:this.collectionName, + near: [x, y] + } + + // Decorate object if any with known properties + if(options['maxDistance'] != null) commandObject['maxDistance'] = options['maxDistance']; + if(options['query'] != null) commandObject['search'] = options['query']; + if(options['search'] != null) commandObject['search'] = options['search']; + if(options['limit'] != null) commandObject['limit'] = options['limit']; + + // Ensure we have the right read preference inheritance + options.readPreference = _getReadConcern(this, options); + + // Execute the command + this.db.command(commandObject, options, function (err, res) { + if (err) { + callback(err); + } else if (res.err || res.errmsg) { + callback(utils.toError(res)); + } else { + // should we only be returning res.results here? Not sure if the user + // should see the other return information + callback(null, res); + } + }); +} + +/** + * Retrieve all the indexes on the collection. + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the indexes method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.indexes = function indexes(callback) { + // Return all the index information + this.db.indexInformation(this.collectionName, {full:true}, callback); +} + +/** + * Execute an aggregation framework pipeline against the collection, needs MongoDB >= 2.1 + * + * Options + * - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST). + * + * @param {Array} array containing all the aggregation framework commands for the execution. + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the aggregate method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.aggregate = function(pipeline, options, callback) { + // * - **explain** {Boolean}, return the query plan for the aggregation pipeline instead of the results. 2.3, 2.4 + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + var self = this; + + // If we have any of the supported options in the options object + var opts = args[args.length - 1]; + options = opts.readPreference || opts.explain ? args.pop() : {} + + // Convert operations to an array + if(!Array.isArray(args[0])) { + pipeline = []; + // Push all the operations to the pipeline + for(var i = 0; i < args.length; i++) pipeline.push(args[i]); + } + + // Build the command + var command = { aggregate : this.collectionName, pipeline : pipeline}; + + // Ensure we have the right read preference inheritance + options.readPreference = _getReadConcern(this, options); + + // Execute the command + this.db.command(command, options, function(err, result) { + if(err) { + callback(err); + } else if(result['err'] || result['errmsg']) { + callback(utils.toError(result)); + } else if(typeof result == 'object' && result['serverPipeline']) { + callback(null, result); + } else { + callback(null, result.result); + } + }); +} + +/** + * Get all the collection statistics. + * + * Options + * - **scale** {Number}, divide the returned sizes by scale value. + * - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST). + * + * @param {Objects} [options] options for the stats command. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the stats method or null if an error occured. + * @return {null} + * @api public + */ +Collection.prototype.stats = function stats(options, callback) { + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + // Fetch all commands + options = args.length ? args.shift() || {} : {}; + + // Build command object + var commandObject = { + collStats:this.collectionName, + } + + // Check if we have the scale value + if(options['scale'] != null) commandObject['scale'] = options['scale']; + + // Ensure we have the right read preference inheritance + options.readPreference = _getReadConcern(this, options); + + // Execute the command + this.db.command(commandObject, options, callback); +} + +/** + * @ignore + */ +Object.defineProperty(Collection.prototype, "hint", { + enumerable: true + , get: function () { + return this.internalHint; + } + , set: function (v) { + this.internalHint = normalizeHintField(v); + } +}); + +var _getReadConcern = function(self, options) { + if(options.readPreference) return options.readPreference; + if(self.readPreference) return self.readPreference; + if(self.db.readPreference) return self.readPreference; + return 'primary'; +} + +/** + * @ignore + */ +var _hasWriteConcern = function(errorOptions) { + return errorOptions == true + || errorOptions.w > 0 + || errorOptions.w == 'majority' + || errorOptions.j == true + || errorOptions.journal == true + || errorOptions.fsync == true +} + +/** + * @ignore + */ +var _setWriteConcernHash = function(options) { + var finalOptions = {}; + if(options.w != null) finalOptions.w = options.w; + if(options.journal == true) finalOptions.j = options.journal; + if(options.j == true) finalOptions.j = options.j; + if(options.fsync == true) finalOptions.fsync = options.fsync; + if(options.wtimeout != null) finalOptions.wtimeout = options.wtimeout; + return finalOptions; +} + +/** + * @ignore + */ +var _getWriteConcern = function(self, options, callback) { + // Final options + var finalOptions = {w:1}; + // Local options verification + if(options.w != null || typeof options.j == 'boolean' || typeof options.journal == 'boolean' || typeof options.fsync == 'boolean') { + finalOptions = _setWriteConcernHash(options); + } else if(typeof options.safe == "boolean") { + finalOptions = {w: (options.safe ? 1 : 0)}; + } else if(options.safe != null && typeof options.safe == 'object') { + finalOptions = _setWriteConcernHash(options.safe); + } else if(self.opts.w != null || typeof self.opts.j == 'boolean' || typeof self.opts.journal == 'boolean' || typeof self.opts.fsync == 'boolean') { + finalOptions = _setWriteConcernHash(self.opts); + } else if(typeof self.opts.safe == "boolean") { + finalOptions = {w: (self.opts.safe ? 1 : 0)}; + } else if(self.db.safe.w != null || typeof self.db.safe.j == 'boolean' || typeof self.db.safe.journal == 'boolean' || typeof self.db.safe.fsync == 'boolean') { + finalOptions = _setWriteConcernHash(self.db.safe); + } else if(self.db.options.w != null || typeof self.db.options.j == 'boolean' || typeof self.db.options.journal == 'boolean' || typeof self.db.options.fsync == 'boolean') { + finalOptions = _setWriteConcernHash(self.db.options); + } else if(typeof self.db.safe == "boolean") { + finalOptions = {w: (self.db.safe ? 1 : 0)}; + } + + // Ensure we don't have an invalid combination of write concerns + if(finalOptions.w < 1 + && (finalOptions.journal == true || finalOptions.j == true || finalOptions.fsync == true)) throw new Error("No acknowlegement using w < 1 cannot be combined with journal:true or fsync:true"); + + // Return the options + return finalOptions; +} + +/** + * Expose. + */ +exports.Collection = Collection; diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/base_command.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/base_command.js new file mode 100644 index 0000000..9558582 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/base_command.js @@ -0,0 +1,29 @@ +/** + Base object used for common functionality +**/ +var BaseCommand = exports.BaseCommand = function BaseCommand() { +}; + +var id = 1; +BaseCommand.prototype.getRequestId = function getRequestId() { + if (!this.requestId) this.requestId = id++; + return this.requestId; +}; + +BaseCommand.prototype.setMongosReadPreference = function setMongosReadPreference(readPreference, tags) {} + +BaseCommand.prototype.updateRequestId = function() { + this.requestId = id++; + return this.requestId; +}; + +// OpCodes +BaseCommand.OP_REPLY = 1; +BaseCommand.OP_MSG = 1000; +BaseCommand.OP_UPDATE = 2001; +BaseCommand.OP_INSERT = 2002; +BaseCommand.OP_GET_BY_OID = 2003; +BaseCommand.OP_QUERY = 2004; +BaseCommand.OP_GET_MORE = 2005; +BaseCommand.OP_DELETE = 2006; +BaseCommand.OP_KILL_CURSORS = 2007; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/db_command.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/db_command.js new file mode 100644 index 0000000..b7019c8 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/db_command.js @@ -0,0 +1,245 @@ +var QueryCommand = require('./query_command').QueryCommand, + InsertCommand = require('./insert_command').InsertCommand, + inherits = require('util').inherits, + utils = require('../utils'), + crypto = require('crypto'); + +/** + Db Command +**/ +var DbCommand = exports.DbCommand = function(dbInstance, collectionName, queryOptions, numberToSkip, numberToReturn, query, returnFieldSelector, options) { + QueryCommand.call(this); + this.collectionName = collectionName; + this.queryOptions = queryOptions; + this.numberToSkip = numberToSkip; + this.numberToReturn = numberToReturn; + this.query = query; + this.returnFieldSelector = returnFieldSelector; + this.db = dbInstance; + + if(this.db && this.db.slaveOk) { + this.queryOptions |= QueryCommand.OPTS_SLAVE; + } + + // Make sure we don't get a null exception + options = options == null ? {} : options; + // Let us defined on a command basis if we want functions to be serialized or not + if(options['serializeFunctions'] != null && options['serializeFunctions']) { + this.serializeFunctions = true; + } +}; + +inherits(DbCommand, QueryCommand); + +// Constants +DbCommand.SYSTEM_NAMESPACE_COLLECTION = "system.namespaces"; +DbCommand.SYSTEM_INDEX_COLLECTION = "system.indexes"; +DbCommand.SYSTEM_PROFILE_COLLECTION = "system.profile"; +DbCommand.SYSTEM_USER_COLLECTION = "system.users"; +DbCommand.SYSTEM_COMMAND_COLLECTION = "$cmd"; +DbCommand.SYSTEM_JS_COLLECTION = "system.js"; + +// New commands +DbCommand.NcreateIsMasterCommand = function(db, databaseName) { + return new DbCommand(db, databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'ismaster':1}, null); +}; + +// Provide constructors for different db commands +DbCommand.createIsMasterCommand = function(db) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'ismaster':1}, null); +}; + +DbCommand.createCollectionInfoCommand = function(db, selector) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_NAMESPACE_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, 0, selector, null); +}; + +DbCommand.createGetNonceCommand = function(db, options) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'getnonce':1}, null); +}; + +DbCommand.createAuthenticationCommand = function(db, username, password, nonce, authdb) { + // Use node md5 generator + var md5 = crypto.createHash('md5'); + // Generate keys used for authentication + md5.update(username + ":mongo:" + password); + var hash_password = md5.digest('hex'); + // Final key + md5 = crypto.createHash('md5'); + md5.update(nonce + username + hash_password); + var key = md5.digest('hex'); + // Creat selector + var selector = {'authenticate':1, 'user':username, 'nonce':nonce, 'key':key}; + // Create db command + return new DbCommand(db, authdb + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NONE, 0, -1, selector, null); +}; + +DbCommand.createLogoutCommand = function(db) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'logout':1}, null); +}; + +DbCommand.createCreateCollectionCommand = function(db, collectionName, options) { + var selector = {'create':collectionName}; + // Modify the options to ensure correct behaviour + for(var name in options) { + if(options[name] != null && options[name].constructor != Function) selector[name] = options[name]; + } + // Execute the command + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, selector, null); +}; + +DbCommand.createDropCollectionCommand = function(db, collectionName) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'drop':collectionName}, null); +}; + +DbCommand.createRenameCollectionCommand = function(db, fromCollectionName, toCollectionName, options) { + var renameCollection = db.databaseName + "." + fromCollectionName; + var toCollection = db.databaseName + "." + toCollectionName; + var dropTarget = options && options.dropTarget ? options.dropTarget : false; + return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'renameCollection':renameCollection, 'to':toCollection, 'dropTarget':dropTarget}, null); +}; + +DbCommand.createGetLastErrorCommand = function(options, db) { + + if (typeof db === 'undefined') { + db = options; + options = {}; + } + // Final command + var command = {'getlasterror':1}; + // If we have an options Object let's merge in the fields (fsync/wtimeout/w) + if('object' === typeof options) { + for(var name in options) { + command[name] = options[name] + } + } + + // Special case for w == 1, remove the w + if(1 == command.w) { + delete command.w; + } + + // Execute command + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command, null); +}; + +DbCommand.createGetLastStatusCommand = DbCommand.createGetLastErrorCommand; + +DbCommand.createGetPreviousErrorsCommand = function(db) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'getpreverror':1}, null); +}; + +DbCommand.createResetErrorHistoryCommand = function(db) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'reseterror':1}, null); +}; + +DbCommand.createCreateIndexCommand = function(db, collectionName, fieldOrSpec, options) { + var fieldHash = {}; + var indexes = []; + var keys; + + // Get all the fields accordingly + if('string' == typeof fieldOrSpec) { + // 'type' + indexes.push(fieldOrSpec + '_' + 1); + fieldHash[fieldOrSpec] = 1; + + } else if(utils.isArray(fieldOrSpec)) { + + fieldOrSpec.forEach(function(f) { + if('string' == typeof f) { + // [{location:'2d'}, 'type'] + indexes.push(f + '_' + 1); + fieldHash[f] = 1; + } else if(utils.isArray(f)) { + // [['location', '2d'],['type', 1]] + indexes.push(f[0] + '_' + (f[1] || 1)); + fieldHash[f[0]] = f[1] || 1; + } else if(utils.isObject(f)) { + // [{location:'2d'}, {type:1}] + keys = Object.keys(f); + keys.forEach(function(k) { + indexes.push(k + '_' + f[k]); + fieldHash[k] = f[k]; + }); + } else { + // undefined (ignore) + } + }); + + } else if(utils.isObject(fieldOrSpec)) { + // {location:'2d', type:1} + keys = Object.keys(fieldOrSpec); + keys.forEach(function(key) { + indexes.push(key + '_' + fieldOrSpec[key]); + fieldHash[key] = fieldOrSpec[key]; + }); + } + + // Generate the index name + var indexName = typeof options.name == 'string' + ? options.name + : indexes.join("_"); + + var selector = { + 'ns': db.databaseName + "." + collectionName, + 'key': fieldHash, + 'name': indexName + } + + // Ensure we have a correct finalUnique + var finalUnique = options == null || 'object' === typeof options + ? false + : options; + + // Set up options + options = options == null || typeof options == 'boolean' + ? {} + : options; + + // Add all the options + var keys = Object.keys(options); + for(var i = 0; i < keys.length; i++) { + selector[keys[i]] = options[keys[i]]; + } + + if(selector['unique'] == null) + selector['unique'] = finalUnique; + + var name = db.databaseName + "." + DbCommand.SYSTEM_INDEX_COLLECTION; + var cmd = new InsertCommand(db, name, false); + return cmd.add(selector); +}; + +DbCommand.logoutCommand = function(db, command_hash, options) { + var dbName = options != null && options['authdb'] != null ? options['authdb'] : db.databaseName; + return new DbCommand(db, dbName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null); +} + +DbCommand.createDropIndexCommand = function(db, collectionName, indexName) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'deleteIndexes':collectionName, 'index':indexName}, null); +}; + +DbCommand.createReIndexCommand = function(db, collectionName) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'reIndex':collectionName}, null); +}; + +DbCommand.createDropDatabaseCommand = function(db) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'dropDatabase':1}, null); +}; + +DbCommand.createDbCommand = function(db, command_hash, options, auth_db) { + var db_name = (auth_db ? auth_db : db.databaseName) + "." + DbCommand.SYSTEM_COMMAND_COLLECTION; + return new DbCommand(db, db_name, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null, options); +}; + +DbCommand.createAdminDbCommand = function(db, command_hash) { + return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null); +}; + +DbCommand.createAdminDbCommandSlaveOk = function(db, command_hash) { + return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT | QueryCommand.OPTS_SLAVE, 0, -1, command_hash, null); +}; + +DbCommand.createDbSlaveOkCommand = function(db, command_hash, options) { + return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT | QueryCommand.OPTS_SLAVE, 0, -1, command_hash, null, options); +}; diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/delete_command.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/delete_command.js new file mode 100644 index 0000000..c2765a7 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/delete_command.js @@ -0,0 +1,129 @@ +var BaseCommand = require('./base_command').BaseCommand, + inherits = require('util').inherits; + +/** + Insert Document Command +**/ +var DeleteCommand = exports.DeleteCommand = function(db, collectionName, selector, flags) { + BaseCommand.call(this); + + // Validate correctness off the selector + var object = selector; + if(Buffer.isBuffer(object)) { + var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24; + if(object_size != object.length) { + var error = new Error("delete raw message size does not match message header size [" + object.length + "] != [" + object_size + "]"); + error.name = 'MongoError'; + throw error; + } + } + + this.flags = flags; + this.collectionName = collectionName; + this.selector = selector; + this.db = db; +}; + +inherits(DeleteCommand, BaseCommand); + +DeleteCommand.OP_DELETE = 2006; + +/* +struct { + MsgHeader header; // standard message header + int32 ZERO; // 0 - reserved for future use + cstring fullCollectionName; // "dbname.collectionname" + int32 ZERO; // 0 - reserved for future use + mongo.BSON selector; // query object. See below for details. +} +*/ +DeleteCommand.prototype.toBinary = function(bsonSettings) { + // Validate that we are not passing 0x00 in the colletion name + if(!!~this.collectionName.indexOf("\x00")) { + throw new Error("namespace cannot contain a null character"); + } + + // Calculate total length of the document + var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + this.db.bson.calculateObjectSize(this.selector, false, true) + (4 * 4); + + // Enforce maximum bson size + if(!bsonSettings.disableDriverBSONSizeCheck + && totalLengthOfCommand > bsonSettings.maxBsonSize) + throw new Error("Document exceeds maximum allowed bson size of " + bsonSettings.maxBsonSize + " bytes"); + + if(bsonSettings.disableDriverBSONSizeCheck + && totalLengthOfCommand > bsonSettings.maxMessageSizeBytes) + throw new Error("Command exceeds maximum message size of " + bsonSettings.maxMessageSizeBytes + " bytes"); + + // Let's build the single pass buffer command + var _index = 0; + var _command = new Buffer(totalLengthOfCommand); + // Write the header information to the buffer + _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff; + _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff; + _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff; + _command[_index] = totalLengthOfCommand & 0xff; + // Adjust index + _index = _index + 4; + // Write the request ID + _command[_index + 3] = (this.requestId >> 24) & 0xff; + _command[_index + 2] = (this.requestId >> 16) & 0xff; + _command[_index + 1] = (this.requestId >> 8) & 0xff; + _command[_index] = this.requestId & 0xff; + // Adjust index + _index = _index + 4; + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + // Write the op_code for the command + _command[_index + 3] = (DeleteCommand.OP_DELETE >> 24) & 0xff; + _command[_index + 2] = (DeleteCommand.OP_DELETE >> 16) & 0xff; + _command[_index + 1] = (DeleteCommand.OP_DELETE >> 8) & 0xff; + _command[_index] = DeleteCommand.OP_DELETE & 0xff; + // Adjust index + _index = _index + 4; + + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + + // Write the collection name to the command + _index = _index + _command.write(this.collectionName, _index, 'utf8') + 1; + _command[_index - 1] = 0; + + // Write the flags + _command[_index + 3] = (this.flags >> 24) & 0xff; + _command[_index + 2] = (this.flags >> 16) & 0xff; + _command[_index + 1] = (this.flags >> 8) & 0xff; + _command[_index] = this.flags & 0xff; + // Adjust index + _index = _index + 4; + + // Document binary length + var documentLength = 0 + + // Serialize the selector + // If we are passing a raw buffer, do minimal validation + if(Buffer.isBuffer(this.selector)) { + documentLength = this.selector.length; + // Copy the data into the current buffer + this.selector.copy(_command, _index); + } else { + documentLength = this.db.bson.serializeWithBufferAndIndex(this.selector, this.checkKeys, _command, _index) - _index + 1; + } + + // Write the length to the document + _command[_index + 3] = (documentLength >> 24) & 0xff; + _command[_index + 2] = (documentLength >> 16) & 0xff; + _command[_index + 1] = (documentLength >> 8) & 0xff; + _command[_index] = documentLength & 0xff; + // Update index in buffer + _index = _index + documentLength; + // Add terminating 0 for the object + _command[_index - 1] = 0; + return _command; +}; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/get_more_command.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/get_more_command.js new file mode 100644 index 0000000..1b6b172 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/get_more_command.js @@ -0,0 +1,88 @@ +var BaseCommand = require('./base_command').BaseCommand, + inherits = require('util').inherits, + binaryutils = require('../utils'); + +/** + Get More Document Command +**/ +var GetMoreCommand = exports.GetMoreCommand = function(db, collectionName, numberToReturn, cursorId) { + BaseCommand.call(this); + + this.collectionName = collectionName; + this.numberToReturn = numberToReturn; + this.cursorId = cursorId; + this.db = db; +}; + +inherits(GetMoreCommand, BaseCommand); + +GetMoreCommand.OP_GET_MORE = 2005; + +GetMoreCommand.prototype.toBinary = function() { + // Validate that we are not passing 0x00 in the colletion name + if(!!~this.collectionName.indexOf("\x00")) { + throw new Error("namespace cannot contain a null character"); + } + + // Calculate total length of the document + var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 8 + (4 * 4); + // Let's build the single pass buffer command + var _index = 0; + var _command = new Buffer(totalLengthOfCommand); + // Write the header information to the buffer + _command[_index++] = totalLengthOfCommand & 0xff; + _command[_index++] = (totalLengthOfCommand >> 8) & 0xff; + _command[_index++] = (totalLengthOfCommand >> 16) & 0xff; + _command[_index++] = (totalLengthOfCommand >> 24) & 0xff; + + // Write the request ID + _command[_index++] = this.requestId & 0xff; + _command[_index++] = (this.requestId >> 8) & 0xff; + _command[_index++] = (this.requestId >> 16) & 0xff; + _command[_index++] = (this.requestId >> 24) & 0xff; + + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + + // Write the op_code for the command + _command[_index++] = GetMoreCommand.OP_GET_MORE & 0xff; + _command[_index++] = (GetMoreCommand.OP_GET_MORE >> 8) & 0xff; + _command[_index++] = (GetMoreCommand.OP_GET_MORE >> 16) & 0xff; + _command[_index++] = (GetMoreCommand.OP_GET_MORE >> 24) & 0xff; + + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + + // Write the collection name to the command + _index = _index + _command.write(this.collectionName, _index, 'utf8') + 1; + _command[_index - 1] = 0; + + // Number of documents to return + _command[_index++] = this.numberToReturn & 0xff; + _command[_index++] = (this.numberToReturn >> 8) & 0xff; + _command[_index++] = (this.numberToReturn >> 16) & 0xff; + _command[_index++] = (this.numberToReturn >> 24) & 0xff; + + // Encode the cursor id + var low_bits = this.cursorId.getLowBits(); + // Encode low bits + _command[_index++] = low_bits & 0xff; + _command[_index++] = (low_bits >> 8) & 0xff; + _command[_index++] = (low_bits >> 16) & 0xff; + _command[_index++] = (low_bits >> 24) & 0xff; + + var high_bits = this.cursorId.getHighBits(); + // Encode high bits + _command[_index++] = high_bits & 0xff; + _command[_index++] = (high_bits >> 8) & 0xff; + _command[_index++] = (high_bits >> 16) & 0xff; + _command[_index++] = (high_bits >> 24) & 0xff; + // Return command + return _command; +}; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/insert_command.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/insert_command.js new file mode 100644 index 0000000..c6e51e9 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/insert_command.js @@ -0,0 +1,161 @@ +var BaseCommand = require('./base_command').BaseCommand, + inherits = require('util').inherits; + +/** + Insert Document Command +**/ +var InsertCommand = exports.InsertCommand = function(db, collectionName, checkKeys, options) { + BaseCommand.call(this); + + this.collectionName = collectionName; + this.documents = []; + this.checkKeys = checkKeys == null ? true : checkKeys; + this.db = db; + this.flags = 0; + this.serializeFunctions = false; + + // Ensure valid options hash + options = options == null ? {} : options; + + // Check if we have keepGoing set -> set flag if it's the case + if(options['keepGoing'] != null && options['keepGoing']) { + // This will finish inserting all non-index violating documents even if it returns an error + this.flags = 1; + } + + // Check if we have keepGoing set -> set flag if it's the case + if(options['continueOnError'] != null && options['continueOnError']) { + // This will finish inserting all non-index violating documents even if it returns an error + this.flags = 1; + } + + // Let us defined on a command basis if we want functions to be serialized or not + if(options['serializeFunctions'] != null && options['serializeFunctions']) { + this.serializeFunctions = true; + } +}; + +inherits(InsertCommand, BaseCommand); + +// OpCodes +InsertCommand.OP_INSERT = 2002; + +InsertCommand.prototype.add = function(document) { + if(Buffer.isBuffer(document)) { + var object_size = document[0] | document[1] << 8 | document[2] << 16 | document[3] << 24; + if(object_size != document.length) { + var error = new Error("insert raw message size does not match message header size [" + document.length + "] != [" + object_size + "]"); + error.name = 'MongoError'; + throw error; + } + } + + this.documents.push(document); + return this; +}; + +/* +struct { + MsgHeader header; // standard message header + int32 ZERO; // 0 - reserved for future use + cstring fullCollectionName; // "dbname.collectionname" + BSON[] documents; // one or more documents to insert into the collection +} +*/ +InsertCommand.prototype.toBinary = function(bsonSettings) { + // Validate that we are not passing 0x00 in the colletion name + if(!!~this.collectionName.indexOf("\x00")) { + throw new Error("namespace cannot contain a null character"); + } + + // Calculate total length of the document + var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + (4 * 4); + // var docLength = 0 + for(var i = 0; i < this.documents.length; i++) { + if(Buffer.isBuffer(this.documents[i])) { + totalLengthOfCommand += this.documents[i].length; + } else { + // Calculate size of document + totalLengthOfCommand += this.db.bson.calculateObjectSize(this.documents[i], this.serializeFunctions, true); + } + } + + // Enforce maximum bson size + if(!bsonSettings.disableDriverBSONSizeCheck + && totalLengthOfCommand > bsonSettings.maxBsonSize) + throw new Error("Document exceeds maximum allowed bson size of " + bsonSettings.maxBsonSize + " bytes"); + + if(bsonSettings.disableDriverBSONSizeCheck + && totalLengthOfCommand > bsonSettings.maxMessageSizeBytes) + throw new Error("Command exceeds maximum message size of " + bsonSettings.maxMessageSizeBytes + " bytes"); + + // Let's build the single pass buffer command + var _index = 0; + var _command = new Buffer(totalLengthOfCommand); + // Write the header information to the buffer + _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff; + _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff; + _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff; + _command[_index] = totalLengthOfCommand & 0xff; + // Adjust index + _index = _index + 4; + // Write the request ID + _command[_index + 3] = (this.requestId >> 24) & 0xff; + _command[_index + 2] = (this.requestId >> 16) & 0xff; + _command[_index + 1] = (this.requestId >> 8) & 0xff; + _command[_index] = this.requestId & 0xff; + // Adjust index + _index = _index + 4; + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + // Write the op_code for the command + _command[_index + 3] = (InsertCommand.OP_INSERT >> 24) & 0xff; + _command[_index + 2] = (InsertCommand.OP_INSERT >> 16) & 0xff; + _command[_index + 1] = (InsertCommand.OP_INSERT >> 8) & 0xff; + _command[_index] = InsertCommand.OP_INSERT & 0xff; + // Adjust index + _index = _index + 4; + // Write flags if any + _command[_index + 3] = (this.flags >> 24) & 0xff; + _command[_index + 2] = (this.flags >> 16) & 0xff; + _command[_index + 1] = (this.flags >> 8) & 0xff; + _command[_index] = this.flags & 0xff; + // Adjust index + _index = _index + 4; + // Write the collection name to the command + _index = _index + _command.write(this.collectionName, _index, 'utf8') + 1; + _command[_index - 1] = 0; + + // Write all the bson documents to the buffer at the index offset + for(var i = 0; i < this.documents.length; i++) { + // Document binary length + var documentLength = 0 + var object = this.documents[i]; + + // Serialize the selector + // If we are passing a raw buffer, do minimal validation + if(Buffer.isBuffer(object)) { + documentLength = object.length; + // Copy the data into the current buffer + object.copy(_command, _index); + } else { + // Serialize the document straight to the buffer + documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1; + } + + // Write the length to the document + _command[_index + 3] = (documentLength >> 24) & 0xff; + _command[_index + 2] = (documentLength >> 16) & 0xff; + _command[_index + 1] = (documentLength >> 8) & 0xff; + _command[_index] = documentLength & 0xff; + // Update index in buffer + _index = _index + documentLength; + // Add terminating 0 for the object + _command[_index - 1] = 0; + } + + return _command; +}; diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/kill_cursor_command.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/kill_cursor_command.js new file mode 100644 index 0000000..d8ccb0c --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/kill_cursor_command.js @@ -0,0 +1,98 @@ +var BaseCommand = require('./base_command').BaseCommand, + inherits = require('util').inherits, + binaryutils = require('../utils'); + +/** + Insert Document Command +**/ +var KillCursorCommand = exports.KillCursorCommand = function(db, cursorIds) { + BaseCommand.call(this); + + this.cursorIds = cursorIds; + this.db = db; +}; + +inherits(KillCursorCommand, BaseCommand); + +KillCursorCommand.OP_KILL_CURSORS = 2007; + +/* +struct { + MsgHeader header; // standard message header + int32 ZERO; // 0 - reserved for future use + int32 numberOfCursorIDs; // number of cursorIDs in message + int64[] cursorIDs; // array of cursorIDs to close +} +*/ +KillCursorCommand.prototype.toBinary = function() { + // Calculate total length of the document + var totalLengthOfCommand = 4 + 4 + (4 * 4) + (this.cursorIds.length * 8); + // Let's build the single pass buffer command + var _index = 0; + var _command = new Buffer(totalLengthOfCommand); + // Write the header information to the buffer + _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff; + _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff; + _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff; + _command[_index] = totalLengthOfCommand & 0xff; + // Adjust index + _index = _index + 4; + // Write the request ID + _command[_index + 3] = (this.requestId >> 24) & 0xff; + _command[_index + 2] = (this.requestId >> 16) & 0xff; + _command[_index + 1] = (this.requestId >> 8) & 0xff; + _command[_index] = this.requestId & 0xff; + // Adjust index + _index = _index + 4; + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + // Write the op_code for the command + _command[_index + 3] = (KillCursorCommand.OP_KILL_CURSORS >> 24) & 0xff; + _command[_index + 2] = (KillCursorCommand.OP_KILL_CURSORS >> 16) & 0xff; + _command[_index + 1] = (KillCursorCommand.OP_KILL_CURSORS >> 8) & 0xff; + _command[_index] = KillCursorCommand.OP_KILL_CURSORS & 0xff; + // Adjust index + _index = _index + 4; + + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + + // Number of cursors to kill + var numberOfCursors = this.cursorIds.length; + _command[_index + 3] = (numberOfCursors >> 24) & 0xff; + _command[_index + 2] = (numberOfCursors >> 16) & 0xff; + _command[_index + 1] = (numberOfCursors >> 8) & 0xff; + _command[_index] = numberOfCursors & 0xff; + // Adjust index + _index = _index + 4; + + // Encode all the cursors + for(var i = 0; i < this.cursorIds.length; i++) { + // Encode the cursor id + var low_bits = this.cursorIds[i].getLowBits(); + // Encode low bits + _command[_index + 3] = (low_bits >> 24) & 0xff; + _command[_index + 2] = (low_bits >> 16) & 0xff; + _command[_index + 1] = (low_bits >> 8) & 0xff; + _command[_index] = low_bits & 0xff; + // Adjust index + _index = _index + 4; + + var high_bits = this.cursorIds[i].getHighBits(); + // Encode high bits + _command[_index + 3] = (high_bits >> 24) & 0xff; + _command[_index + 2] = (high_bits >> 16) & 0xff; + _command[_index + 1] = (high_bits >> 8) & 0xff; + _command[_index] = high_bits & 0xff; + // Adjust index + _index = _index + 4; + } + + return _command; +}; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/query_command.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/query_command.js new file mode 100644 index 0000000..16045b8 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/query_command.js @@ -0,0 +1,280 @@ +var BaseCommand = require('./base_command').BaseCommand, + inherits = require('util').inherits; + +/** + Insert Document Command +**/ +var QueryCommand = exports.QueryCommand = function(db, collectionName, queryOptions, numberToSkip, numberToReturn, query, returnFieldSelector, options) { + BaseCommand.call(this); + + // Validate correctness off the selector + var object = query, + object_size; + if(Buffer.isBuffer(object)) { + object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24; + if(object_size != object.length) { + var error = new Error("query selector raw message size does not match message header size [" + object.length + "] != [" + object_size + "]"); + error.name = 'MongoError'; + throw error; + } + } + + object = returnFieldSelector; + if(Buffer.isBuffer(object)) { + object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24; + if(object_size != object.length) { + var error = new Error("query fields raw message size does not match message header size [" + object.length + "] != [" + object_size + "]"); + error.name = 'MongoError'; + throw error; + } + } + + // Make sure we don't get a null exception + options = options == null ? {} : options; + // Set up options + this.collectionName = collectionName; + this.queryOptions = queryOptions; + this.numberToSkip = numberToSkip; + this.numberToReturn = numberToReturn; + + // Ensure we have no null query + query = query == null ? {} : query; + // Wrap query in the $query parameter so we can add read preferences for mongos + this.query = query; + this.returnFieldSelector = returnFieldSelector; + this.db = db; + + // Force the slave ok flag to be set if we are not using primary read preference + if(this.db && this.db.slaveOk) { + this.queryOptions |= QueryCommand.OPTS_SLAVE; + } + + // Let us defined on a command basis if we want functions to be serialized or not + if(options['serializeFunctions'] != null && options['serializeFunctions']) { + this.serializeFunctions = true; + } +}; + +inherits(QueryCommand, BaseCommand); + +QueryCommand.OP_QUERY = 2004; + +/* + * Adds the read prefrence to the current command + */ +QueryCommand.prototype.setMongosReadPreference = function(readPreference, tags) { + // If we have readPreference set to true set to secondary prefered + if(readPreference == true) { + readPreference = 'secondaryPreferred'; + } else if(readPreference == 'false') { + readPreference = 'primary'; + } + + // Force the slave ok flag to be set if we are not using primary read preference + if(readPreference != false && readPreference != 'primary') { + this.queryOptions |= QueryCommand.OPTS_SLAVE; + } + + // Backward compatibility, ensure $query only set on read preference so 1.8.X works + if((readPreference != null || tags != null) && this.query['$query'] == null) { + this.query = {'$query': this.query}; + } + + // If we have no readPreference set and no tags, check if the slaveOk bit is set + if(readPreference == null && tags == null) { + // If we have a slaveOk bit set the read preference for MongoS + if(this.queryOptions & QueryCommand.OPTS_SLAVE) { + this.query['$readPreference'] = {mode: 'secondary'} + } else { + this.query['$readPreference'] = {mode: 'primary'} + } + } + + // Build read preference object + if(typeof readPreference == 'object' && readPreference['_type'] == 'ReadPreference') { + this.query['$readPreference'] = readPreference.toObject(); + } else if(readPreference != null) { + // Add the read preference + this.query['$readPreference'] = {mode: readPreference}; + + // If we have tags let's add them + if(tags != null) { + this.query['$readPreference']['tags'] = tags; + } + } +} + +/* +struct { + MsgHeader header; // standard message header + int32 opts; // query options. See below for details. + cstring fullCollectionName; // "dbname.collectionname" + int32 numberToSkip; // number of documents to skip when returning results + int32 numberToReturn; // number of documents to return in the first OP_REPLY + BSON query ; // query object. See below for details. + [ BSON returnFieldSelector; ] // OPTIONAL : selector indicating the fields to return. See below for details. +} +*/ +QueryCommand.prototype.toBinary = function(bsonSettings) { + // Validate that we are not passing 0x00 in the colletion name + if(!!~this.collectionName.indexOf("\x00")) { + throw new Error("namespace cannot contain a null character"); + } + + // Total length of the command + var totalLengthOfCommand = 0; + // Calculate total length of the document + if(Buffer.isBuffer(this.query)) { + totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 4 + this.query.length + (4 * 4); + } else { + totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 4 + this.db.bson.calculateObjectSize(this.query, this.serializeFunctions, true) + (4 * 4); + } + + // Calculate extra fields size + if(this.returnFieldSelector != null && !(Buffer.isBuffer(this.returnFieldSelector))) { + if(Object.keys(this.returnFieldSelector).length > 0) { + totalLengthOfCommand += this.db.bson.calculateObjectSize(this.returnFieldSelector, this.serializeFunctions, true); + } + } else if(Buffer.isBuffer(this.returnFieldSelector)) { + totalLengthOfCommand += this.returnFieldSelector.length; + } + + // Enforce maximum bson size + if(!bsonSettings.disableDriverBSONSizeCheck + && totalLengthOfCommand > bsonSettings.maxBsonSize) + throw new Error("Document exceeds maximum allowed bson size of " + bsonSettings.maxBsonSize + " bytes"); + + if(bsonSettings.disableDriverBSONSizeCheck + && totalLengthOfCommand > bsonSettings.maxMessageSizeBytes) + throw new Error("Command exceeds maximum message size of " + bsonSettings.maxMessageSizeBytes + " bytes"); + + // Let's build the single pass buffer command + var _index = 0; + var _command = new Buffer(totalLengthOfCommand); + // Write the header information to the buffer + _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff; + _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff; + _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff; + _command[_index] = totalLengthOfCommand & 0xff; + // Adjust index + _index = _index + 4; + // Write the request ID + _command[_index + 3] = (this.requestId >> 24) & 0xff; + _command[_index + 2] = (this.requestId >> 16) & 0xff; + _command[_index + 1] = (this.requestId >> 8) & 0xff; + _command[_index] = this.requestId & 0xff; + // Adjust index + _index = _index + 4; + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + // Write the op_code for the command + _command[_index + 3] = (QueryCommand.OP_QUERY >> 24) & 0xff; + _command[_index + 2] = (QueryCommand.OP_QUERY >> 16) & 0xff; + _command[_index + 1] = (QueryCommand.OP_QUERY >> 8) & 0xff; + _command[_index] = QueryCommand.OP_QUERY & 0xff; + // Adjust index + _index = _index + 4; + + // Write the query options + _command[_index + 3] = (this.queryOptions >> 24) & 0xff; + _command[_index + 2] = (this.queryOptions >> 16) & 0xff; + _command[_index + 1] = (this.queryOptions >> 8) & 0xff; + _command[_index] = this.queryOptions & 0xff; + // Adjust index + _index = _index + 4; + + // Write the collection name to the command + _index = _index + _command.write(this.collectionName, _index, 'utf8') + 1; + _command[_index - 1] = 0; + + // Write the number of documents to skip + _command[_index + 3] = (this.numberToSkip >> 24) & 0xff; + _command[_index + 2] = (this.numberToSkip >> 16) & 0xff; + _command[_index + 1] = (this.numberToSkip >> 8) & 0xff; + _command[_index] = this.numberToSkip & 0xff; + // Adjust index + _index = _index + 4; + + // Write the number of documents to return + _command[_index + 3] = (this.numberToReturn >> 24) & 0xff; + _command[_index + 2] = (this.numberToReturn >> 16) & 0xff; + _command[_index + 1] = (this.numberToReturn >> 8) & 0xff; + _command[_index] = this.numberToReturn & 0xff; + // Adjust index + _index = _index + 4; + + // Document binary length + var documentLength = 0 + var object = this.query; + + // Serialize the selector + if(Buffer.isBuffer(object)) { + documentLength = object.length; + // Copy the data into the current buffer + object.copy(_command, _index); + } else { + // Serialize the document straight to the buffer + documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1; + } + + // Write the length to the document + _command[_index + 3] = (documentLength >> 24) & 0xff; + _command[_index + 2] = (documentLength >> 16) & 0xff; + _command[_index + 1] = (documentLength >> 8) & 0xff; + _command[_index] = documentLength & 0xff; + // Update index in buffer + _index = _index + documentLength; + // Add terminating 0 for the object + _command[_index - 1] = 0; + + // Push field selector if available + if(this.returnFieldSelector != null && !(Buffer.isBuffer(this.returnFieldSelector))) { + if(Object.keys(this.returnFieldSelector).length > 0) { + var documentLength = this.db.bson.serializeWithBufferAndIndex(this.returnFieldSelector, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1; + // Write the length to the document + _command[_index + 3] = (documentLength >> 24) & 0xff; + _command[_index + 2] = (documentLength >> 16) & 0xff; + _command[_index + 1] = (documentLength >> 8) & 0xff; + _command[_index] = documentLength & 0xff; + // Update index in buffer + _index = _index + documentLength; + // Add terminating 0 for the object + _command[_index - 1] = 0; + } + } if(this.returnFieldSelector != null && Buffer.isBuffer(this.returnFieldSelector)) { + // Document binary length + var documentLength = 0 + var object = this.returnFieldSelector; + + // Serialize the selector + documentLength = object.length; + // Copy the data into the current buffer + object.copy(_command, _index); + + // Write the length to the document + _command[_index + 3] = (documentLength >> 24) & 0xff; + _command[_index + 2] = (documentLength >> 16) & 0xff; + _command[_index + 1] = (documentLength >> 8) & 0xff; + _command[_index] = documentLength & 0xff; + // Update index in buffer + _index = _index + documentLength; + // Add terminating 0 for the object + _command[_index - 1] = 0; + } + + // Return finished command + return _command; +}; + +// Constants +QueryCommand.OPTS_NONE = 0; +QueryCommand.OPTS_TAILABLE_CURSOR = 2; +QueryCommand.OPTS_SLAVE = 4; +QueryCommand.OPTS_OPLOG_REPLY = 8; +QueryCommand.OPTS_NO_CURSOR_TIMEOUT = 16; +QueryCommand.OPTS_AWAIT_DATA = 32; +QueryCommand.OPTS_EXHAUST = 64; +QueryCommand.OPTS_PARTIAL = 128; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/update_command.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/update_command.js new file mode 100644 index 0000000..daa3cba --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/commands/update_command.js @@ -0,0 +1,189 @@ +var BaseCommand = require('./base_command').BaseCommand, + inherits = require('util').inherits; + +/** + Update Document Command +**/ +var UpdateCommand = exports.UpdateCommand = function(db, collectionName, spec, document, options) { + BaseCommand.call(this); + + var object = spec; + if(Buffer.isBuffer(object)) { + var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24; + if(object_size != object.length) { + var error = new Error("update spec raw message size does not match message header size [" + object.length + "] != [" + object_size + "]"); + error.name = 'MongoError'; + throw error; + } + } + + var object = document; + if(Buffer.isBuffer(object)) { + var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24; + if(object_size != object.length) { + var error = new Error("update document raw message size does not match message header size [" + object.length + "] != [" + object_size + "]"); + error.name = 'MongoError'; + throw error; + } + } + + this.collectionName = collectionName; + this.spec = spec; + this.document = document; + this.db = db; + this.serializeFunctions = false; + this.checkKeys = typeof options.checkKeys != 'boolean' ? false : options.checkKeys; + + // Generate correct flags + var db_upsert = 0; + var db_multi_update = 0; + db_upsert = options != null && options['upsert'] != null ? (options['upsert'] == true ? 1 : 0) : db_upsert; + db_multi_update = options != null && options['multi'] != null ? (options['multi'] == true ? 1 : 0) : db_multi_update; + + // Flags + this.flags = parseInt(db_multi_update.toString() + db_upsert.toString(), 2); + // Let us defined on a command basis if we want functions to be serialized or not + if(options['serializeFunctions'] != null && options['serializeFunctions']) { + this.serializeFunctions = true; + } +}; + +inherits(UpdateCommand, BaseCommand); + +UpdateCommand.OP_UPDATE = 2001; + +/* +struct { + MsgHeader header; // standard message header + int32 ZERO; // 0 - reserved for future use + cstring fullCollectionName; // "dbname.collectionname" + int32 flags; // bit vector. see below + BSON spec; // the query to select the document + BSON document; // the document data to update with or insert +} +*/ +UpdateCommand.prototype.toBinary = function(bsonSettings) { + // Validate that we are not passing 0x00 in the colletion name + if(!!~this.collectionName.indexOf("\x00")) { + throw new Error("namespace cannot contain a null character"); + } + + // Calculate total length of the document + var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + this.db.bson.calculateObjectSize(this.spec, false, true) + + this.db.bson.calculateObjectSize(this.document, this.serializeFunctions, true) + (4 * 4); + + // Enforce maximum bson size + if(!bsonSettings.disableDriverBSONSizeCheck + && totalLengthOfCommand > bsonSettings.maxBsonSize) + throw new Error("Document exceeds maximum allowed bson size of " + bsonSettings.maxBsonSize + " bytes"); + + if(bsonSettings.disableDriverBSONSizeCheck + && totalLengthOfCommand > bsonSettings.maxMessageSizeBytes) + throw new Error("Command exceeds maximum message size of " + bsonSettings.maxMessageSizeBytes + " bytes"); + + // Let's build the single pass buffer command + var _index = 0; + var _command = new Buffer(totalLengthOfCommand); + // Write the header information to the buffer + _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff; + _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff; + _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff; + _command[_index] = totalLengthOfCommand & 0xff; + // Adjust index + _index = _index + 4; + // Write the request ID + _command[_index + 3] = (this.requestId >> 24) & 0xff; + _command[_index + 2] = (this.requestId >> 16) & 0xff; + _command[_index + 1] = (this.requestId >> 8) & 0xff; + _command[_index] = this.requestId & 0xff; + // Adjust index + _index = _index + 4; + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + // Write the op_code for the command + _command[_index + 3] = (UpdateCommand.OP_UPDATE >> 24) & 0xff; + _command[_index + 2] = (UpdateCommand.OP_UPDATE >> 16) & 0xff; + _command[_index + 1] = (UpdateCommand.OP_UPDATE >> 8) & 0xff; + _command[_index] = UpdateCommand.OP_UPDATE & 0xff; + // Adjust index + _index = _index + 4; + + // Write zero + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + _command[_index++] = 0; + + // Write the collection name to the command + _index = _index + _command.write(this.collectionName, _index, 'utf8') + 1; + _command[_index - 1] = 0; + + // Write the update flags + _command[_index + 3] = (this.flags >> 24) & 0xff; + _command[_index + 2] = (this.flags >> 16) & 0xff; + _command[_index + 1] = (this.flags >> 8) & 0xff; + _command[_index] = this.flags & 0xff; + // Adjust index + _index = _index + 4; + + // Document binary length + var documentLength = 0 + var object = this.spec; + + // Serialize the selector + // If we are passing a raw buffer, do minimal validation + if(Buffer.isBuffer(object)) { + var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24; + if(object_size != object.length) throw new Error("raw message size does not match message header size [" + object.length + "] != [" + object_size + "]"); + documentLength = object.length; + // Copy the data into the current buffer + object.copy(_command, _index); + } else { + documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, false) - _index + 1; + } + + // Write the length to the document + _command[_index + 3] = (documentLength >> 24) & 0xff; + _command[_index + 2] = (documentLength >> 16) & 0xff; + _command[_index + 1] = (documentLength >> 8) & 0xff; + _command[_index] = documentLength & 0xff; + // Update index in buffer + _index = _index + documentLength; + // Add terminating 0 for the object + _command[_index - 1] = 0; + + // Document binary length + var documentLength = 0 + var object = this.document; + + // Serialize the document + // If we are passing a raw buffer, do minimal validation + if(Buffer.isBuffer(object)) { + var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24; + if(object_size != object.length) throw new Error("raw message size does not match message header size [" + object.length + "] != [" + object_size + "]"); + documentLength = object.length; + // Copy the data into the current buffer + object.copy(_command, _index); + } else { + documentLength = this.db.bson.serializeWithBufferAndIndex(object, false, _command, _index, this.serializeFunctions) - _index + 1; + } + + // Write the length to the document + _command[_index + 3] = (documentLength >> 24) & 0xff; + _command[_index + 2] = (documentLength >> 16) & 0xff; + _command[_index + 1] = (documentLength >> 8) & 0xff; + _command[_index] = documentLength & 0xff; + // Update index in buffer + _index = _index + documentLength; + // Add terminating 0 for the object + _command[_index - 1] = 0; + + return _command; +}; + +// Constants +UpdateCommand.DB_UPSERT = 0; +UpdateCommand.DB_MULTI_UPDATE = 1; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/base.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/base.js new file mode 100644 index 0000000..30cdc5f --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/base.js @@ -0,0 +1,442 @@ +var EventEmitter = require('events').EventEmitter + , inherits = require('util').inherits + , mongodb_cr_authenticate = require('../auth/mongodb_cr.js').authenticate + , mongodb_gssapi_authenticate = require('../auth/mongodb_gssapi.js').authenticate + , mongodb_sspi_authenticate = require('../auth/mongodb_sspi.js').authenticate; + +var id = 0; + +/** + * Internal class for callback storage + * @ignore + */ +var CallbackStore = function() { + // Make class an event emitter + EventEmitter.call(this); + // Add a info about call variable + this._notReplied = {}; + this.id = id++; +} + +/** + * @ignore + */ +inherits(CallbackStore, EventEmitter); + +CallbackStore.prototype.notRepliedToIds = function() { + return Object.keys(this._notReplied); +} + +CallbackStore.prototype.callbackInfo = function(id) { + return this._notReplied[id]; +} + +/** + * Internal class for holding non-executed commands + * @ignore + */ +var NonExecutedOperationStore = function(config) { + this.config = config; + this.commands = { + read: [] + , write_reads: [] + , write: [] + }; +} + +NonExecutedOperationStore.prototype.write = function(op) { + this.commands.write.push(op); +} + +NonExecutedOperationStore.prototype.read_from_writer = function(op) { + this.commands.write_reads.push(op); +} + +NonExecutedOperationStore.prototype.read = function(op) { + this.commands.read.push(op); +} + +NonExecutedOperationStore.prototype.execute_queries = function(executeInsertCommand) { + var connection = this.config.checkoutReader(); + if(connection == null || connection instanceof Error) return; + + // Write out all the queries + while(this.commands.read.length > 0) { + // Get the next command + var command = this.commands.read.shift(); + command.options.connection = connection; + // Execute the next command + command.executeQueryCommand(command.db, command.db_command, command.options, command.callback); + } +} + +NonExecutedOperationStore.prototype.execute_writes = function() { + var connection = this.config.checkoutWriter(); + if(connection == null || connection instanceof Error) return; + + // Write out all the queries to the primary + while(this.commands.write_reads.length > 0) { + // Get the next command + var command = this.commands.write_reads.shift(); + command.options.connection = connection; + // Execute the next command + command.executeQueryCommand(command.db, command.db_command, command.options, command.callback); + } + + // Execute all write operations + while(this.commands.write.length > 0) { + // Get the next command + var command = this.commands.write.shift(); + // Set the connection + command.options.connection = connection; + // Execute the next command + command.executeInsertCommand(command.db, command.db_command, command.options, command.callback); + } +} + +/** + * Internal class for authentication storage + * @ignore + */ +var AuthStore = function() { + this._auths = []; +} + +AuthStore.prototype.add = function(authMechanism, dbName, username, password, authdbName, gssapiServiceName) { + // Check for duplicates + if(!this.contains(dbName)) { + // Base config + var config = { + 'username':username + , 'password':password + , 'db': dbName + , 'authMechanism': authMechanism + , 'gssapiServiceName': gssapiServiceName + }; + + // Add auth source if passed in + if(typeof authdbName == 'string') { + config['authdb'] = authdbName; + } + + // Push the config + this._auths.push(config); + } +} + +AuthStore.prototype.contains = function(dbName) { + for(var i = 0; i < this._auths.length; i++) { + if(this._auths[i].db == dbName) return true; + } + + return false; +} + +AuthStore.prototype.remove = function(dbName) { + var newAuths = []; + + // Filter out all the login details + for(var i = 0; i < this._auths.length; i++) { + if(this._auths[i].db != dbName) newAuths.push(this._auths[i]); + } + + // Set the filtered list + this._auths = newAuths; +} + +AuthStore.prototype.get = function(index) { + return this._auths[index]; +} + +AuthStore.prototype.length = function() { + return this._auths.length; +} + +AuthStore.prototype.toArray = function() { + return this._auths.slice(0); +} + +/** + * Internal class for storing db references + * @ignore + */ +var DbStore = function() { + this._dbs = []; +} + +DbStore.prototype.add = function(db) { + var found = false; + + // Only add if it does not exist already + for(var i = 0; i < this._dbs.length; i++) { + if(db.databaseName == this._dbs[i].databaseName) found = true; + } + + // Only add if it does not already exist + if(!found) { + this._dbs.push(db); + } +} + +DbStore.prototype.reset = function() { + this._dbs = []; +} + +DbStore.prototype.fetch = function(databaseName) { + // Only add if it does not exist already + for(var i = 0; i < this._dbs.length; i++) { + if(databaseName == this._dbs[i].databaseName) + return this._dbs[i]; + } + + return null; +} + +DbStore.prototype.emit = function(event, message, object, reset, filterDb, rethrow_if_no_listeners) { + var emitted = false; + + // Emit the events + for(var i = 0; i < this._dbs.length; i++) { + if(this._dbs[i].listeners(event).length > 0) { + if(filterDb == null || filterDb.databaseName !== this._dbs[i].databaseName + || filterDb.tag !== this._dbs[i].tag) { + this._dbs[i].emit(event, message, object == null ? this._dbs[i] : object); + emitted = true; + } + } + } + + // Emit error message + if(message + && event == 'error' + && !emitted + && rethrow_if_no_listeners + && object && object.db) { + process.nextTick(function() { + object.db.emit(event, message, null); + }) + } + + // Not emitted and we have enabled rethrow, let process.uncaughtException + // deal with the issue + if(!emitted && rethrow_if_no_listeners) { + throw message; + } +} + +var Base = function Base() { + EventEmitter.call(this); + + // Callback store is part of connection specification + if(Base._callBackStore == null) { + Base._callBackStore = new CallbackStore(); + } + + // Create a new callback store + this._callBackStore = new CallbackStore(); + // All commands not being executed + this._commandsStore = new NonExecutedOperationStore(this); + // Create a new auth store + this.auth = new AuthStore(); + // Contains all the dbs attached to this server config + this._dbStore = new DbStore(); +} + +/** + * @ignore + */ +inherits(Base, EventEmitter); + +/** + * @ignore + */ +Base.prototype._apply_auths = function(db, callback) { + _apply_auths_serially(this, db, this.auth.toArray(), callback); +} + +var _apply_auths_serially = function(self, db, auths, callback) { + if(auths.length == 0) return callback(null, null); + // Get the first auth + var auth = auths.shift(); + var connections = self.allRawConnections(); + var connectionsLeft = connections.length; + var options = {}; + + if(auth.authMechanism == 'GSSAPI') { + // We have the kerberos library, execute auth process + if(process.platform == 'win32') { + mongodb_sspi_authenticate(db, auth.username, auth.password, auth.authdb, options, callback); + } else { + mongodb_gssapi_authenticate(db, auth.username, auth.password, auth.authdb, options, callback); + } + } else if(auth.authMechanism == 'MONGODB-CR') { + mongodb_cr_authenticate(db, auth.username, auth.password, auth.authdb, options, callback); + } +} + +/** + * Fire all the errors + * @ignore + */ +Base.prototype.__executeAllCallbacksWithError = function(err) { + // Check all callbacks + var keys = Object.keys(this._callBackStore._notReplied); + // For each key check if it's a callback that needs to be returned + for(var j = 0; j < keys.length; j++) { + var info = this._callBackStore._notReplied[keys[j]]; + // Execute callback with error + this._callBackStore.emit(keys[j], err, null); + // Remove the key + delete this._callBackStore._notReplied[keys[j]]; + // Force cleanup _events, node.js seems to set it as a null value + if(this._callBackStore._events) { + delete this._callBackStore._events[keys[j]]; + } + } +} + +/** + * Fire all the errors + * @ignore + */ +Base.prototype.__executeAllServerSpecificErrorCallbacks = function(host, port, err) { + // Check all callbacks + var keys = Object.keys(this._callBackStore._notReplied); + // For each key check if it's a callback that needs to be returned + for(var j = 0; j < keys.length; j++) { + var info = this._callBackStore._notReplied[keys[j]]; + + if(info.connection) { + // Unpack the connection settings + var _host = info.connection.socketOptions.host; + var _port = info.connection.socketOptions.port; + // If the server matches execute the callback with the error + if(_port == port && _host == host) { + this._callBackStore.emit(keys[j], err, null); + // Remove the key + delete this._callBackStore._notReplied[keys[j]]; + // Force cleanup _events, node.js seems to set it as a null value + if(this._callBackStore._events) { + delete this._callBackStore._events[keys[j]]; + } + } + } + } +} + +/** + * Register a handler + * @ignore + * @api private + */ +Base.prototype._registerHandler = function(db_command, raw, connection, exhaust, callback) { + // Check if we have exhausted + if(typeof exhaust == 'function') { + callback = exhaust; + exhaust = false; + } + + // Add the callback to the list of handlers + this._callBackStore.once(db_command.getRequestId(), callback); + // Add the information about the reply + this._callBackStore._notReplied[db_command.getRequestId().toString()] = {start: new Date().getTime(), 'raw': raw, connection:connection, exhaust:exhaust}; +} + +/** + * Re-Register a handler, on the cursor id f.ex + * @ignore + * @api private + */ +Base.prototype._reRegisterHandler = function(newId, object, callback) { + // Add the callback to the list of handlers + this._callBackStore.once(newId, object.callback.listener); + // Add the information about the reply + this._callBackStore._notReplied[newId] = object.info; +} + +/** + * + * @ignore + * @api private + */ +Base.prototype._callHandler = function(id, document, err) { + var self = this; + + // If there is a callback peform it + if(this._callBackStore.listeners(id).length >= 1) { + // Get info object + var info = this._callBackStore._notReplied[id]; + // Delete the current object + delete this._callBackStore._notReplied[id]; + // Call the handle directly don't emit + var callback = this._callBackStore.listeners(id)[0].listener; + // Remove the listeners + this._callBackStore.removeAllListeners(id); + // Force key deletion because it nulling it not deleting in 0.10.X + if(this._callBackStore._events) { + delete this._callBackStore._events[id]; + } + + try { + // Execute the callback if one was provided + if(typeof callback == 'function') callback(err, document, info.connection); + } catch(err) { + self._emitAcrossAllDbInstances(self, null, "error", err, self, true, true); + } + } +} + +/** + * + * @ignore + * @api private + */ +Base.prototype._hasHandler = function(id) { + return this._callBackStore.listeners(id).length >= 1; +} + +/** + * + * @ignore + * @api private + */ +Base.prototype._removeHandler = function(id) { + // Remove the information + if(this._callBackStore._notReplied[id] != null) delete this._callBackStore._notReplied[id]; + // Remove the callback if it's registered + this._callBackStore.removeAllListeners(id); + // Force cleanup _events, node.js seems to set it as a null value + if(this._callBackStore._events) { + delete this._callBackStore._events[id]; + } +} + +/** + * + * @ignore + * @api private + */ +Base.prototype._findHandler = function(id) { + var info = this._callBackStore._notReplied[id]; + // Return the callback + return {info:info, callback:(this._callBackStore.listeners(id).length >= 1) ? this._callBackStore.listeners(id)[0] : null} +} + +/** + * + * @ignore + * @api private + */ +Base.prototype._emitAcrossAllDbInstances = function(server, filterDb, event, message, object, resetConnection, rethrow_if_no_listeners) { + if(resetConnection) { + for(var i = 0; i < this._dbStore._dbs.length; i++) { + if(typeof this._dbStore._dbs[i].openCalled != 'undefined') + this._dbStore._dbs[i].openCalled = false; + } + } + + // Fire event + this._dbStore.emit(event, message, object, resetConnection, filterDb, rethrow_if_no_listeners); +} + +exports.Base = Base; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection.js new file mode 100644 index 0000000..8f4d4c0 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection.js @@ -0,0 +1,507 @@ +var utils = require('./connection_utils'), + inherits = require('util').inherits, + net = require('net'), + EventEmitter = require('events').EventEmitter, + inherits = require('util').inherits, + binaryutils = require('../utils'), + tls = require('tls'); + +var Connection = exports.Connection = function(id, socketOptions) { + // Set up event emitter + EventEmitter.call(this); + // Store all socket options + this.socketOptions = socketOptions ? socketOptions : {host:'localhost', port:27017, domainSocket:false}; + // Set keep alive default if not overriden + if(this.socketOptions.keepAlive == null && (process.platform !== "sunos" || process.platform !== "win32")) this.socketOptions.keepAlive = 100; + // Id for the connection + this.id = id; + // State of the connection + this.connected = false; + // Set if this is a domain socket + this.domainSocket = this.socketOptions.domainSocket; + + // + // Connection parsing state + // + this.maxBsonSize = socketOptions.maxBsonSize ? socketOptions.maxBsonSize : Connection.DEFAULT_MAX_BSON_SIZE; + this.maxMessageSizeBytes = socketOptions.maxMessageSizeBytes ? socketOptions.maxMessageSizeBytes : Connection.DEFAULT_MAX_MESSAGE_SIZE; + // Contains the current message bytes + this.buffer = null; + // Contains the current message size + this.sizeOfMessage = 0; + // Contains the readIndex for the messaage + this.bytesRead = 0; + // Contains spill over bytes from additional messages + this.stubBuffer = 0; + + // Just keeps list of events we allow + this.eventHandlers = {error:[], parseError:[], poolReady:[], message:[], close:[], timeout:[], end:[]}; + + // Just keeps list of events we allow + resetHandlers(this, false); + // Bson object + this.maxBsonSettings = { + disableDriverBSONSizeCheck: this.socketOptions['disableDriverBSONSizeCheck'] || false + , maxBsonSize: this.maxBsonSize + , maxMessageSizeBytes: this.maxMessageSizeBytes + } +} + +// Set max bson size +Connection.DEFAULT_MAX_BSON_SIZE = 1024 * 1024 * 4; +// Set default to max bson to avoid overflow or bad guesses +Connection.DEFAULT_MAX_MESSAGE_SIZE = Connection.DEFAULT_MAX_BSON_SIZE; + +// Inherit event emitter so we can emit stuff wohoo +inherits(Connection, EventEmitter); + +Connection.prototype.start = function() { + var self = this; + + // If we have a normal connection + if(this.socketOptions.ssl) { + // Create new connection instance + if(this.domainSocket) { + this.connection = net.createConnection(this.socketOptions.host); + } else { + this.connection = net.createConnection(this.socketOptions.port, this.socketOptions.host); + } + if(this.logger != null && this.logger.doDebug){ + this.logger.debug("opened connection", this.socketOptions); + } + // Set options on the socket + this.connection.setTimeout(this.socketOptions.connectTimeoutMS != null ? this.socketOptions.connectTimeoutMS : this.socketOptions.timeout); + // Work around for 0.4.X + if(process.version.indexOf("v0.4") == -1) this.connection.setNoDelay(this.socketOptions.noDelay); + // Set keep alive if defined + if(process.version.indexOf("v0.4") == -1) { + if(this.socketOptions.keepAlive > 0) { + this.connection.setKeepAlive(true, this.socketOptions.keepAlive); + } else { + this.connection.setKeepAlive(false); + } + } + + // Check if the driver should validate the certificate + var validate_certificates = this.socketOptions.sslValidate == true ? true : false; + + // Create options for the tls connection + var tls_options = { + socket: this.connection + , rejectUnauthorized: false + } + + // If we wish to validate the certificate we have provided a ca store + if(validate_certificates) { + tls_options.ca = this.socketOptions.sslCA; + } + + // If we have a certificate to present + if(this.socketOptions.sslCert) { + tls_options.cert = this.socketOptions.sslCert; + tls_options.key = this.socketOptions.sslKey; + } + + // If the driver has been provided a private key password + if(this.socketOptions.sslPass) { + tls_options.passphrase = this.socketOptions.sslPass; + } + + // Contains the cleartext stream + var cleartext = null; + // Attempt to establish a TLS connection to the server + try { + cleartext = tls.connect(this.socketOptions.port, this.socketOptions.host, tls_options, function() { + // If we have a ssl certificate validation error return an error + if(cleartext.authorizationError && validate_certificates) { + // Emit an error + return self.emit("error", cleartext.authorizationError, self, {ssl:true}); + } + + // Connect to the server + connectHandler(self)(); + }) + } catch(err) { + return self.emit("error", "SSL connection failed", self, {ssl:true}); + } + + // Save the output stream + this.writeSteam = cleartext; + + // Set up data handler for the clear stream + cleartext.on("data", createDataHandler(this)); + // Do any handling of end event of the stream + cleartext.on("end", endHandler(this)); + cleartext.on("error", errorHandler(this)); + + // Handle any errors + this.connection.on("error", errorHandler(this)); + // Handle timeout + this.connection.on("timeout", timeoutHandler(this)); + // Handle drain event + this.connection.on("drain", drainHandler(this)); + // Handle the close event + this.connection.on("close", closeHandler(this)); + } else { + // Create new connection instance + if(this.domainSocket) { + this.connection = net.createConnection(this.socketOptions.host); + } else { + this.connection = net.createConnection(this.socketOptions.port, this.socketOptions.host); + } + if(this.logger != null && this.logger.doDebug){ + this.logger.debug("opened connection", this.socketOptions); + } + + // Set options on the socket + this.connection.setTimeout(this.socketOptions.connectTimeoutMS != null ? this.socketOptions.connectTimeoutMS : this.socketOptions.timeout); + // Work around for 0.4.X + if(process.version.indexOf("v0.4") == -1) this.connection.setNoDelay(this.socketOptions.noDelay); + // Set keep alive if defined + if(process.version.indexOf("v0.4") == -1) { + if(this.socketOptions.keepAlive > 0) { + this.connection.setKeepAlive(true, this.socketOptions.keepAlive); + } else { + this.connection.setKeepAlive(false); + } + } + + // Set up write stream + this.writeSteam = this.connection; + // Add handlers + this.connection.on("error", errorHandler(this)); + // Add all handlers to the socket to manage it + this.connection.on("connect", connectHandler(this)); + // this.connection.on("end", endHandler(this)); + this.connection.on("data", createDataHandler(this)); + this.connection.on("timeout", timeoutHandler(this)); + this.connection.on("drain", drainHandler(this)); + this.connection.on("close", closeHandler(this)); + } +} + +// Check if the sockets are live +Connection.prototype.isConnected = function() { + return this.connected && !this.connection.destroyed && this.connection.writable && this.connection.readable; +} + +// Write the data out to the socket +Connection.prototype.write = function(command, callback) { + try { + // If we have a list off commands to be executed on the same socket + if(Array.isArray(command)) { + for(var i = 0; i < command.length; i++) { + try { + // Pass in the bson validation settings (validate early) + var binaryCommand = command[i].toBinary(this.maxBsonSettings) + + if(this.logger != null && this.logger.doDebug) + this.logger.debug("writing command to mongodb", {binary: binaryCommand, json: command[i]}); + + this.writeSteam.write(binaryCommand); + } catch(err) { + return callback(err, null); + } + } + } else { + try { + // Pass in the bson validation settings (validate early) + var binaryCommand = command.toBinary(this.maxBsonSettings) + + if(this.logger != null && this.logger.doDebug) + this.logger.debug("writing command to mongodb", {binary: binaryCommand, json: command[i]}); + + this.writeSteam.write(binaryCommand); + } catch(err) { + return callback(err, null) + } + } + } catch (err) { + if(typeof callback === 'function') callback(err); + } +} + +// Force the closure of the connection +Connection.prototype.close = function() { + // clear out all the listeners + resetHandlers(this, true); + // Add a dummy error listener to catch any weird last moment errors (and ignore them) + this.connection.on("error", function() {}) + // destroy connection + this.connection.destroy(); + if(this.logger != null && this.logger.doDebug){ + this.logger.debug("closed connection", this.connection); + } +} + +// Reset all handlers +var resetHandlers = function(self, clearListeners) { + self.eventHandlers = {error:[], connect:[], close:[], end:[], timeout:[], parseError:[], message:[]}; + + // If we want to clear all the listeners + if(clearListeners && self.connection != null) { + var keys = Object.keys(self.eventHandlers); + // Remove all listeners + for(var i = 0; i < keys.length; i++) { + self.connection.removeAllListeners(keys[i]); + } + } +} + +// +// Handlers +// + +// Connect handler +var connectHandler = function(self) { + return function(data) { + // Set connected + self.connected = true; + // Now that we are connected set the socket timeout + self.connection.setTimeout(self.socketOptions.socketTimeoutMS != null ? self.socketOptions.socketTimeoutMS : self.socketOptions.timeout); + // Emit the connect event with no error + self.emit("connect", null, self); + } +} + +var createDataHandler = exports.Connection.createDataHandler = function(self) { + // We need to handle the parsing of the data + // and emit the messages when there is a complete one + return function(data) { + // Parse until we are done with the data + while(data.length > 0) { + // If we still have bytes to read on the current message + if(self.bytesRead > 0 && self.sizeOfMessage > 0) { + // Calculate the amount of remaining bytes + var remainingBytesToRead = self.sizeOfMessage - self.bytesRead; + // Check if the current chunk contains the rest of the message + if(remainingBytesToRead > data.length) { + // Copy the new data into the exiting buffer (should have been allocated when we know the message size) + data.copy(self.buffer, self.bytesRead); + // Adjust the number of bytes read so it point to the correct index in the buffer + self.bytesRead = self.bytesRead + data.length; + + // Reset state of buffer + data = new Buffer(0); + } else { + // Copy the missing part of the data into our current buffer + data.copy(self.buffer, self.bytesRead, 0, remainingBytesToRead); + // Slice the overflow into a new buffer that we will then re-parse + data = data.slice(remainingBytesToRead); + + // Emit current complete message + try { + var emitBuffer = self.buffer; + // Reset state of buffer + self.buffer = null; + self.sizeOfMessage = 0; + self.bytesRead = 0; + self.stubBuffer = null; + // Emit the buffer + self.emit("message", emitBuffer, self); + } catch(err) { + var errorObject = {err:"socketHandler", trace:err, bin:self.buffer, parseState:{ + sizeOfMessage:self.sizeOfMessage, + bytesRead:self.bytesRead, + stubBuffer:self.stubBuffer}}; + if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject); + // We got a parse Error fire it off then keep going + self.emit("parseError", errorObject, self); + } + } + } else { + // Stub buffer is kept in case we don't get enough bytes to determine the + // size of the message (< 4 bytes) + if(self.stubBuffer != null && self.stubBuffer.length > 0) { + + // If we have enough bytes to determine the message size let's do it + if(self.stubBuffer.length + data.length > 4) { + // Prepad the data + var newData = new Buffer(self.stubBuffer.length + data.length); + self.stubBuffer.copy(newData, 0); + data.copy(newData, self.stubBuffer.length); + // Reassign for parsing + data = newData; + + // Reset state of buffer + self.buffer = null; + self.sizeOfMessage = 0; + self.bytesRead = 0; + self.stubBuffer = null; + + } else { + + // Add the the bytes to the stub buffer + var newStubBuffer = new Buffer(self.stubBuffer.length + data.length); + // Copy existing stub buffer + self.stubBuffer.copy(newStubBuffer, 0); + // Copy missing part of the data + data.copy(newStubBuffer, self.stubBuffer.length); + // Exit parsing loop + data = new Buffer(0); + } + } else { + if(data.length > 4) { + // Retrieve the message size + var sizeOfMessage = binaryutils.decodeUInt32(data, 0); + // If we have a negative sizeOfMessage emit error and return + if(sizeOfMessage < 0 || sizeOfMessage > self.maxBsonSize) { + var errorObject = {err:"socketHandler", trace:'', bin:self.buffer, parseState:{ + sizeOfMessage: sizeOfMessage, + bytesRead: self.bytesRead, + stubBuffer: self.stubBuffer}}; + if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject); + // We got a parse Error fire it off then keep going + self.emit("parseError", errorObject, self); + return; + } + + // Ensure that the size of message is larger than 0 and less than the max allowed + if(sizeOfMessage > 4 && sizeOfMessage < self.maxBsonSize && sizeOfMessage > data.length) { + self.buffer = new Buffer(sizeOfMessage); + // Copy all the data into the buffer + data.copy(self.buffer, 0); + // Update bytes read + self.bytesRead = data.length; + // Update sizeOfMessage + self.sizeOfMessage = sizeOfMessage; + // Ensure stub buffer is null + self.stubBuffer = null; + // Exit parsing loop + data = new Buffer(0); + + } else if(sizeOfMessage > 4 && sizeOfMessage < self.maxBsonSize && sizeOfMessage == data.length) { + try { + var emitBuffer = data; + // Reset state of buffer + self.buffer = null; + self.sizeOfMessage = 0; + self.bytesRead = 0; + self.stubBuffer = null; + // Exit parsing loop + data = new Buffer(0); + // Emit the message + self.emit("message", emitBuffer, self); + } catch (err) { + var errorObject = {err:"socketHandler", trace:err, bin:self.buffer, parseState:{ + sizeOfMessage:self.sizeOfMessage, + bytesRead:self.bytesRead, + stubBuffer:self.stubBuffer}}; + if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject); + // We got a parse Error fire it off then keep going + self.emit("parseError", errorObject, self); + } + } else if(sizeOfMessage <= 4 || sizeOfMessage > self.maxBsonSize) { + var errorObject = {err:"socketHandler", trace:null, bin:data, parseState:{ + sizeOfMessage:sizeOfMessage, + bytesRead:0, + buffer:null, + stubBuffer:null}}; + if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject); + // We got a parse Error fire it off then keep going + self.emit("parseError", errorObject, self); + + // Clear out the state of the parser + self.buffer = null; + self.sizeOfMessage = 0; + self.bytesRead = 0; + self.stubBuffer = null; + // Exit parsing loop + data = new Buffer(0); + + } else { + try { + var emitBuffer = data.slice(0, sizeOfMessage); + // Reset state of buffer + self.buffer = null; + self.sizeOfMessage = 0; + self.bytesRead = 0; + self.stubBuffer = null; + // Copy rest of message + data = data.slice(sizeOfMessage); + // Emit the message + self.emit("message", emitBuffer, self); + } catch (err) { + var errorObject = {err:"socketHandler", trace:err, bin:self.buffer, parseState:{ + sizeOfMessage:sizeOfMessage, + bytesRead:self.bytesRead, + stubBuffer:self.stubBuffer}}; + if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject); + // We got a parse Error fire it off then keep going + self.emit("parseError", errorObject, self); + } + + } + } else { + // Create a buffer that contains the space for the non-complete message + self.stubBuffer = new Buffer(data.length) + // Copy the data to the stub buffer + data.copy(self.stubBuffer, 0); + // Exit parsing loop + data = new Buffer(0); + } + } + } + } + } +} + +var endHandler = function(self) { + return function() { + // Set connected to false + self.connected = false; + // Emit end event + self.emit("end", {err: 'connection received Fin packet from [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self); + } +} + +var timeoutHandler = function(self) { + return function() { + // Set connected to false + self.connected = false; + // Emit timeout event + self.emit("timeout", {err: 'connection to [' + self.socketOptions.host + ':' + self.socketOptions.port + '] timed out'}, self); + } +} + +var drainHandler = function(self) { + return function() { + } +} + +var errorHandler = function(self) { + return function(err) { + self.connection.destroy(); + // Set connected to false + self.connected = false; + // Emit error + self.emit("error", {err: 'failed to connect to [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self); + } +} + +var closeHandler = function(self) { + return function(hadError) { + // If we have an error during the connection phase + if(hadError && !self.connected) { + // Set disconnected + self.connected = false; + // Emit error + self.emit("error", {err: 'failed to connect to [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self); + } else { + // Set disconnected + self.connected = false; + // Emit close + self.emit("close", {err: 'connection closed to [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self); + } + } +} + +// Some basic defaults +Connection.DEFAULT_PORT = 27017; + + + + + + + diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_pool.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_pool.js new file mode 100644 index 0000000..3d9e7c5 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_pool.js @@ -0,0 +1,295 @@ +var utils = require('./connection_utils'), + inherits = require('util').inherits, + net = require('net'), + timers = require('timers'), + EventEmitter = require('events').EventEmitter, + inherits = require('util').inherits, + MongoReply = require("../responses/mongo_reply").MongoReply, + Connection = require("./connection").Connection; + +// Set processor, setImmediate if 0.10 otherwise nextTick +var processor = require('../utils').processor(); + +var ConnectionPool = exports.ConnectionPool = function(host, port, poolSize, bson, socketOptions) { + if(typeof host !== 'string') { + throw new Error("host must be specified [" + host + "]"); + } + + // Set up event emitter + EventEmitter.call(this); + + // Keep all options for the socket in a specific collection allowing the user to specify the + // Wished upon socket connection parameters + this.socketOptions = typeof socketOptions === 'object' ? socketOptions : {}; + this.socketOptions.host = host; + this.socketOptions.port = port; + this.socketOptions.domainSocket = false; + this.bson = bson; + // PoolSize is always + 1 for special reserved "measurment" socket (like ping, stats etc) + this.poolSize = poolSize; + this.minPoolSize = Math.floor(this.poolSize / 2) + 1; + + // Check if the host is a socket + if(host.match(/^\//)) { + this.socketOptions.domainSocket = true; + } else if(typeof port === 'string') { + try { + port = parseInt(port, 10); + } catch(err) { + new Error("port must be specified or valid integer[" + port + "]"); + } + } else if(typeof port !== 'number') { + throw new Error("port must be specified [" + port + "]"); + } + + // Set default settings for the socket options + utils.setIntegerParameter(this.socketOptions, 'timeout', 0); + // Delay before writing out the data to the server + utils.setBooleanParameter(this.socketOptions, 'noDelay', true); + // Delay before writing out the data to the server + utils.setIntegerParameter(this.socketOptions, 'keepAlive', 0); + // Set the encoding of the data read, default is binary == null + utils.setStringParameter(this.socketOptions, 'encoding', null); + // Allows you to set a throttling bufferSize if you need to stop overflows + utils.setIntegerParameter(this.socketOptions, 'bufferSize', 0); + + // Internal structures + this.openConnections = []; + // Assign connection id's + this.connectionId = 0; + + // Current index for selection of pool connection + this.currentConnectionIndex = 0; + // The pool state + this._poolState = 'disconnected'; + // timeout control + this._timeout = false; + // Time to wait between connections for the pool + this._timeToWait = 10; +} + +inherits(ConnectionPool, EventEmitter); + +ConnectionPool.prototype.setMaxBsonSize = function(maxBsonSize) { + if(maxBsonSize == null){ + maxBsonSize = Connection.DEFAULT_MAX_BSON_SIZE; + } + + for(var i = 0; i < this.openConnections.length; i++) { + this.openConnections[i].maxBsonSize = maxBsonSize; + this.openConnections[i].maxBsonSettings.maxBsonSize = maxBsonSize; + } +} + +ConnectionPool.prototype.setMaxMessageSizeBytes = function(maxMessageSizeBytes) { + if(maxMessageSizeBytes == null){ + maxMessageSizeBytes = Connection.DEFAULT_MAX_MESSAGE_SIZE; + } + + for(var i = 0; i < this.openConnections.length; i++) { + this.openConnections[i].maxMessageSizeBytes = maxMessageSizeBytes; + this.openConnections[i].maxBsonSettings.maxMessageSizeBytes = maxMessageSizeBytes; + } +} + +// Start a function +var _connect = function(_self) { + // return new function() { + // Create a new connection instance + var connection = new Connection(_self.connectionId++, _self.socketOptions); + // Set logger on pool + connection.logger = _self.logger; + // Connect handler + connection.on("connect", function(err, connection) { + // Add connection to list of open connections + _self.openConnections.push(connection); + // If the number of open connections is equal to the poolSize signal ready pool + if(_self.openConnections.length === _self.poolSize && _self._poolState !== 'disconnected') { + // Set connected + _self._poolState = 'connected'; + // Emit pool ready + _self.emit("poolReady"); + } else if(_self.openConnections.length < _self.poolSize) { + // Wait a little bit of time to let the close event happen if the server closes the connection + // so we don't leave hanging connections around + if(typeof _self._timeToWait == 'number') { + setTimeout(function() { + // If we are still connecting (no close events fired in between start another connection) + if(_self._poolState == 'connecting') { + _connect(_self); + } + }, _self._timeToWait); + } else { + processor(function() { + // If we are still connecting (no close events fired in between start another connection) + if(_self._poolState == 'connecting') { + _connect(_self); + } + }); + } + } + }); + + var numberOfErrors = 0 + + // Error handler + connection.on("error", function(err, connection, error_options) { + numberOfErrors++; + // If we are already disconnected ignore the event + if(_self._poolState != 'disconnected' && _self.listeners("error").length > 0) { + _self.emit("error", err, connection, error_options); + } + + // Close the connection + connection.close(); + // Set pool as disconnected + _self._poolState = 'disconnected'; + // Stop the pool + _self.stop(); + }); + + // Close handler + connection.on("close", function() { + // If we are already disconnected ignore the event + if(_self._poolState !== 'disconnected' && _self.listeners("close").length > 0) { + _self.emit("close"); + } + + // Set disconnected + _self._poolState = 'disconnected'; + // Stop + _self.stop(); + }); + + // Timeout handler + connection.on("timeout", function(err, connection) { + // If we are already disconnected ignore the event + if(_self._poolState !== 'disconnected' && _self.listeners("timeout").length > 0) { + _self.emit("timeout", err); + } + + // Close the connection + connection.close(); + // Set disconnected + _self._poolState = 'disconnected'; + _self.stop(); + }); + + // Parse error, needs a complete shutdown of the pool + connection.on("parseError", function() { + // If we are already disconnected ignore the event + if(_self._poolState !== 'disconnected' && _self.listeners("parseError").length > 0) { + _self.emit("parseError", new Error("parseError occured")); + } + + // Set disconnected + _self._poolState = 'disconnected'; + _self.stop(); + }); + + connection.on("message", function(message) { + _self.emit("message", message); + }); + + // Start connection in the next tick + connection.start(); + // }(); +} + + +// Start method, will throw error if no listeners are available +// Pass in an instance of the listener that contains the api for +// finding callbacks for a given message etc. +ConnectionPool.prototype.start = function() { + var markerDate = new Date().getTime(); + var self = this; + + if(this.listeners("poolReady").length == 0) { + throw "pool must have at least one listener ready that responds to the [poolReady] event"; + } + + // Set pool state to connecting + this._poolState = 'connecting'; + this._timeout = false; + + _connect(self); +} + +// Restart a connection pool (on a close the pool might be in a wrong state) +ConnectionPool.prototype.restart = function() { + // Close all connections + this.stop(false); + // Now restart the pool + this.start(); +} + +// Stop the connections in the pool +ConnectionPool.prototype.stop = function(removeListeners) { + removeListeners = removeListeners == null ? true : removeListeners; + // Set disconnected + this._poolState = 'disconnected'; + + // Clear all listeners if specified + if(removeListeners) { + this.removeAllEventListeners(); + } + + // Close all connections + for(var i = 0; i < this.openConnections.length; i++) { + this.openConnections[i].close(); + } + + // Clean up + this.openConnections = []; +} + +// Check the status of the connection +ConnectionPool.prototype.isConnected = function() { + // return this._poolState === 'connected'; + return this.openConnections.length > 0 && this.openConnections[0].isConnected(); +} + +// Checkout a connection from the pool for usage, or grab a specific pool instance +ConnectionPool.prototype.checkoutConnection = function(id) { + var index = (this.currentConnectionIndex++ % (this.openConnections.length)); + var connection = this.openConnections[index]; + return connection; +} + +ConnectionPool.prototype.getAllConnections = function() { + return this.openConnections; +} + +// Remove all non-needed event listeners +ConnectionPool.prototype.removeAllEventListeners = function() { + this.removeAllListeners("close"); + this.removeAllListeners("error"); + this.removeAllListeners("timeout"); + this.removeAllListeners("connect"); + this.removeAllListeners("end"); + this.removeAllListeners("parseError"); + this.removeAllListeners("message"); + this.removeAllListeners("poolReady"); +} + + + + + + + + + + + + + + + + + + + + + + diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_utils.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_utils.js new file mode 100644 index 0000000..5910924 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_utils.js @@ -0,0 +1,23 @@ +exports.setIntegerParameter = function(object, field, defaultValue) { + if(object[field] == null) { + object[field] = defaultValue; + } else if(typeof object[field] !== "number" && object[field] !== parseInt(object[field], 10)) { + throw "object field [" + field + "] must be a numeric integer value, attempted to set to [" + object[field] + "] type of [" + typeof object[field] + "]"; + } +} + +exports.setBooleanParameter = function(object, field, defaultValue) { + if(object[field] == null) { + object[field] = defaultValue; + } else if(typeof object[field] !== "boolean") { + throw "object field [" + field + "] must be a boolean value, attempted to set to [" + object[field] + "] type of [" + typeof object[field] + "]"; + } +} + +exports.setStringParameter = function(object, field, defaultValue) { + if(object[field] == null) { + object[field] = defaultValue; + } else if(typeof object[field] !== "string") { + throw "object field [" + field + "] must be a string value, attempted to set to [" + object[field] + "] type of [" + typeof object[field] + "]"; + } +} \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/mongos.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/mongos.js new file mode 100644 index 0000000..47075bd --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/mongos.js @@ -0,0 +1,524 @@ +var ReadPreference = require('./read_preference').ReadPreference + , Base = require('./base').Base + , Server = require('./server').Server + , format = require('util').format + , timers = require('timers') + , inherits = require('util').inherits; + +// Set processor, setImmediate if 0.10 otherwise nextTick +var processor = require('../utils').processor(); + +/** + * Mongos constructor provides a connection to a mongos proxy including failover to additional servers + * + * Options + * - **socketOptions** {Object, default:null}, an object containing socket options to use (noDelay:(boolean), keepAlive:(number), connectTimeoutMS:(number), socketTimeoutMS:(number)) + * - **ha** {Boolean, default:true}, turn on high availability, attempts to reconnect to down proxies + * - **haInterval** {Number, default:2000}, time between each replicaset status check. + * + * @class Represents a Mongos connection with failover to backup proxies + * @param {Array} list of mongos server objects + * @param {Object} [options] additional options for the mongos connection + */ +var Mongos = function Mongos(servers, options) { + // Set up basic + if(!(this instanceof Mongos)) + return new Mongos(servers, options); + + // Set up event emitter + Base.call(this); + + // Throw error on wrong setup + if(servers == null || !Array.isArray(servers) || servers.length == 0) + throw new Error("At least one mongos proxy must be in the array"); + + // Ensure we have at least an empty options object + this.options = options == null ? {} : options; + // Set default connection pool options + this.socketOptions = this.options.socketOptions != null ? this.options.socketOptions : {}; + // Enabled ha + this.haEnabled = this.options['ha'] == null ? true : this.options['ha']; + this._haInProgress = false; + // How often are we checking for new servers in the replicaset + this.mongosStatusCheckInterval = this.options['haInterval'] == null ? 1000 : this.options['haInterval']; + // Save all the server connections + this.servers = servers; + // Servers we need to attempt reconnect with + this.downServers = {}; + // Servers that are up + this.upServers = {}; + // Up servers by ping time + this.upServersByUpTime = {}; + // Emit open setup + this.emitOpen = this.options.emitOpen || true; + // Just contains the current lowest ping time and server + this.lowestPingTimeServer = null; + this.lowestPingTime = 0; + // Connection timeout + this._connectTimeoutMS = this.socketOptions.connectTimeoutMS + ? this.socketOptions.connectTimeoutMS + : 1000; + + // Add options to servers + for(var i = 0; i < this.servers.length; i++) { + var server = this.servers[i]; + server._callBackStore = this._callBackStore; + server.auto_reconnect = false; + // Default empty socket options object + var socketOptions = {host: server.host, port: server.port}; + // If a socket option object exists clone it + if(this.socketOptions != null) { + var keys = Object.keys(this.socketOptions); + for(var k = 0; k < keys.length;k++) socketOptions[keys[i]] = this.socketOptions[keys[i]]; + } + + // Set socket options + server.socketOptions = socketOptions; + } +} + +/** + * @ignore + */ +inherits(Mongos, Base); + +/** + * @ignore + */ +Mongos.prototype.isMongos = function() { + return true; +} + +/** + * @ignore + */ +Mongos.prototype.connect = function(db, options, callback) { + if('function' === typeof options) callback = options, options = {}; + if(options == null) options = {}; + if(!('function' === typeof callback)) callback = null; + var self = this; + + // Keep reference to parent + this.db = db; + // Set server state to connecting + this._serverState = 'connecting'; + // Number of total servers that need to initialized (known servers) + this._numberOfServersLeftToInitialize = this.servers.length; + // Connect handler + var connectHandler = function(_server) { + return function(err, result) { + self._numberOfServersLeftToInitialize = self._numberOfServersLeftToInitialize - 1; + + // Add the server to the list of servers that are up + if(!err) { + self.upServers[format("%s:%s", _server.host, _server.port)] = _server; + } + + // We are done connecting + if(self._numberOfServersLeftToInitialize == 0) { + // Start ha function if it exists + if(self.haEnabled) { + // Setup the ha process + if(self._replicasetTimeoutId != null) clearInterval(self._replicasetTimeoutId); + self._replicasetTimeoutId = setInterval(self.mongosCheckFunction, self.mongosStatusCheckInterval); + } + + // Set the mongos to connected + self._serverState = "connected"; + + // Emit the open event + if(self.emitOpen) + self._emitAcrossAllDbInstances(self, null, "open", null, null, null); + + self._emitAcrossAllDbInstances(self, null, "fullsetup", null, null, null); + // Callback + callback(null, self.db); + } + } + }; + + // Error handler + var errorOrCloseHandler = function(_server) { + return function(err, result) { + // Execute all the callbacks with errors + self.__executeAllCallbacksWithError(err); + // Check if we have the server + var found = false; + + // Get the server name + var server_name = format("%s:%s", _server.host, _server.port); + // Add the downed server + self.downServers[server_name] = _server; + // Remove the current server from the list + delete self.upServers[server_name]; + + // Emit close across all the attached db instances + if(Object.keys(self.upServers).length == 0) { + self._emitAcrossAllDbInstances(self, null, "close", new Error("mongos disconnected, no valid proxies contactable over tcp"), null, null); + } + } + } + + // Mongo function + this.mongosCheckFunction = function() { + // Set as not waiting for check event + self._haInProgress = true; + + // Servers down + var numberOfServersLeft = Object.keys(self.downServers).length; + + // Check downed servers + if(numberOfServersLeft > 0) { + for(var name in self.downServers) { + // Pop a downed server + var downServer = self.downServers[name]; + // Set up the connection options for a Mongos + var options = { + auto_reconnect: false, + returnIsMasterResults: true, + slaveOk: true, + poolSize: downServer.poolSize, + socketOptions: { + connectTimeoutMS: self._connectTimeoutMS, + socketTimeoutMS: self._socketTimeoutMS + } + } + + // Create a new server object + var newServer = new Server(downServer.host, downServer.port, options); + // Setup the connection function + var connectFunction = function(_db, _server, _options, _callback) { + return function() { + // Attempt to connect + _server.connect(_db, _options, function(err, result) { + numberOfServersLeft = numberOfServersLeft - 1; + + if(err) { + return _callback(err, _server); + } else { + // Set the new server settings + _server._callBackStore = self._callBackStore; + + // Add server event handlers + _server.on("close", errorOrCloseHandler(_server)); + _server.on("timeout", errorOrCloseHandler(_server)); + _server.on("error", errorOrCloseHandler(_server)); + + // Get a read connection + var _connection = _server.checkoutReader(); + // Get the start time + var startTime = new Date().getTime(); + + // Execute ping command to mark each server with the expected times + self.db.command({ping:1} + , {failFast:true, connection:_connection}, function(err, result) { + // Get the start time + var endTime = new Date().getTime(); + // Mark the server with the ping time + _server.runtimeStats['pingMs'] = endTime - startTime; + // Execute any waiting reads + self._commandsStore.execute_writes(); + self._commandsStore.execute_queries(); + // Callback + return _callback(null, _server); + }); + } + }); + } + } + + // Attempt to connect to the database + connectFunction(self.db, newServer, options, function(err, _server) { + // If we have an error + if(err) { + self.downServers[format("%s:%s", _server.host, _server.port)] = _server; + } + + // Connection function + var connectionFunction = function(_auth, _connection, _callback) { + var pending = _auth.length(); + + for(var j = 0; j < pending; j++) { + // Get the auth object + var _auth = _auth.get(j); + // Unpack the parameter + var username = _auth.username; + var password = _auth.password; + var options = { + authMechanism: _auth.authMechanism + , authSource: _auth.authdb + , connection: _connection + }; + + // If we have changed the service name + if(_auth.gssapiServiceName) + options.gssapiServiceName = _auth.gssapiServiceName; + + // Hold any error + var _error = null; + // Authenticate against the credentials + self.db.authenticate(username, password, options, function(err, result) { + _error = err != null ? err : _error; + // Adjust the pending authentication + pending = pending - 1; + // Finished up + if(pending == 0) _callback(_error ? _error : null, _error ? false : true); + }); + } + } + + // Run auths against the connections + if(self.auth.length() > 0) { + var connections = _server.allRawConnections(); + var pendingAuthConn = connections.length; + + // No connections we are done + if(connections.length == 0) { + // Set ha done + if(numberOfServersLeft == 0) { + self._haInProgress = false; + } + } + + // Final error object + var finalError = null; + // Go over all the connections + for(var j = 0; j < connections.length; j++) { + + // Execute against all the connections + connectionFunction(self.auth, connections[j], function(err, result) { + // Pending authentication + pendingAuthConn = pendingAuthConn - 1 ; + + // Save error if any + finalError = err ? err : finalError; + + // If we are done let's finish up + if(pendingAuthConn == 0) { + // Set ha done + if(numberOfServersLeft == 0) { + self._haInProgress = false; + } + + if(!err) { + add_server(self, _server); + } + + // Execute any waiting reads + self._commandsStore.execute_writes(); + self._commandsStore.execute_queries(); + } + }); + } + } else { + if(!err) { + add_server(self, _server); + } + + // Set ha done + if(numberOfServersLeft == 0) { + self._haInProgress = false; + // Execute any waiting reads + self._commandsStore.execute_writes(); + self._commandsStore.execute_queries(); + } + } + })(); + } + } else { + self._haInProgress = false; + } + } + + // Connect all the server instances + for(var i = 0; i < this.servers.length; i++) { + // Get the connection + var server = this.servers[i]; + server.mongosInstance = this; + // Add server event handlers + server.on("close", errorOrCloseHandler(server)); + server.on("timeout", errorOrCloseHandler(server)); + server.on("error", errorOrCloseHandler(server)); + + // Configuration + var options = { + slaveOk: true, + poolSize: server.poolSize, + socketOptions: { connectTimeoutMS: self._connectTimeoutMS }, + returnIsMasterResults: true + } + + // Connect the instance + server.connect(self.db, options, connectHandler(server)); + } +} + +/** + * @ignore + * Add a server to the list of up servers and sort them by ping time + */ +var add_server = function(self, _server) { + var server_key = format("%s:%s", _server.host, _server.port); + // Push to list of valid server + self.upServers[server_key] = _server; + // Remove the server from the list of downed servers + delete self.downServers[server_key]; + + // Sort the keys by ping time + var keys = Object.keys(self.upServers); + var _upServersSorted = {}; + var _upServers = [] + + // Get all the servers + for(var name in self.upServers) { + _upServers.push(self.upServers[name]); + } + + // Sort all the server + _upServers.sort(function(a, b) { + return a.runtimeStats['pingMs'] > b.runtimeStats['pingMs']; + }); + + // Rebuild the upServer + for(var i = 0; i < _upServers.length; i++) { + _upServersSorted[format("%s:%s", _upServers[i].host, _upServers[i].port)] = _upServers[i]; + } + + // Set the up servers + self.upServers = _upServersSorted; +} + +/** + * @ignore + * Just return the currently picked active connection + */ +Mongos.prototype.allServerInstances = function() { + return this.servers; +} + +/** + * Always ourselves + * @ignore + */ +Mongos.prototype.setReadPreference = function() {} + +/** + * @ignore + */ +Mongos.prototype.allRawConnections = function() { + // Neeed to build a complete list of all raw connections, start with master server + var allConnections = []; + // Get all connected connections + for(var name in this.upServers) { + allConnections = allConnections.concat(this.upServers[name].allRawConnections()); + } + // Return all the conections + return allConnections; +} + +/** + * @ignore + */ +Mongos.prototype.isConnected = function() { + return Object.keys(this.upServers).length > 0; +} + +/** + * @ignore + */ +Mongos.prototype.isAutoReconnect = function() { + return true; +} + +/** + * @ignore + */ +Mongos.prototype.canWrite = Mongos.prototype.isConnected; + +/** + * @ignore + */ +Mongos.prototype.canRead = Mongos.prototype.isConnected; + +/** + * @ignore + */ +Mongos.prototype.isDestroyed = function() { + return this._serverState == 'destroyed'; +} + +/** + * @ignore + */ +Mongos.prototype.checkoutWriter = function() { + // Checkout a writer + var keys = Object.keys(this.upServers); + // console.dir("============================ checkoutWriter :: " + keys.length) + if(keys.length == 0) return null; + // console.log("=============== checkoutWriter :: " + this.upServers[keys[0]].checkoutWriter().socketOptions.port) + return this.upServers[keys[0]].checkoutWriter(); +} + +/** + * @ignore + */ +Mongos.prototype.checkoutReader = function(read) { + // console.log("=============== checkoutReader :: read :: " + read); + // If read is set to null default to primary + read = read || 'primary' + // If we have a read preference object unpack it + if(read != null && typeof read == 'object' && read['_type'] == 'ReadPreference') { + // Validate if the object is using a valid mode + if(!read.isValid()) throw new Error("Illegal readPreference mode specified, " + read.mode); + } else if(!ReadPreference.isValid(read)) { + throw new Error("Illegal readPreference mode specified, " + read); + } + + // Checkout a writer + var keys = Object.keys(this.upServers); + if(keys.length == 0) return null; + // console.log("=============== checkoutReader :: " + this.upServers[keys[0]].checkoutWriter().socketOptions.port) + // console.dir(this._commandsStore.commands) + return this.upServers[keys[0]].checkoutWriter(); +} + +/** + * @ignore + */ +Mongos.prototype.close = function(callback) { + var self = this; + // Set server status as disconnected + this._serverState = 'destroyed'; + // Number of connections to close + var numberOfConnectionsToClose = self.servers.length; + // If we have a ha process running kill it + if(self._replicasetTimeoutId != null) clearInterval(self._replicasetTimeoutId); + self._replicasetTimeoutId = null; + + // Emit close event + processor(function() { + self._emitAcrossAllDbInstances(self, null, "close", null, null, true) + }); + + // Close all the up servers + for(var name in this.upServers) { + this.upServers[name].close(function(err, result) { + numberOfConnectionsToClose = numberOfConnectionsToClose - 1; + + // Callback if we have one defined + if(numberOfConnectionsToClose == 0 && typeof callback == 'function') { + callback(null); + } + }); + } +} + +/** + * @ignore + * Return the used state + */ +Mongos.prototype._isUsed = function() { + return this._used; +} + +exports.Mongos = Mongos; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/read_preference.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/read_preference.js new file mode 100644 index 0000000..6845171 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/read_preference.js @@ -0,0 +1,67 @@ +/** + * A class representation of the Read Preference. + * + * Read Preferences + * - **ReadPreference.PRIMARY**, Read from primary only. All operations produce an error (throw an exception where applicable) if primary is unavailable. Cannot be combined with tags (This is the default.). + * - **ReadPreference.PRIMARY_PREFERRED**, Read from primary if available, otherwise a secondary. + * - **ReadPreference.SECONDARY**, Read from secondary if available, otherwise error. + * - **ReadPreference.SECONDARY_PREFERRED**, Read from a secondary if available, otherwise read from the primary. + * - **ReadPreference.NEAREST**, All modes read from among the nearest candidates, but unlike other modes, NEAREST will include both the primary and all secondaries in the random selection. + * + * @class Represents a Read Preference. + * @param {String} the read preference type + * @param {Object} tags + * @return {ReadPreference} + */ +var ReadPreference = function(mode, tags) { + if(!(this instanceof ReadPreference)) + return new ReadPreference(mode, tags); + this._type = 'ReadPreference'; + this.mode = mode; + this.tags = tags; +} + +/** + * @ignore + */ +ReadPreference.isValid = function(_mode) { + return (_mode == ReadPreference.PRIMARY || _mode == ReadPreference.PRIMARY_PREFERRED + || _mode == ReadPreference.SECONDARY || _mode == ReadPreference.SECONDARY_PREFERRED + || _mode == ReadPreference.NEAREST + || _mode == true || _mode == false); +} + +/** + * @ignore + */ +ReadPreference.prototype.isValid = function(mode) { + var _mode = typeof mode == 'string' ? mode : this.mode; + return ReadPreference.isValid(_mode); +} + +/** + * @ignore + */ +ReadPreference.prototype.toObject = function() { + var object = {mode:this.mode}; + + if(this.tags != null) { + object['tags'] = this.tags; + } + + return object; +} + +/** + * @ignore + */ +ReadPreference.PRIMARY = 'primary'; +ReadPreference.PRIMARY_PREFERRED = 'primaryPreferred'; +ReadPreference.SECONDARY = 'secondary'; +ReadPreference.SECONDARY_PREFERRED = 'secondaryPreferred'; +ReadPreference.NEAREST = 'nearest' + +/** + * @ignore + */ +exports.ReadPreference = ReadPreference; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/ha.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/ha.js new file mode 100644 index 0000000..b89e7ba --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/ha.js @@ -0,0 +1,407 @@ +var DbCommand = require('../../commands/db_command').DbCommand + , format = require('util').format; + +var HighAvailabilityProcess = function(replset, options) { + this.replset = replset; + this.options = options; + this.server = null; + this.state = HighAvailabilityProcess.INIT; + this.selectedIndex = 0; +} + +HighAvailabilityProcess.INIT = 'init'; +HighAvailabilityProcess.RUNNING = 'running'; +HighAvailabilityProcess.STOPPED = 'stopped'; + +HighAvailabilityProcess.prototype.start = function() { + var self = this; + if(this.replset._state + && Object.keys(this.replset._state.addresses).length == 0) { + if(this.server) this.server.close(); + this.state = HighAvailabilityProcess.STOPPED; + return; + } + + if(this.server) this.server.close(); + // Start the running + this._haProcessInProcess = false; + this.state = HighAvailabilityProcess.RUNNING; + + // Get all possible reader servers + var candidate_servers = this.replset._state.getAllReadServers(); + if(candidate_servers.length == 0) { + return; + } + + // Select a candidate server for the connection + var server = candidate_servers[this.selectedIndex % candidate_servers.length]; + this.selectedIndex = this.selectedIndex + 1; + + // Unpack connection options + var connectTimeoutMS = self.options.connectTimeoutMS || 10000; + var socketTimeoutMS = self.options.socketTimeoutMS || 30000; + + // Just ensure we don't have a full cycle dependency + var Db = require('../../db').Db + var Server = require('../server').Server; + + // Set up a new server instance + var newServer = new Server(server.host, server.port, { + auto_reconnect: false + , returnIsMasterResults: true + , poolSize: 1 + , socketOptions: { + connectTimeoutMS: connectTimeoutMS, + socketTimeoutMS: socketTimeoutMS, + keepAlive: 100 + } + , ssl: this.options.ssl + , sslValidate: this.options.sslValidate + , sslCA: this.options.sslCA + , sslCert: this.options.sslCert + , sslKey: this.options.sslKey + , sslPass: this.options.sslPass + }); + + // Create new dummy db for app + self.db = new Db('local', newServer, {w:1}); + + // Set up the event listeners + newServer.once("error", _handle(this, newServer)); + newServer.once("close", _handle(this, newServer)); + newServer.once("timeout", _handle(this, newServer)); + newServer.name = format("%s:%s", server.host, server.port); + + // Let's attempt a connection over here + newServer.connect(self.db, function(err, result, _server) { + if(self.state == HighAvailabilityProcess.STOPPED) { + _server.close(); + } + + if(err) { + // Close the server + _server.close(); + // Check if we can even do HA (is there anything running) + if(Object.keys(self.replset._state.addresses).length == 0) { + return; + } + + // Let's boot the ha timeout settings + setTimeout(function() { + self.start(); + }, self.options.haInterval); + } else { + self.server = _server; + // Let's boot the ha timeout settings + setTimeout(_timeoutHandle(self), self.options.haInterval); + } + }); +} + +HighAvailabilityProcess.prototype.stop = function() { + this.state = HighAvailabilityProcess.STOPPED; + if(this.server) this.server.close(); +} + +var _timeoutHandle = function(self) { + return function() { + if(self.state == HighAvailabilityProcess.STOPPED) { + // Stop all server instances + for(var name in self.replset._state.addresses) { + self.replset._state.addresses[name].close(); + delete self.replset._state.addresses[name]; + } + + // Finished pinging + return; + } + + // If the server is connected + if(self.server.isConnected() && !self._haProcessInProcess) { + // Start HA process + self._haProcessInProcess = true; + // Execute is master command + self.db._executeQueryCommand(DbCommand.createIsMasterCommand(self.db), + {failFast:true, connection: self.server.checkoutReader()} + , function(err, res) { + if(err) { + self.server.close(); + return setTimeout(_timeoutHandle(self), self.options.haInterval); + } + + // Master document + var master = res.documents[0]; + var hosts = master.hosts || []; + var reconnect_servers = []; + var state = self.replset._state; + + // We are in recovery mode, let's remove the current server + if(!master.ismaster + && !master.secondary + && state.addresses[master.me]) { + self.server.close(); + state.addresses[master.me].close(); + delete state.secondaries[master.me]; + return setTimeout(_timeoutHandle(self), self.options.haInterval); + } + + // For all the hosts let's check that we have connections + for(var i = 0; i < hosts.length; i++) { + var host = hosts[i]; + // Check if we need to reconnect to a server + if(state.addresses[host] == null) { + reconnect_servers.push(host); + } else if(state.addresses[host] && !state.addresses[host].isConnected()) { + state.addresses[host].close(); + delete state.secondaries[host]; + reconnect_servers.push(host); + } + + if((master.primary && state.master == null) + || (master.primary && state.master.name != master.primary)) { + + // Locate the primary and set it + if(state.addresses[master.primary]) { + if(state.master) state.master.close(); + delete state.secondaries[master.primary]; + state.master = state.addresses[master.primary]; + } + + // Set up the changes + if(state.master != null && state.master.isMasterDoc != null) { + state.master.isMasterDoc.ismaster = true; + state.master.isMasterDoc.secondary = false; + } else if(state.master != null) { + state.master.isMasterDoc = master; + state.master.isMasterDoc.ismaster = true; + state.master.isMasterDoc.secondary = false; + } + + // Execute any waiting commands (queries or writes) + self.replset._commandsStore.execute_queries(); + self.replset._commandsStore.execute_writes(); + } + } + + // Let's reconnect to any server needed + if(reconnect_servers.length > 0) { + _reconnect_servers(self, reconnect_servers); + } else { + self._haProcessInProcess = false + return setTimeout(_timeoutHandle(self), self.options.haInterval); + } + }); + } else if(!self.server.isConnected()) { + setTimeout(function() { + return self.start(); + }, self.options.haInterval); + } else { + setTimeout(_timeoutHandle(self), self.options.haInterval); + } + } +} + +var _reconnect_servers = function(self, reconnect_servers) { + if(reconnect_servers.length == 0) { + self._haProcessInProcess = false + return setTimeout(_timeoutHandle(self), self.options.haInterval); + } + + // Unpack connection options + var connectTimeoutMS = self.options.connectTimeoutMS || 10000; + var socketTimeoutMS = self.options.socketTimeoutMS || 30000; + + // Server class + var Db = require('../../db').Db + var Server = require('../server').Server; + // Get the host + var host = reconnect_servers.shift(); + // Split it up + var _host = host.split(":")[0]; + var _port = parseInt(host.split(":")[1], 10); + + // Set up a new server instance + var newServer = new Server(_host, _port, { + auto_reconnect: false + , returnIsMasterResults: true + , poolSize: self.options.poolSize + , socketOptions: { + connectTimeoutMS: connectTimeoutMS, + socketTimeoutMS: socketTimeoutMS + } + , ssl: self.options.ssl + , sslValidate: self.options.sslValidate + , sslCA: self.options.sslCA + , sslCert: self.options.sslCert + , sslKey: self.options.sslKey + , sslPass: self.options.sslPass + }); + + // Create new dummy db for app + var db = new Db('local', newServer, {w:1}); + var state = self.replset._state; + + // Set up the event listeners + newServer.once("error", _repl_set_handler("error", self.replset, newServer)); + newServer.once("close", _repl_set_handler("close", self.replset, newServer)); + newServer.once("timeout", _repl_set_handler("timeout", self.replset, newServer)); + + // Set shared state + newServer.name = host; + newServer._callBackStore = self.replset._callBackStore; + newServer.replicasetInstance = self.replset; + newServer.enableRecordQueryStats(self.replset.recordQueryStats); + + // Let's attempt a connection over here + newServer.connect(db, function(err, result, _server) { + if(self.state == HighAvailabilityProcess.STOPPED) { + _server.close(); + } + + // If we connected let's check what kind of server we have + if(!err) { + _apply_auths(self, db, _server, function(err, result) { + if(err) { + _server.close(); + // Process the next server + return setTimeout(function() { + _reconnect_servers(self, reconnect_servers); + }, self.options.haInterval); + } + var doc = _server.isMasterDoc; + // Fire error on any unknown callbacks for this server + self.replset.__executeAllServerSpecificErrorCallbacks(_server.socketOptions.host, _server.socketOptions.port, err); + + if(doc.ismaster) { + if(state.secondaries[doc.me]) { + delete state.secondaries[doc.me]; + } + + // Override any server in list of addresses + state.addresses[doc.me] = _server; + // Set server as master + state.master = _server; + // Execute any waiting writes + self.replset._commandsStore.execute_writes(); + } else if(doc.secondary) { + state.secondaries[doc.me] = _server; + // Override any server in list of addresses + state.addresses[doc.me] = _server; + // Execute any waiting reads + self.replset._commandsStore.execute_queries(); + } else { + _server.close(); + } + + // Set any tags on the instance server + _server.name = doc.me; + _server.tags = doc.tags; + // Process the next server + setTimeout(function() { + _reconnect_servers(self, reconnect_servers); + }, self.options.haInterval); + }); + } else { + _server.close(); + self.replset.__executeAllServerSpecificErrorCallbacks(_server.socketOptions.host, _server.socketOptions.port, err); + + setTimeout(function() { + _reconnect_servers(self, reconnect_servers); + }, self.options.haInterval); + } + }); +} + +var _apply_auths = function(self, _db, _server, _callback) { + if(self.replset.auth.length() == 0) return _callback(null); + // Apply any authentication needed + if(self.replset.auth.length() > 0) { + var pending = self.replset.auth.length(); + var connections = _server.allRawConnections(); + var pendingAuthConn = connections.length; + + // Connection function + var connectionFunction = function(_auth, _connection, __callback) { + var pending = _auth.length(); + + for(var j = 0; j < pending; j++) { + // Get the auth object + var _auth = _auth.get(j); + // Unpack the parameter + var username = _auth.username; + var password = _auth.password; + var options = { + authMechanism: _auth.authMechanism + , authSource: _auth.authdb + , connection: _connection + }; + + // If we have changed the service name + if(_auth.gssapiServiceName) + options.gssapiServiceName = _auth.gssapiServiceName; + + // Hold any error + var _error = null; + + // Authenticate against the credentials + _db.authenticate(username, password, options, function(err, result) { + _error = err != null ? err : _error; + // Adjust the pending authentication + pending = pending - 1; + // Finished up + if(pending == 0) __callback(_error ? _error : null, _error ? false : true); + }); + } + } + + // Final error object + var finalError = null; + // Iterate over all the connections + for(var i = 0; i < connections.length; i++) { + connectionFunction(self.replset.auth, connections[i], function(err, result) { + // Pending authentication + pendingAuthConn = pendingAuthConn - 1 ; + + // Save error if any + finalError = err ? err : finalError; + + // If we are done let's finish up + if(pendingAuthConn == 0) { + _callback(null); + } + }); + } + } +} + +var _handle = function(self, server) { + return function(err) { + server.close(); + } +} + +var _repl_set_handler = function(event, self, server) { + var ReplSet = require('./repl_set').ReplSet; + + return function(err, doc) { + server.close(); + + // The event happened to a primary + // Remove it from play + if(self._state.isPrimary(server)) { + self._state.master == null; + self._serverState = ReplSet.REPLSET_READ_ONLY; + } else if(self._state.isSecondary(server)) { + delete self._state.secondaries[server.name]; + } + + // Unpack variables + var host = server.socketOptions.host; + var port = server.socketOptions.port; + + // Fire error on any unknown callbacks + self.__executeAllServerSpecificErrorCallbacks(host, port, err); + } +} + +exports.HighAvailabilityProcess = HighAvailabilityProcess; diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/options.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/options.js new file mode 100644 index 0000000..a5658e3 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/options.js @@ -0,0 +1,126 @@ +var PingStrategy = require('./strategies/ping_strategy').PingStrategy + , StatisticsStrategy = require('./strategies/statistics_strategy').StatisticsStrategy + , ReadPreference = require('../read_preference').ReadPreference; + +var Options = function(options) { + options = options || {}; + this._options = options; + this.ha = options.ha || true; + this.haInterval = options.haInterval || 2000; + this.reconnectWait = options.reconnectWait || 1000; + this.retries = options.retries || 30; + this.rs_name = options.rs_name; + this.socketOptions = options.socketOptions || {}; + this.readPreference = options.readPreference; + this.readSecondary = options.read_secondary; + this.poolSize = options.poolSize == null ? 5 : options.poolSize; + this.strategy = options.strategy || 'ping'; + this.secondaryAcceptableLatencyMS = options.secondaryAcceptableLatencyMS || 15; + this.connectArbiter = options.connectArbiter || false; + this.connectWithNoPrimary = options.connectWithNoPrimary || false; + this.logger = options.logger; + this.ssl = options.ssl || false; + this.sslValidate = options.sslValidate || false; + this.sslCA = options.sslCA; + this.sslCert = options.sslCert; + this.sslKey = options.sslKey; + this.sslPass = options.sslPass; + this.emitOpen = options.emitOpen || true; +} + +Options.prototype.init = function() { + if(this.sslValidate && (!Array.isArray(this.sslCA) || this.sslCA.length == 0)) { + throw new Error("The driver expects an Array of CA certificates in the sslCA parameter when enabling sslValidate"); + } + + // Make sure strategy is one of the two allowed + if(this.strategy != null && (this.strategy != 'ping' && this.strategy != 'statistical' && this.strategy != 'none')) + throw new Error("Only ping or statistical strategies allowed"); + + if(this.strategy == null) this.strategy = 'ping'; + + // Set logger if strategy exists + if(this.strategyInstance) this.strategyInstance.logger = this.logger; + + // Unpack read Preference + var readPreference = this.readPreference; + // Validate correctness of Read preferences + if(readPreference != null) { + if(readPreference != ReadPreference.PRIMARY && readPreference != ReadPreference.PRIMARY_PREFERRED + && readPreference != ReadPreference.SECONDARY && readPreference != ReadPreference.SECONDARY_PREFERRED + && readPreference != ReadPreference.NEAREST && typeof readPreference != 'object' && readPreference['_type'] != 'ReadPreference') { + throw new Error("Illegal readPreference mode specified, " + readPreference); + } + + this.readPreference = readPreference; + } else { + this.readPreference = null; + } + + // Ensure read_secondary is set correctly + if(this.readSecondary != null) + this.readSecondary = this.readPreference == ReadPreference.PRIMARY + || this.readPreference == false + || this.readPreference == null ? false : true; + + // Ensure correct slave set + if(this.readSecondary) this.slaveOk = true; + + // Set up logger if any set + this.logger = this.logger != null + && (typeof this.logger.debug == 'function') + && (typeof this.logger.error == 'function') + && (typeof this.logger.debug == 'function') + ? this.logger : {error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}}; + + // Connection timeout + this.connectTimeoutMS = this.socketOptions.connectTimeoutMS + ? this.socketOptions.connectTimeoutMS + : 1000; + + // Socket connection timeout + this.socketTimeoutMS = this.socketOptions.socketTimeoutMS + ? this.socketOptions.socketTimeoutMS + : 30000; +} + +Options.prototype.decorateAndClean = function(servers, callBackStore) { + var self = this; + + // var de duplicate list + var uniqueServers = {}; + // De-duplicate any servers in the seed list + for(var i = 0; i < servers.length; i++) { + var server = servers[i]; + // If server does not exist set it + if(uniqueServers[server.host + ":" + server.port] == null) { + uniqueServers[server.host + ":" + server.port] = server; + } + } + + // Let's set the deduplicated list of servers + var finalServers = []; + // Add the servers + for(var key in uniqueServers) { + finalServers.push(uniqueServers[key]); + } + + finalServers.forEach(function(server) { + // Ensure no server has reconnect on + server.options.auto_reconnect = false; + // Set up ssl options + server.ssl = self.ssl; + server.sslValidate = self.sslValidate; + server.sslCA = self.sslCA; + server.sslCert = self.sslCert; + server.sslKey = self.sslKey; + server.sslPass = self.sslPass; + server.poolSize = self.poolSize; + // Set callback store + server._callBackStore = callBackStore; + }); + + return finalServers; +} + +exports.Options = Options; diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/repl_set.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/repl_set.js new file mode 100644 index 0000000..3254df9 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/repl_set.js @@ -0,0 +1,799 @@ +var ReadPreference = require('../read_preference').ReadPreference + , DbCommand = require('../../commands/db_command').DbCommand + , inherits = require('util').inherits + , format = require('util').format + , timers = require('timers') + , Server = require('../server').Server + , utils = require('../../utils') + , PingStrategy = require('./strategies/ping_strategy').PingStrategy + , StatisticsStrategy = require('./strategies/statistics_strategy').StatisticsStrategy + , Options = require('./options').Options + , ReplSetState = require('./repl_set_state').ReplSetState + , HighAvailabilityProcess = require('./ha').HighAvailabilityProcess + , Base = require('../base').Base; + +const STATE_STARTING_PHASE_1 = 0; +const STATE_PRIMARY = 1; +const STATE_SECONDARY = 2; +const STATE_RECOVERING = 3; +const STATE_FATAL_ERROR = 4; +const STATE_STARTING_PHASE_2 = 5; +const STATE_UNKNOWN = 6; +const STATE_ARBITER = 7; +const STATE_DOWN = 8; +const STATE_ROLLBACK = 9; + +// Set processor, setImmediate if 0.10 otherwise nextTick +var processor = require('../../utils').processor(); + +/** + * ReplSet constructor provides replicaset functionality + * + * Options + * - **ha** {Boolean, default:true}, turn on high availability. + * - **haInterval** {Number, default:2000}, time between each replicaset status check. + * - **reconnectWait** {Number, default:1000}, time to wait in miliseconds before attempting reconnect. + * - **retries** {Number, default:30}, number of times to attempt a replicaset reconnect. + * - **rs_name** {String}, the name of the replicaset to connect to. + * - **socketOptions** {Object, default:null}, an object containing socket options to use (noDelay:(boolean), keepAlive:(number), connectTimeoutMS:(number), socketTimeoutMS:(number)) + * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST). + * - **strategy** {String, default:'ping'}, selection strategy for reads choose between (ping, statistical and none, default is ping) + * - **secondaryAcceptableLatencyMS** {Number, default:15}, sets the range of servers to pick when using NEAREST (lowest ping ms + the latency fence, ex: range of 1 to (1 + 15) ms) + * - **connectWithNoPrimary** {Boolean, default:false}, sets if the driver should connect even if no primary is available + * - **connectArbiter** {Boolean, default:false}, sets if the driver should connect to arbiters or not. + * - **logger** {Object, default:null}, an object representing a logger that you want to use, needs to support functions debug, log, error **({error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}})**. + * - **poolSize** {Number, default:5}, number of connections in the connection pool for each server instance, set to 5 as default for legacy reasons. + * - **ssl** {Boolean, default:false}, use ssl connection (needs to have a mongod server with ssl support) + * - **sslValidate** {Boolean, default:false}, validate mongod server certificate against ca (needs to have a mongod server with ssl support, 2.4 or higher) + * - **sslCA** {Array, default:null}, Array of valid certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher) + * - **sslCert** {Buffer/String, default:null}, String or buffer containing the certificate we wish to present (needs to have a mongod server with ssl support, 2.4 or higher) + * - **sslKey** {Buffer/String, default:null}, String or buffer containing the certificate private key we wish to present (needs to have a mongod server with ssl support, 2.4 or higher) + * - **sslPass** {Buffer/String, default:null}, String or buffer containing the certificate password (needs to have a mongod server with ssl support, 2.4 or higher) + * + * @class Represents a + Replicaset Configuration + * @param {Array} list of server objects participating in the replicaset. + * @param {Object} [options] additional options for the replicaset connection. + */ +var ReplSet = exports.ReplSet = function(servers, options) { + // Set up basic + if(!(this instanceof ReplSet)) + return new ReplSet(servers, options); + + // Set up event emitter + Base.call(this); + + // Ensure we have a list of servers + if(!Array.isArray(servers)) throw Error("The parameter must be an array of servers and contain at least one server"); + // Ensure no Mongos's + for(var i = 0; i < servers.length; i++) { + if(!(servers[i] instanceof Server)) throw new Error("list of servers must be of type Server"); + } + + // Save the options + this.options = new Options(options); + // Ensure basic validation of options + this.options.init(); + + // Server state + this._serverState = ReplSet.REPLSET_DISCONNECTED; + // Add high availability process + this._haProcess = new HighAvailabilityProcess(this, this.options); + + + // Let's iterate over all the provided server objects and decorate them + this.servers = this.options.decorateAndClean(servers, this._callBackStore); + // Throw error if no seed servers + if(this.servers.length == 0) throw new Error("No valid seed servers in the array"); + + // Let's set up our strategy object for picking secondaries + if(this.options.strategy == 'ping') { + // Create a new instance + this.strategyInstance = new PingStrategy(this, this.options.secondaryAcceptableLatencyMS); + } else if(this.options.strategy == 'statistical') { + // Set strategy as statistical + this.strategyInstance = new StatisticsStrategy(this); + // Add enable query information + this.enableRecordQueryStats(true); + } + + this.emitOpen = this.options.emitOpen || true; + // Set up a clean state + this._state = new ReplSetState(); + // Current round robin selected server + this._currentServerChoice = 0; + // Ensure up the server callbacks + for(var i = 0; i < this.servers.length; i++) { + this.servers[i]._callBackStore = this._callBackStore; + this.servers[i].name = format("%s:%s", this.servers[i].host, this.servers[i].port) + this.servers[i].replicasetInstance = this; + this.servers[i].options.auto_reconnect = false; + this.servers[i].inheritReplSetOptionsFrom(this); + } +} + +/** + * @ignore + */ +inherits(ReplSet, Base); + +// Replicaset states +ReplSet.REPLSET_CONNECTING = 'connecting'; +ReplSet.REPLSET_DISCONNECTED = 'disconnected'; +ReplSet.REPLSET_CONNECTED = 'connected'; +ReplSet.REPLSET_RECONNECTING = 'reconnecting'; +ReplSet.REPLSET_DESTROYED = 'destroyed'; +ReplSet.REPLSET_READ_ONLY = 'readonly'; + +ReplSet.prototype.isAutoReconnect = function() { + return true; +} + +ReplSet.prototype.canWrite = function() { + return this._state.master && this._state.master.isConnected(); +} + +ReplSet.prototype.canRead = function(read) { + if((read == ReadPreference.PRIMARY + || read == null || read == false) && (this._state.master == null || !this._state.master.isConnected())) return false; + return Object.keys(this._state.secondaries).length > 0; +} + +/** + * @ignore + */ +ReplSet.prototype.enableRecordQueryStats = function(enable) { + // Set the global enable record query stats + this.recordQueryStats = enable; + + // Enable all the servers + for(var i = 0; i < this.servers.length; i++) { + this.servers[i].enableRecordQueryStats(enable); + } +} + +/** + * @ignore + */ +ReplSet.prototype.setReadPreference = function(preference) { + this.options.readPreference = preference; +} + +ReplSet.prototype.connect = function(parent, options, callback) { + if(this._serverState != ReplSet.REPLSET_DISCONNECTED) + return callback(new Error("in process of connection")); + + // If no callback throw + if(!(typeof callback == 'function')) + throw new Error("cannot call ReplSet.prototype.connect with no callback function"); + + var self = this; + // Save db reference + this.options.db = parent; + // Set replicaset as connecting + this._serverState = ReplSet.REPLSET_CONNECTING + // Copy all the servers to our list of seeds + var candidateServers = this.servers.slice(0); + // Pop the first server + var server = candidateServers.pop(); + server.name = format("%s:%s", server.host, server.port); + // Set up the options + var opts = { + returnIsMasterResults: true, + eventReceiver: server + } + + // Register some event listeners + this.once("fullsetup", function(err, db, replset) { + // Set state to connected + self._serverState = ReplSet.REPLSET_CONNECTED; + // Stop any process running + if(self._haProcess) self._haProcess.stop(); + // Start the HA process + self._haProcess.start(); + + // Emit fullsetup + processor(function() { + if(self.emitOpen) + self._emitAcrossAllDbInstances(self, null, "open", null, null, null); + + self._emitAcrossAllDbInstances(self, null, "fullsetup", null, null, null); + }); + + // If we have a strategy defined start it + if(self.strategyInstance) { + self.strategyInstance.start(); + } + + // Finishing up the call + callback(err, db, replset); + }); + + // Errors + this.once("connectionError", function(err, result) { + callback(err, result); + }); + + // Attempt to connect to the server + server.connect(this.options.db, opts, _connectHandler(this, candidateServers, server)); +} + +ReplSet.prototype.close = function(callback) { + var self = this; + // Set as destroyed + this._serverState = ReplSet.REPLSET_DESTROYED; + // Stop the ha + this._haProcess.stop(); + + // If we have a strategy stop it + if(this.strategyInstance) { + this.strategyInstance.stop(); + } + + // Kill all servers available + for(var name in this._state.addresses) { + this._state.addresses[name].close(); + } + + // Clean out the state + this._state = new ReplSetState(); + + // Emit close event + processor(function() { + self._emitAcrossAllDbInstances(self, null, "close", null, null, true) + }); + + // Callback + if(typeof callback == 'function') + return callback(null, null); +} + +/** + * Creates a new server for the `replset` based on `host`. + * + * @param {String} host - host:port pair (localhost:27017) + * @param {ReplSet} replset - the ReplSet instance + * @return {Server} + * @ignore + */ +var createServer = function(self, host, options) { + // copy existing socket options to new server + var socketOptions = {} + if(options.socketOptions) { + var keys = Object.keys(options.socketOptions); + for(var k = 0; k < keys.length; k++) { + socketOptions[keys[k]] = options.socketOptions[keys[k]]; + } + } + + var parts = host.split(/:/); + if(1 === parts.length) { + parts[1] = Connection.DEFAULT_PORT; + } + + socketOptions.host = parts[0]; + socketOptions.port = parseInt(parts[1], 10); + + var serverOptions = { + readPreference: options.readPreference, + socketOptions: socketOptions, + poolSize: options.poolSize, + logger: options.logger, + auto_reconnect: false, + ssl: options.ssl, + sslValidate: options.sslValidate, + sslCA: options.sslCA, + sslCert: options.sslCert, + sslKey: options.sslKey, + sslPass: options.sslPass + } + + var server = new Server(socketOptions.host, socketOptions.port, serverOptions); + // Set up shared state + server._callBackStore = self._callBackStore; + server.replicasetInstance = self; + server.enableRecordQueryStats(self.recordQueryStats); + // Set up event handlers + server.on("close", _handler("close", self, server)); + server.on("error", _handler("error", self, server)); + server.on("timeout", _handler("timeout", self, server)); + return server; +} + +var _handler = function(event, self, server) { + return function(err, doc) { + // The event happened to a primary + // Remove it from play + if(self._state.isPrimary(server)) { + var current_master = self._state.master; + self._state.master = null; + self._serverState = ReplSet.REPLSET_READ_ONLY; + + if(current_master != null) { + // Unpack variables + var host = current_master.socketOptions.host; + var port = current_master.socketOptions.port; + + // Fire error on any unknown callbacks + self.__executeAllServerSpecificErrorCallbacks(host, port, err); + } + } else if(self._state.isSecondary(server)) { + delete self._state.secondaries[server.name]; + } + + // If there is no more connections left and the setting is not destroyed + // set to disconnected + if(Object.keys(self._state.addresses).length == 0 + && self._serverState != ReplSet.REPLSET_DESTROYED) { + self._serverState = ReplSet.REPLSET_DISCONNECTED; + + // Emit close across all the attached db instances + self._dbStore.emit("close", new Error("replicaset disconnected, no valid servers contactable over tcp"), null, true); + } + + // Unpack variables + var host = server.socketOptions.host; + var port = server.socketOptions.port; + + // Fire error on any unknown callbacks + self.__executeAllServerSpecificErrorCallbacks(host, port, err); + } +} + +var locateNewServers = function(self, state, candidateServers, ismaster) { + // Retrieve the host + var hosts = ismaster.hosts; + // In candidate servers + var inCandidateServers = function(name, candidateServers) { + for(var i = 0; i < candidateServers.length; i++) { + if(candidateServers[i].name == name) return true; + } + + return false; + } + + // New servers + var newServers = []; + if(Array.isArray(hosts)) { + // Let's go over all the hosts + for(var i = 0; i < hosts.length; i++) { + if(!state.contains(hosts[i]) + && !inCandidateServers(hosts[i], candidateServers)) { + newServers.push(createServer(self, hosts[i], self.options)); + } + } + } + + // Return list of possible new servers + return newServers; +} + +var _connectHandler = function(self, candidateServers, instanceServer) { + return function(err, doc) { + // If we have an error add to the list + if(err) { + self._state.errors[instanceServer.name] = instanceServer; + } else { + delete self._state.errors[instanceServer.name]; + } + + if(!err) { + var ismaster = doc.documents[0] + + // Error the server if + if(!ismaster.ismaster + && !ismaster.secondary) { + self._state.errors[instanceServer.name] = instanceServer; + } + } + + + // No error let's analyse the ismaster command + if(!err && self._state.errors[instanceServer.name] == null) { + var ismaster = doc.documents[0] + + // If no replicaset name exists set the current one + if(self.options.rs_name == null) { + self.options.rs_name = ismaster.setName; + } + + // If we have a member that is not part of the set let's finish up + if(typeof ismaster.setName == 'string' && ismaster.setName != self.options.rs_name) { + return self.emit("connectionError", new Error("Replicaset name " + ismaster.setName + " does not match specified name " + self.options.rs_name)); + } + + // Add the error handlers + instanceServer.on("close", _handler("close", self, instanceServer)); + instanceServer.on("error", _handler("error", self, instanceServer)); + instanceServer.on("timeout", _handler("timeout", self, instanceServer)); + + // Set any tags on the instance server + instanceServer.name = ismaster.me; + instanceServer.tags = ismaster.tags; + + // Add the server to the list + self._state.addServer(instanceServer, ismaster); + + // Check if we have more servers to add (only check when done with initial set) + if(candidateServers.length == 0) { + // Get additional new servers that are not currently in set + var new_servers = locateNewServers(self, self._state, candidateServers, ismaster); + + // Locate any new servers that have not errored out yet + for(var i = 0; i < new_servers.length; i++) { + if(self._state.errors[new_servers[i].name] == null) { + candidateServers.push(new_servers[i]) + } + } + } + } + + // If the candidate server list is empty and no valid servers + if(candidateServers.length == 0 && + !self._state.hasValidServers()) { + return self.emit("connectionError", new Error("No valid replicaset instance servers found")); + } else if(candidateServers.length == 0) { + if(!self.options.connectWithNoPrimary && (self._state.master == null || !self._state.master.isConnected())) { + return self.emit("connectionError", new Error("No primary found in set")); + } + return self.emit("fullsetup", null, self.options.db, self); + } + + // Let's connect the next server + var nextServer = candidateServers.pop(); + + // Set up the options + var opts = { + returnIsMasterResults: true, + eventReceiver: nextServer + } + + // Attempt to connect to the server + nextServer.connect(self.options.db, opts, _connectHandler(self, candidateServers, nextServer)); + } +} + +ReplSet.prototype.isDestroyed = function() { + return this._serverState == ReplSet.REPLSET_DESTROYED; +} + +ReplSet.prototype.isConnected = function(read) { + var isConnected = false; + + if(read == null || read == ReadPreference.PRIMARY || read == false) + isConnected = this._state.master != null && this._state.master.isConnected(); + + if((read == ReadPreference.PRIMARY_PREFERRED || read == ReadPreference.SECONDARY_PREFERRED || read == ReadPreference.NEAREST) + && ((this._state.master != null && this._state.master.isConnected()) + || (this._state && this._state.secondaries && Object.keys(this._state.secondaries).length > 0))) { + isConnected = true; + } else if(read == ReadPreference.SECONDARY) { + isConnected = this._state && this._state.secondaries && Object.keys(this._state.secondaries).length > 0; + } + + // No valid connection return false + return isConnected; +} + +ReplSet.prototype.isMongos = function() { + return false; +} + +ReplSet.prototype.checkoutWriter = function() { + if(this._state.master) return this._state.master.checkoutWriter(); + return new Error("no writer connection available"); +} + +ReplSet.prototype.processIsMaster = function(_server, _ismaster) { + // Server in recovery mode, remove it from available servers + if(!_ismaster.ismaster && !_ismaster.secondary) { + // Locate the actual server + var server = this._state.addresses[_server.name]; + // Close the server, simulating the closing of the connection + // to get right removal semantics + if(server) server.close(); + // Execute any callback errors + _handler(null, this, server)(new Error("server is in recovery mode")); + } +} + +ReplSet.prototype.allRawConnections = function() { + var connections = []; + + for(var name in this._state.addresses) { + connections = connections.concat(this._state.addresses[name].allRawConnections()); + } + + return connections; +} + +/** + * @ignore + */ +ReplSet.prototype.allServerInstances = function() { + var self = this; + // If no state yet return empty + if(!self._state) return []; + // Close all the servers (concatenate entire list of servers first for ease) + var allServers = self._state.master != null ? [self._state.master] : []; + + // Secondary keys + var keys = Object.keys(self._state.secondaries); + // Add all secondaries + for(var i = 0; i < keys.length; i++) { + allServers.push(self._state.secondaries[keys[i]]); + } + + // Return complete list of all servers + return allServers; +} + +/** + * @ignore + */ +ReplSet.prototype.checkoutReader = function(readPreference, tags) { + var connection = null; + + // If we have a read preference object unpack it + if(typeof readPreference == 'object' && readPreference['_type'] == 'ReadPreference') { + // Validate if the object is using a valid mode + if(!readPreference.isValid()) throw new Error("Illegal readPreference mode specified, " + readPreference.mode); + // Set the tag + tags = readPreference.tags; + readPreference = readPreference.mode; + } else if(typeof readPreference == 'object' && readPreference['_type'] != 'ReadPreference') { + return new Error("read preferences must be either a string or an instance of ReadPreference"); + } + + // Set up our read Preference, allowing us to override the readPreference + var finalReadPreference = readPreference != null ? readPreference : this.options.readPreference; + + // Ensure we unpack a reference + if(finalReadPreference != null && typeof finalReadPreference == 'object' && finalReadPreference['_type'] == 'ReadPreference') { + // Validate if the object is using a valid mode + if(!finalReadPreference.isValid()) throw new Error("Illegal readPreference mode specified, " + finalReadPreference.mode); + // Set the tag + tags = finalReadPreference.tags; + readPreference = finalReadPreference.mode; + } + + // Finalize the read preference setup + finalReadPreference = finalReadPreference == true ? ReadPreference.SECONDARY_PREFERRED : finalReadPreference; + finalReadPreference = finalReadPreference == null ? ReadPreference.PRIMARY : finalReadPreference; + + // If we are reading from a primary + if(finalReadPreference == 'primary') { + // If we provide a tags set send an error + if(typeof tags == 'object' && tags != null) { + return new Error("PRIMARY cannot be combined with tags"); + } + + // If we provide a tags set send an error + if(this._state.master == null) { + return new Error("No replica set primary available for query with ReadPreference PRIMARY"); + } + + // Checkout a writer + return this.checkoutWriter(); + } + + // If we have specified to read from a secondary server grab a random one and read + // from it, otherwise just pass the primary connection + if((this.options.readSecondary || finalReadPreference == ReadPreference.SECONDARY_PREFERRED || finalReadPreference == ReadPreference.SECONDARY) && Object.keys(this._state.secondaries).length > 0) { + // If we have tags, look for servers matching the specific tag + if(this.strategyInstance != null) { + // Only pick from secondaries + var _secondaries = []; + for(var key in this._state.secondaries) { + _secondaries.push(this._state.secondaries[key]); + } + + if(finalReadPreference == ReadPreference.SECONDARY) { + // Check out the nearest from only the secondaries + connection = this.strategyInstance.checkoutConnection(tags, _secondaries); + } else { + connection = this.strategyInstance.checkoutConnection(tags, _secondaries); + // No candidate servers that match the tags, error + if(connection == null || connection instanceof Error) { + // No secondary server avilable, attemp to checkout a primary server + connection = this.checkoutWriter(); + // If no connection return an error + if(connection == null || connection instanceof Error) { + return new Error("No replica set members available for query"); + } + } + } + } else if(tags != null && typeof tags == 'object') { + // Get connection + connection = _pickFromTags(this, tags);// = function(self, readPreference, tags) { + // No candidate servers that match the tags, error + if(connection == null) { + return new Error("No replica set members available for query"); + } + } else { + connection = _roundRobin(this, tags); + } + } else if(finalReadPreference == ReadPreference.PRIMARY_PREFERRED) { + // Check if there is a primary available and return that if possible + connection = this.checkoutWriter(); + // If no connection available checkout a secondary + if(connection == null || connection instanceof Error) { + // If we have tags, look for servers matching the specific tag + if(tags != null && typeof tags == 'object') { + // Get connection + connection = _pickFromTags(this, tags);// = function(self, readPreference, tags) { + // No candidate servers that match the tags, error + if(connection == null) { + return new Error("No replica set members available for query"); + } + } else { + connection = _roundRobin(this, tags); + } + } + } else if(finalReadPreference == ReadPreference.SECONDARY_PREFERRED) { + // If we have tags, look for servers matching the specific tag + if(this.strategyInstance != null) { + connection = this.strategyInstance.checkoutConnection(tags); + + // No candidate servers that match the tags, error + if(connection == null || connection instanceof Error) { + // No secondary server avilable, attemp to checkout a primary server + connection = this.checkoutWriter(); + // If no connection return an error + if(connection == null || connection instanceof Error) { + var preferenceName = finalReadPreference == ReadPreference.SECONDARY ? 'secondary' : finalReadPreference; + return new Error("No replica set member available for query with ReadPreference " + preferenceName + " and tags " + JSON.stringify(tags)); + } + } + } else if(tags != null && typeof tags == 'object') { + // Get connection + connection = _pickFromTags(this, tags);// = function(self, readPreference, tags) { + // No candidate servers that match the tags, error + if(connection == null) { + // No secondary server avilable, attemp to checkout a primary server + connection = this.checkoutWriter(); + // If no connection return an error + if(connection == null || connection instanceof Error) { + var preferenceName = finalReadPreference == ReadPreference.SECONDARY ? 'secondary' : finalReadPreference; + return new Error("No replica set member available for query with ReadPreference " + preferenceName + " and tags " + JSON.stringify(tags)); + } + } + } + } else if(finalReadPreference == ReadPreference.NEAREST && this.strategyInstance != null) { + connection = this.strategyInstance.checkoutConnection(tags); + } else if(finalReadPreference == ReadPreference.NEAREST && this.strategyInstance == null) { + return new Error("A strategy for calculating nearness must be enabled such as ping or statistical"); + } else if(finalReadPreference == ReadPreference.SECONDARY && Object.keys(this._state.secondaries).length == 0) { + if(tags != null && typeof tags == 'object') { + var preferenceName = finalReadPreference == ReadPreference.SECONDARY ? 'secondary' : finalReadPreference; + return new Error("No replica set member available for query with ReadPreference " + preferenceName + " and tags " + JSON.stringify(tags)); + } else { + return new Error("No replica set secondary available for query with ReadPreference SECONDARY"); + } + } else { + connection = this.checkoutWriter(); + } + + // Return the connection + return connection; +} + +/** + * @ignore + */ +var _pickFromTags = function(self, tags) { + // If we have an array or single tag selection + var tagObjects = Array.isArray(tags) ? tags : [tags]; + // Iterate over all tags until we find a candidate server + for(var _i = 0; _i < tagObjects.length; _i++) { + // Grab a tag object + var tagObject = tagObjects[_i]; + // Matching keys + var matchingKeys = Object.keys(tagObject); + // Match all the servers that match the provdided tags + var keys = Object.keys(self._state.secondaries); + var candidateServers = []; + + for(var i = 0; i < keys.length; i++) { + var server = self._state.secondaries[keys[i]]; + // If we have tags match + if(server.tags != null) { + var matching = true; + // Ensure we have all the values + for(var j = 0; j < matchingKeys.length; j++) { + if(server.tags[matchingKeys[j]] != tagObject[matchingKeys[j]]) { + matching = false; + break; + } + } + + // If we have a match add it to the list of matching servers + if(matching) { + candidateServers.push(server); + } + } + } + + // If we have a candidate server return + if(candidateServers.length > 0) { + if(self.strategyInstance) return self.strategyInstance.checkoutConnection(tags, candidateServers); + // Set instance to return + return candidateServers[Math.floor(Math.random() * candidateServers.length)].checkoutReader(); + } + } + + // No connection found + return null; +} + +/** + * Pick a secondary using round robin + * + * @ignore + */ +function _roundRobin (replset, tags) { + var keys = Object.keys(replset._state.secondaries); + // Update index + replset._currentServerChoice = replset._currentServerChoice + 1; + // Pick a server + var key = keys[replset._currentServerChoice % keys.length]; + + var conn = null != replset._state.secondaries[key] + ? replset._state.secondaries[key].checkoutReader() + : null; + + // If connection is null fallback to first available secondary + if(null == conn) { + conn = pickFirstConnectedSecondary(replset, tags); + } + + return conn; +} + +/** + * @ignore + */ +var pickFirstConnectedSecondary = function pickFirstConnectedSecondary(self, tags) { + var keys = Object.keys(self._state.secondaries); + var connection; + + // Find first available reader if any + for(var i = 0; i < keys.length; i++) { + connection = self._state.secondaries[keys[i]].checkoutReader(); + if(connection) return connection; + } + + // If we still have a null, read from primary if it's not secondary only + if(self._readPreference == ReadPreference.SECONDARY_PREFERRED) { + connection = self._state.master.checkoutReader(); + if(connection) return connection; + } + + var preferenceName = self._readPreference == ReadPreference.SECONDARY_PREFERRED + ? 'secondary' + : self._readPreference; + + return new Error("No replica set member available for query with ReadPreference " + + preferenceName + " and tags " + JSON.stringify(tags)); +} + +/** + * Get list of secondaries + * @ignore + */ +Object.defineProperty(ReplSet.prototype, "secondaries", {enumerable: true + , get: function() { + return utils.objectToArray(this._state.secondaries); + } +}); + +/** + * Get list of secondaries + * @ignore + */ +Object.defineProperty(ReplSet.prototype, "arbiters", {enumerable: true + , get: function() { + return utils.objectToArray(this._state.arbiters); + } +}); + diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/repl_set_state.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/repl_set_state.js new file mode 100644 index 0000000..6f9e143 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/repl_set_state.js @@ -0,0 +1,70 @@ +/** + * Interval state object constructor + * + * @ignore + */ +var ReplSetState = function ReplSetState () { + this.errorMessages = []; + this.secondaries = {}; + this.addresses = {}; + this.arbiters = {}; + this.passives = {}; + this.members = []; + this.errors = {}; + this.setName = null; + this.master = null; +} + +ReplSetState.prototype.hasValidServers = function() { + var validServers = []; + if(this.master && this.master.isConnected()) return true; + + if(this.secondaries) { + var keys = Object.keys(this.secondaries) + for(var i = 0; i < keys.length; i++) { + if(this.secondaries[keys[i]].isConnected()) + return true; + } + } + + return false; +} + +ReplSetState.prototype.getAllReadServers = function() { + var candidate_servers = []; + for(var name in this.addresses) { + candidate_servers.push(this.addresses[name]); + } + + // Return all possible read candidates + return candidate_servers; +} + +ReplSetState.prototype.addServer = function(server, master) { + server.name = master.me; + + if(master.ismaster) { + this.master = server; + this.addresses[server.name] = server; + } else if(master.secondary) { + this.secondaries[server.name] = server; + this.addresses[server.name] = server; + } else if(master.arbiters) { + this.arbiters[server.name] = server; + this.addresses[server.name] = server; + } +} + +ReplSetState.prototype.contains = function(host) { + return this.addresses[host] != null; +} + +ReplSetState.prototype.isPrimary = function(server) { + return this.master && this.master.name == server.name; +} + +ReplSetState.prototype.isSecondary = function(server) { + return this.secondaries[server.name] != null; +} + +exports.ReplSetState = ReplSetState; diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/strategies/ping_strategy.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/strategies/ping_strategy.js new file mode 100644 index 0000000..76990e2 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/strategies/ping_strategy.js @@ -0,0 +1,333 @@ +var Server = require("../../server").Server + , format = require('util').format; + +// The ping strategy uses pings each server and records the +// elapsed time for the server so it can pick a server based on lowest +// return time for the db command {ping:true} +var PingStrategy = exports.PingStrategy = function(replicaset, secondaryAcceptableLatencyMS) { + this.replicaset = replicaset; + this.secondaryAcceptableLatencyMS = secondaryAcceptableLatencyMS; + this.state = 'disconnected'; + this.pingInterval = 5000; + // Class instance + this.Db = require("../../../db").Db; + // Active db connections + this.dbs = {}; + // Current server index + this.index = 0; + // Logger api + this.Logger = null; +} + +// Starts any needed code +PingStrategy.prototype.start = function(callback) { + // already running? + if ('connected' == this.state) return; + + this.state = 'connected'; + + // Start ping server + this._pingServer(callback); +} + +// Stops and kills any processes running +PingStrategy.prototype.stop = function(callback) { + // Stop the ping process + this.state = 'disconnected'; + + // Stop all the server instances + for(var key in this.dbs) { + this.dbs[key].close(); + } + + // optional callback + callback && callback(null, null); +} + +PingStrategy.prototype.checkoutConnection = function(tags, secondaryCandidates) { + // Servers are picked based on the lowest ping time and then servers that lower than that + secondaryAcceptableLatencyMS + // Create a list of candidat servers, containing the primary if available + var candidateServers = []; + var self = this; + + // If we have not provided a list of candidate servers use the default setup + if(!Array.isArray(secondaryCandidates)) { + candidateServers = this.replicaset._state.master != null ? [this.replicaset._state.master] : []; + // Add all the secondaries + var keys = Object.keys(this.replicaset._state.secondaries); + for(var i = 0; i < keys.length; i++) { + candidateServers.push(this.replicaset._state.secondaries[keys[i]]) + } + } else { + candidateServers = secondaryCandidates; + } + + // Final list of eligable server + var finalCandidates = []; + + // If we have tags filter by tags + if(tags != null && typeof tags == 'object') { + // If we have an array or single tag selection + var tagObjects = Array.isArray(tags) ? tags : [tags]; + // Iterate over all tags until we find a candidate server + for(var _i = 0; _i < tagObjects.length; _i++) { + // Grab a tag object + var tagObject = tagObjects[_i]; + // Matching keys + var matchingKeys = Object.keys(tagObject); + // Remove any that are not tagged correctly + for(var i = 0; i < candidateServers.length; i++) { + var server = candidateServers[i]; + // If we have tags match + if(server.tags != null) { + var matching = true; + + // Ensure we have all the values + for(var j = 0; j < matchingKeys.length; j++) { + if(server.tags[matchingKeys[j]] != tagObject[matchingKeys[j]]) { + matching = false; + break; + } + } + + // If we have a match add it to the list of matching servers + if(matching) { + finalCandidates.push(server); + } + } + } + } + } else { + // Final array candidates + var finalCandidates = candidateServers; + } + + // Sort by ping time + finalCandidates.sort(function(a, b) { + return a.runtimeStats['pingMs'] > b.runtimeStats['pingMs']; + }); + + if(0 === finalCandidates.length) + return new Error("No replica set members available for query"); + + // find lowest server with a ping time + var lowest = finalCandidates.filter(function (server) { + return undefined != server.runtimeStats.pingMs; + })[0]; + + if(!lowest) { + lowest = finalCandidates[0]; + } + + // convert to integer + var lowestPing = lowest.runtimeStats.pingMs | 0; + + // determine acceptable latency + var acceptable = lowestPing + this.secondaryAcceptableLatencyMS; + + // remove any server responding slower than acceptable + var len = finalCandidates.length; + while(len--) { + if(finalCandidates[len].runtimeStats['pingMs'] > acceptable) { + finalCandidates.splice(len, 1); + } + } + + if(self.logger && self.logger.debug) { + self.logger.debug("Ping strategy selection order for tags", tags); + finalCandidates.forEach(function(c) { + self.logger.debug(format("%s:%s = %s ms", c.host, c.port, c.runtimeStats['pingMs']), null); + }) + } + + // If no candidates available return an error + if(finalCandidates.length == 0) + return new Error("No replica set members available for query"); + + // Ensure no we don't overflow + this.index = this.index % finalCandidates.length + // Pick a random acceptable server + var connection = finalCandidates[this.index].checkoutReader(); + // Point to next candidate (round robin style) + this.index = this.index + 1; + + if(self.logger && self.logger.debug) { + if(connection) + self.logger.debug("picked server %s:%s", connection.socketOptions.host, connection.socketOptions.port); + } + + return connection; +} + +PingStrategy.prototype._pingServer = function(callback) { + var self = this; + + // Ping server function + var pingFunction = function() { + // Our state changed to disconnected or destroyed return + if(self.state == 'disconnected' || self.state == 'destroyed') return; + // If the replicaset is destroyed return + if(self.replicaset.isDestroyed() || self.replicaset._serverState == 'disconnected') return + + // Create a list of all servers we can send the ismaster command to + var allServers = self.replicaset._state.master != null ? [self.replicaset._state.master] : []; + + // Secondary keys + var keys = Object.keys(self.replicaset._state.secondaries); + // Add all secondaries + for(var i = 0; i < keys.length; i++) { + allServers.push(self.replicaset._state.secondaries[keys[i]]); + } + + // Number of server entries + var numberOfEntries = allServers.length; + + // We got keys + for(var i = 0; i < allServers.length; i++) { + + // We got a server instance + var server = allServers[i]; + + // Create a new server object, avoid using internal connections as they might + // be in an illegal state + new function(serverInstance) { + var _db = self.dbs[serverInstance.host + ":" + serverInstance.port]; + // If we have a db + if(_db != null) { + // Startup time of the command + var startTime = Date.now(); + + // Execute ping command in own scope + var _ping = function(__db, __serverInstance) { + // Execute ping on this connection + __db.executeDbCommand({ping:1}, {failFast:true}, function(err) { + if(err) { + delete self.dbs[__db.serverConfig.host + ":" + __db.serverConfig.port]; + __db.close(); + return done(); + } + + if(null != __serverInstance.runtimeStats && __serverInstance.isConnected()) { + __serverInstance.runtimeStats['pingMs'] = Date.now() - startTime; + } + + __db.executeDbCommand({ismaster:1}, {failFast:true}, function(err, result) { + if(err) { + delete self.dbs[__db.serverConfig.host + ":" + __db.serverConfig.port]; + __db.close(); + return done(); + } + + // Process the ismaster for the server + if(result && result.documents && self.replicaset.processIsMaster) { + self.replicaset.processIsMaster(__serverInstance, result.documents[0]); + } + + // Done with the pinging + done(); + }); + }); + }; + // Ping + _ping(_db, serverInstance); + } else { + var connectTimeoutMS = self.replicaset.options.socketOptions + ? self.replicaset.options.socketOptions.connectTimeoutMS : 0 + + // Create a new master connection + var _server = new Server(serverInstance.host, serverInstance.port, { + auto_reconnect: false, + returnIsMasterResults: true, + slaveOk: true, + poolSize: 1, + socketOptions: { connectTimeoutMS: connectTimeoutMS }, + ssl: self.replicaset.ssl, + sslValidate: self.replicaset.sslValidate, + sslCA: self.replicaset.sslCA, + sslCert: self.replicaset.sslCert, + sslKey: self.replicaset.sslKey, + sslPass: self.replicaset.sslPass + }); + + // Create Db instance + var _db = new self.Db('local', _server, { safe: true }); + _db.on("close", function() { + delete self.dbs[this.serverConfig.host + ":" + this.serverConfig.port]; + }) + + var _ping = function(__db, __serverInstance) { + if(self.state == 'disconnected') { + self.stop(); + return; + } + + __db.open(function(err, db) { + if(self.state == 'disconnected' && __db != null) { + return __db.close(); + } + + if(err) { + delete self.dbs[__db.serverConfig.host + ":" + __db.serverConfig.port]; + __db.close(); + return done(); + } + + // Save instance + self.dbs[__db.serverConfig.host + ":" + __db.serverConfig.port] = __db; + + // Startup time of the command + var startTime = Date.now(); + + // Execute ping on this connection + __db.executeDbCommand({ping:1}, {failFast:true}, function(err) { + if(err) { + delete self.dbs[__db.serverConfig.host + ":" + __db.serverConfig.port]; + __db.close(); + return done(); + } + + if(null != __serverInstance.runtimeStats && __serverInstance.isConnected()) { + __serverInstance.runtimeStats['pingMs'] = Date.now() - startTime; + } + + __db.executeDbCommand({ismaster:1}, {failFast:true}, function(err, result) { + if(err) { + delete self.dbs[__db.serverConfig.host + ":" + __db.serverConfig.port]; + __db.close(); + return done(); + } + + // Process the ismaster for the server + if(result && result.documents && self.replicaset.processIsMaster) { + self.replicaset.processIsMaster(__serverInstance, result.documents[0]); + } + + // Done with the pinging + done(); + }); + }); + }); + }; + + // Ping the server + _ping(_db, serverInstance); + } + + function done() { + // Adjust the number of checks + numberOfEntries--; + + // If we are done with all results coming back trigger ping again + if(0 === numberOfEntries && 'connected' == self.state) { + setTimeout(pingFunction, self.pingInterval); + } + } + }(server); + } + } + + // Start pingFunction + pingFunction(); + + callback && callback(null); +} diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/strategies/statistics_strategy.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/strategies/statistics_strategy.js new file mode 100644 index 0000000..f9b8c46 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/strategies/statistics_strategy.js @@ -0,0 +1,80 @@ +// The Statistics strategy uses the measure of each end-start time for each +// query executed against the db to calculate the mean, variance and standard deviation +// and pick the server which the lowest mean and deviation +var StatisticsStrategy = exports.StatisticsStrategy = function(replicaset) { + this.replicaset = replicaset; + // Logger api + this.Logger = null; +} + +// Starts any needed code +StatisticsStrategy.prototype.start = function(callback) { + callback && callback(null, null); +} + +StatisticsStrategy.prototype.stop = function(callback) { + callback && callback(null, null); +} + +StatisticsStrategy.prototype.checkoutConnection = function(tags, secondaryCandidates) { + // Servers are picked based on the lowest ping time and then servers that lower than that + secondaryAcceptableLatencyMS + // Create a list of candidat servers, containing the primary if available + var candidateServers = []; + + // If we have not provided a list of candidate servers use the default setup + if(!Array.isArray(secondaryCandidates)) { + candidateServers = this.replicaset._state.master != null ? [this.replicaset._state.master] : []; + // Add all the secondaries + var keys = Object.keys(this.replicaset._state.secondaries); + for(var i = 0; i < keys.length; i++) { + candidateServers.push(this.replicaset._state.secondaries[keys[i]]) + } + } else { + candidateServers = secondaryCandidates; + } + + // Final list of eligable server + var finalCandidates = []; + + // If we have tags filter by tags + if(tags != null && typeof tags == 'object') { + // If we have an array or single tag selection + var tagObjects = Array.isArray(tags) ? tags : [tags]; + // Iterate over all tags until we find a candidate server + for(var _i = 0; _i < tagObjects.length; _i++) { + // Grab a tag object + var tagObject = tagObjects[_i]; + // Matching keys + var matchingKeys = Object.keys(tagObject); + // Remove any that are not tagged correctly + for(var i = 0; i < candidateServers.length; i++) { + var server = candidateServers[i]; + // If we have tags match + if(server.tags != null) { + var matching = true; + + // Ensure we have all the values + for(var j = 0; j < matchingKeys.length; j++) { + if(server.tags[matchingKeys[j]] != tagObject[matchingKeys[j]]) { + matching = false; + break; + } + } + + // If we have a match add it to the list of matching servers + if(matching) { + finalCandidates.push(server); + } + } + } + } + } else { + // Final array candidates + var finalCandidates = candidateServers; + } + + // If no candidates available return an error + if(finalCandidates.length == 0) return new Error("No replica set members available for query"); + // Pick a random server + return finalCandidates[Math.round(Math.random(1000000) * (finalCandidates.length - 1))].checkoutReader(); +} diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js new file mode 100644 index 0000000..f80f6f6 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js @@ -0,0 +1,919 @@ +var Connection = require('./connection').Connection, + ReadPreference = require('./read_preference').ReadPreference, + DbCommand = require('../commands/db_command').DbCommand, + MongoReply = require('../responses/mongo_reply').MongoReply, + ConnectionPool = require('./connection_pool').ConnectionPool, + EventEmitter = require('events').EventEmitter, + Base = require('./base').Base, + format = require('util').format, + utils = require('../utils'), + timers = require('timers'), + inherits = require('util').inherits; + +// Set processor, setImmediate if 0.10 otherwise nextTick +var processor = require('../utils').processor(); + +/** + * Class representing a single MongoDB Server connection + * + * Options + * - **readPreference** {String, default:null}, set's the read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST) + * - **ssl** {Boolean, default:false}, use ssl connection (needs to have a mongod server with ssl support) + * - **sslValidate** {Boolean, default:false}, validate mongod server certificate against ca (needs to have a mongod server with ssl support, 2.4 or higher) + * - **sslCA** {Array, default:null}, Array of valid certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher) + * - **sslCert** {Buffer/String, default:null}, String or buffer containing the certificate we wish to present (needs to have a mongod server with ssl support, 2.4 or higher) + * - **sslKey** {Buffer/String, default:null}, String or buffer containing the certificate private key we wish to present (needs to have a mongod server with ssl support, 2.4 or higher) + * - **sslPass** {Buffer/String, default:null}, String or buffer containing the certificate password (needs to have a mongod server with ssl support, 2.4 or higher) + * - **poolSize** {Number, default:5}, number of connections in the connection pool, set to 5 as default for legacy reasons. + * - **socketOptions** {Object, default:null}, an object containing socket options to use (noDelay:(boolean), keepAlive:(number), connectTimeoutMS:(number), socketTimeoutMS:(number)) + * - **logger** {Object, default:null}, an object representing a logger that you want to use, needs to support functions debug, log, error **({error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}})**. + * - **auto_reconnect** {Boolean, default:false}, reconnect on error. + * - **disableDriverBSONSizeCheck** {Boolean, default:false}, force the server to error if the BSON message is to big + * + * @class Represents a Server connection. + * @param {String} host the server host + * @param {Number} port the server port + * @param {Object} [options] optional options for insert command + */ +function Server(host, port, options) { + // Set up Server instance + if(!(this instanceof Server)) return new Server(host, port, options); + + // Set up event emitter + Base.call(this); + + // Ensure correct values + if(port != null && typeof port == 'object') { + options = port; + port = Connection.DEFAULT_PORT; + } + + var self = this; + this.host = host; + this.port = port; + this.options = options == null ? {} : options; + this.internalConnection; + this.internalMaster = false; + this.connected = false; + this.poolSize = this.options.poolSize == null ? 5 : this.options.poolSize; + this.disableDriverBSONSizeCheck = this.options.disableDriverBSONSizeCheck != null ? this.options.disableDriverBSONSizeCheck : false; + this._used = false; + this.replicasetInstance = null; + + // Emit open setup + this.emitOpen = this.options.emitOpen || true; + // Set ssl as connection method + this.ssl = this.options.ssl == null ? false : this.options.ssl; + // Set ssl validation + this.sslValidate = this.options.sslValidate == null ? false : this.options.sslValidate; + // Set the ssl certificate authority (array of Buffer/String keys) + this.sslCA = Array.isArray(this.options.sslCA) ? this.options.sslCA : null; + // Certificate to present to the server + this.sslCert = this.options.sslCert; + // Certificate private key if in separate file + this.sslKey = this.options.sslKey; + // Password to unlock private key + this.sslPass = this.options.sslPass; + // Set server name + this.name = format("%s:%s", host, port); + + // Ensure we are not trying to validate with no list of certificates + if(this.sslValidate && (!Array.isArray(this.sslCA) || this.sslCA.length == 0)) { + throw new Error("The driver expects an Array of CA certificates in the sslCA parameter when enabling sslValidate"); + } + + // Get the readPreference + var readPreference = this.options['readPreference']; + // If readPreference is an object get the mode string + var validateReadPreference = readPreference != null && typeof readPreference == 'object' ? readPreference.mode : readPreference; + // Read preference setting + if(validateReadPreference != null) { + if(validateReadPreference != ReadPreference.PRIMARY && validateReadPreference != ReadPreference.SECONDARY && validateReadPreference != ReadPreference.NEAREST + && validateReadPreference != ReadPreference.SECONDARY_PREFERRED && validateReadPreference != ReadPreference.PRIMARY_PREFERRED) { + throw new Error("Illegal readPreference mode specified, " + validateReadPreference); + } + + // Set read Preference + this._readPreference = readPreference; + } else { + this._readPreference = null; + } + + // Contains the isMaster information returned from the server + this.isMasterDoc; + + // Set default connection pool options + this.socketOptions = this.options.socketOptions != null ? this.options.socketOptions : {}; + if(this.disableDriverBSONSizeCheck) this.socketOptions.disableDriverBSONSizeCheck = this.disableDriverBSONSizeCheck; + + // Set ssl up if it's defined + if(this.ssl) { + this.socketOptions.ssl = true; + // Set ssl validation + this.socketOptions.sslValidate = this.sslValidate == null ? false : this.sslValidate; + // Set the ssl certificate authority (array of Buffer/String keys) + this.socketOptions.sslCA = Array.isArray(this.sslCA) ? this.sslCA : null; + // Set certificate to present + this.socketOptions.sslCert = this.sslCert; + // Set certificate to present + this.socketOptions.sslKey = this.sslKey; + // Password to unlock private key + this.socketOptions.sslPass = this.sslPass; + } + + // Set up logger if any set + this.logger = this.options.logger != null + && (typeof this.options.logger.debug == 'function') + && (typeof this.options.logger.error == 'function') + && (typeof this.options.logger.log == 'function') + ? this.options.logger : {error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}}; + + // Just keeps list of events we allow + this.eventHandlers = {error:[], parseError:[], poolReady:[], message:[], close:[], timeout:[]}; + // Internal state of server connection + this._serverState = 'disconnected'; + // Contains state information about server connection + this._state = {'runtimeStats': {'queryStats':new RunningStats()}}; + // Do we record server stats or not + this.recordQueryStats = false; +}; + +/** + * @ignore + */ +inherits(Server, Base); + +// +// Deprecated, USE ReadPreferences class +// +Server.READ_PRIMARY = ReadPreference.PRIMARY; +Server.READ_SECONDARY = ReadPreference.SECONDARY_PREFERRED; +Server.READ_SECONDARY_ONLY = ReadPreference.SECONDARY; + +/** + * Always ourselves + * @ignore + */ +Server.prototype.setReadPreference = function(readPreference) { + this._readPreference = readPreference; +} + +/** + * @ignore + */ +Server.prototype.isMongos = function() { + return this.isMasterDoc != null && this.isMasterDoc['msg'] == "isdbgrid" ? true : false; +} + +/** + * @ignore + */ +Server.prototype._isUsed = function() { + return this._used; +} + +/** + * @ignore + */ +Server.prototype.close = function(callback) { + // Set server status as disconnected + this._serverState = 'destroyed'; + // Remove all local listeners + this.removeAllListeners(); + + if(this.connectionPool != null) { + // Remove all the listeners on the pool so it does not fire messages all over the place + this.connectionPool.removeAllEventListeners(); + // Close the connection if it's open + this.connectionPool.stop(true); + } + + // Emit close event + if(this.db && !this.isSetMember()) { + var self = this; + processor(function() { + self._emitAcrossAllDbInstances(self, null, "close", null, null, true) + }) + } + + // Peform callback if present + if(typeof callback === 'function') callback(null); +}; + +Server.prototype.isDestroyed = function() { + return this._serverState == 'destroyed'; +} + +/** + * @ignore + */ +Server.prototype.isConnected = function() { + return this.connectionPool != null && this.connectionPool.isConnected(); +} + +/** + * @ignore + */ +Server.prototype.canWrite = Server.prototype.isConnected; +Server.prototype.canRead = Server.prototype.isConnected; + +Server.prototype.isAutoReconnect = function() { + if(this.isSetMember()) return false; + return this.options.auto_reconnect != null ? this.options.auto_reconnect : true; +} + +/** + * @ignore + */ +Server.prototype.allServerInstances = function() { + return [this]; +} + +/** + * @ignore + */ +Server.prototype.isSetMember = function() { + return this.replicasetInstance != null || this.mongosInstance != null; +} + +/** + * Assigns a replica set to this `server`. + * + * @param {ReplSet} replset + * @ignore + */ +Server.prototype.assignReplicaSet = function (replset) { + this.replicasetInstance = replset; + this.inheritReplSetOptionsFrom(replset); + this.enableRecordQueryStats(replset.recordQueryStats); +} + +/** + * Takes needed options from `replset` and overwrites + * our own options. + * + * @param {ReplSet} replset + * @ignore + */ +Server.prototype.inheritReplSetOptionsFrom = function (replset) { + this.socketOptions = {}; + this.socketOptions.connectTimeoutMS = replset.options.socketOptions.connectTimeoutMS || 30000; + + if(replset.options.ssl) { + // Set ssl on + this.socketOptions.ssl = true; + // Set ssl validation + this.socketOptions.sslValidate = replset.options.sslValidate == null ? false : replset.options.sslValidate; + // Set the ssl certificate authority (array of Buffer/String keys) + this.socketOptions.sslCA = Array.isArray(replset.options.sslCA) ? replset.options.sslCA : null; + // Set certificate to present + this.socketOptions.sslCert = replset.options.sslCert; + // Set certificate to present + this.socketOptions.sslKey = replset.options.sslKey; + // Password to unlock private key + this.socketOptions.sslPass = replset.options.sslPass; + } + + // If a socket option object exists clone it + if(utils.isObject(replset.options.socketOptions)) { + var keys = Object.keys(replset.options.socketOptions); + for(var i = 0; i < keys.length; i++) + this.socketOptions[keys[i]] = replset.options.socketOptions[keys[i]]; + } +} + +/** + * Opens this server connection. + * + * @ignore + */ +Server.prototype.connect = function(dbInstance, options, callback) { + if('function' === typeof options) callback = options, options = {}; + if(options == null) options = {}; + if(!('function' === typeof callback)) callback = null; + var self = this; + // Save the options + this.options = options; + + // Currently needed to work around problems with multiple connections in a pool with ssl + // TODO fix if possible + if(this.ssl == true) { + // Set up socket options for ssl + this.socketOptions.ssl = true; + // Set ssl validation + this.socketOptions.sslValidate = this.sslValidate == null ? false : this.sslValidate; + // Set the ssl certificate authority (array of Buffer/String keys) + this.socketOptions.sslCA = Array.isArray(this.sslCA) ? this.sslCA : null; + // Set certificate to present + this.socketOptions.sslCert = this.sslCert; + // Set certificate to present + this.socketOptions.sslKey = this.sslKey; + // Password to unlock private key + this.socketOptions.sslPass = this.sslPass; + } + + // Let's connect + var server = this; + // Let's us override the main receiver of events + var eventReceiver = options.eventReceiver != null ? options.eventReceiver : this; + // Save reference to dbInstance + this.db = dbInstance; // `db` property matches ReplSet and Mongos + this.dbInstances = [dbInstance]; + + // Force connection pool if there is one + if(server.connectionPool) server.connectionPool.stop(); + // Set server state to connecting + this._serverState = 'connecting'; + + if(server.connectionPool != null) { + // Remove all the listeners on the pool so it does not fire messages all over the place + this.connectionPool.removeAllEventListeners(); + // Close the connection if it's open + this.connectionPool.stop(true); + } + + this.connectionPool = new ConnectionPool(this.host, this.port, this.poolSize, dbInstance.bson, this.socketOptions); + var connectionPool = this.connectionPool; + // If ssl is not enabled don't wait between the pool connections + if(this.ssl == null || !this.ssl) connectionPool._timeToWait = null; + // Set logger on pool + connectionPool.logger = this.logger; + connectionPool.bson = dbInstance.bson; + + // Set basic parameters passed in + var returnIsMasterResults = options.returnIsMasterResults == null ? false : options.returnIsMasterResults; + + // Create a default connect handler, overriden when using replicasets + var connectCallback = function(_server) { + return function(err, reply) { + // ensure no callbacks get called twice + var internalCallback = callback; + callback = null; + + // Assign the server + _server = _server != null ? _server : server; + + // If something close down the connection and removed the callback before + // proxy killed connection etc, ignore the erorr as close event was isssued + if(err != null && internalCallback == null) return; + // Internal callback + if(err != null) return internalCallback(err, null, _server); + _server.master = reply.documents[0].ismaster == 1 ? true : false; + _server.connectionPool.setMaxBsonSize(reply.documents[0].maxBsonObjectSize); + _server.connectionPool.setMaxMessageSizeBytes(reply.documents[0].maxMessageSizeBytes); + // Set server state to connEcted + _server._serverState = 'connected'; + // Set server as connected + _server.connected = true; + // Save document returned so we can query it + _server.isMasterDoc = reply.documents[0]; + + if(self.emitOpen) { + _server._emitAcrossAllDbInstances(_server, eventReceiver, "open", null, returnIsMasterResults ? reply : null, null); + self.emitOpen = false; + } else { + _server._emitAcrossAllDbInstances(_server, eventReceiver, "reconnect", null, returnIsMasterResults ? reply : null, null); + } + + // If we have it set to returnIsMasterResults + if(returnIsMasterResults) { + internalCallback(null, reply, _server); + } else { + internalCallback(null, dbInstance, _server); + } + } + }; + + // Let's us override the main connect callback + var connectHandler = options.connectHandler == null ? connectCallback(server) : options.connectHandler; + + // Set up on connect method + connectionPool.on("poolReady", function() { + // Create db command and Add the callback to the list of callbacks by the request id (mapping outgoing messages to correct callbacks) + var db_command = DbCommand.NcreateIsMasterCommand(dbInstance, dbInstance.databaseName); + // Check out a reader from the pool + var connection = connectionPool.checkoutConnection(); + // Register handler for messages + server._registerHandler(db_command, false, connection, connectHandler); + // Write the command out + connection.write(db_command); + }) + + // Set up item connection + connectionPool.on("message", function(message) { + // Attempt to parse the message + try { + // Create a new mongo reply + var mongoReply = new MongoReply() + // Parse the header + mongoReply.parseHeader(message, connectionPool.bson) + + // If message size is not the same as the buffer size + // something went terribly wrong somewhere + if(mongoReply.messageLength != message.length) { + // Emit the error + if(eventReceiver.listeners("error") && eventReceiver.listeners("error").length > 0) eventReceiver.emit("error", new Error("bson length is different from message length"), server); + // Remove all listeners + server.removeAllListeners(); + } else { + var startDate = new Date().getTime(); + + // Callback instance + var callbackInfo = server._findHandler(mongoReply.responseTo.toString()); + + // The command executed another request, log the handler again under that request id + if(mongoReply.requestId > 0 && mongoReply.cursorId.toString() != "0" + && callbackInfo && callbackInfo.info && callbackInfo.info.exhaust) { + server._reRegisterHandler(mongoReply.requestId, callbackInfo); + } + // Parse the body + mongoReply.parseBody(message, connectionPool.bson, callbackInfo.info.raw, function(err) { + if(err != null) { + // If pool connection is already closed + if(server._serverState === 'disconnected') return; + // Set server state to disconnected + server._serverState = 'disconnected'; + // Remove all listeners and close the connection pool + server.removeAllListeners(); + connectionPool.stop(true); + + // If we have a callback return the error + if(typeof callback === 'function') { + // ensure no callbacks get called twice + var internalCallback = callback; + callback = null; + // Perform callback + internalCallback(new Error("connection closed due to parseError"), null, server); + } else if(server.isSetMember()) { + if(server.listeners("parseError") && server.listeners("parseError").length > 0) server.emit("parseError", new Error("connection closed due to parseError"), server); + } else { + if(eventReceiver.listeners("parseError") && eventReceiver.listeners("parseError").length > 0) eventReceiver.emit("parseError", new Error("connection closed due to parseError"), server); + } + + // If we are a single server connection fire errors correctly + if(!server.isSetMember()) { + // Fire all callback errors + server.__executeAllCallbacksWithError(new Error("connection closed due to parseError")); + // Emit error + server._emitAcrossAllDbInstances(server, eventReceiver, "parseError", server, null, true); + } + // Short cut + return; + } + + // Let's record the stats info if it's enabled + if(server.recordQueryStats == true && server._state['runtimeStats'] != null + && server._state.runtimeStats['queryStats'] instanceof RunningStats) { + // Add data point to the running statistics object + server._state.runtimeStats.queryStats.push(new Date().getTime() - callbackInfo.info.start); + } + + // Dispatch the call + server._callHandler(mongoReply.responseTo, mongoReply, null); + + // If we have an error about the server not being master or primary + if((mongoReply.responseFlag & (1 << 1)) != 0 + && mongoReply.documents[0].code + && mongoReply.documents[0].code == 13436) { + server.close(); + } + }); + } + } catch (err) { + // Throw error in next tick + processor(function() { + throw err; + }) + } + }); + + // Handle timeout + connectionPool.on("timeout", function(err) { + // If pool connection is already closed + if(server._serverState === 'disconnected' + || server._serverState === 'destroyed') return; + // Set server state to disconnected + server._serverState = 'disconnected'; + // If we have a callback return the error + if(typeof callback === 'function') { + // ensure no callbacks get called twice + var internalCallback = callback; + callback = null; + // Perform callback + internalCallback(err, null, server); + } else if(server.isSetMember()) { + if(server.listeners("timeout") && server.listeners("timeout").length > 0) server.emit("timeout", err, server); + } else { + if(eventReceiver.listeners("timeout") && eventReceiver.listeners("timeout").length > 0) eventReceiver.emit("timeout", err, server); + } + + // If we are a single server connection fire errors correctly + if(!server.isSetMember()) { + // Fire all callback errors + server.__executeAllCallbacksWithError(err); + // Emit error + server._emitAcrossAllDbInstances(server, eventReceiver, "timeout", err, server, true); + } + + // If we have autoConnect enabled let's fire up an attempt to reconnect + if(server.isAutoReconnect() + && !server.isSetMember() + && (server._serverState != 'destroyed') + && !server._reconnectInProgreess) { + // Set the number of retries + server._reconnect_retries = server.db.numberOfRetries; + // Attempt reconnect + server._reconnectInProgreess = true; + setTimeout(__attemptReconnect(server), server.db.retryMiliSeconds); + } + }); + + // Handle errors + connectionPool.on("error", function(message, connection, error_options) { + // If pool connection is already closed + if(server._serverState === 'disconnected' + || server._serverState === 'destroyed') return; + + // Set server state to disconnected + server._serverState = 'disconnected'; + // Error message + var error_message = new Error(message && message.err ? message.err : message); + // Error message coming from ssl + if(error_options && error_options.ssl) error_message.ssl = true; + + // If we have a callback return the error + if(typeof callback === 'function') { + // ensure no callbacks get called twice + var internalCallback = callback; + callback = null; + // Perform callback + internalCallback(error_message, null, server); + } else if(server.isSetMember()) { + if(server.listeners("error") && server.listeners("error").length > 0) server.emit("error", error_message, server); + } else { + if(eventReceiver.listeners("error") && eventReceiver.listeners("error").length > 0) eventReceiver.emit("error", error_message, server); + } + + // If we are a single server connection fire errors correctly + if(!server.isSetMember()) { + // Fire all callback errors + server.__executeAllCallbacksWithError(error_message); + // Emit error + server._emitAcrossAllDbInstances(server, eventReceiver, "error", error_message, server, true); + } + + // If we have autoConnect enabled let's fire up an attempt to reconnect + if(server.isAutoReconnect() + && !server.isSetMember() + && (server._serverState != 'destroyed') + && !server._reconnectInProgreess) { + + // Set the number of retries + server._reconnect_retries = server.db.numberOfRetries; + // Attempt reconnect + server._reconnectInProgreess = true; + setTimeout(__attemptReconnect(server), server.db.retryMiliSeconds); + } + }); + + // Handle close events + connectionPool.on("close", function() { + // If pool connection is already closed + if(server._serverState === 'disconnected' + || server._serverState === 'destroyed') return; + // Set server state to disconnected + server._serverState = 'disconnected'; + // If we have a callback return the error + if(typeof callback == 'function') { + // ensure no callbacks get called twice + var internalCallback = callback; + callback = null; + // Perform callback + internalCallback(new Error("connection closed"), null, server); + } else if(server.isSetMember()) { + if(server.listeners("close") && server.listeners("close").length > 0) server.emit("close", new Error("connection closed"), server); + } else { + if(eventReceiver.listeners("close") && eventReceiver.listeners("close").length > 0) eventReceiver.emit("close", new Error("connection closed"), server); + } + + // If we are a single server connection fire errors correctly + if(!server.isSetMember()) { + // Fire all callback errors + server.__executeAllCallbacksWithError(new Error("connection closed")); + // Emit error + server._emitAcrossAllDbInstances(server, eventReceiver, "close", server, null, true); + } + + // If we have autoConnect enabled let's fire up an attempt to reconnect + if(server.isAutoReconnect() + && !server.isSetMember() + && (server._serverState != 'destroyed') + && !server._reconnectInProgreess) { + + // Set the number of retries + server._reconnect_retries = server.db.numberOfRetries; + // Attempt reconnect + server._reconnectInProgreess = true; + setTimeout(__attemptReconnect(server), server.db.retryMiliSeconds); + } + }); + + /** + * @ignore + */ + var __attemptReconnect = function(server) { + return function() { + // Attempt reconnect + server.connect(server.db, server.options, function(err, result) { + server._reconnect_retries = server._reconnect_retries - 1; + + if(err) { + // Retry + if(server._reconnect_retries == 0 || server._serverState == 'destroyed') { + server._serverState = 'connected'; + server._reconnectInProgreess = false + // Fire all callback errors + return server.__executeAllCallbacksWithError(new Error("failed to reconnect to server")); + } else { + return setTimeout(__attemptReconnect(server), server.db.retryMiliSeconds); + } + } else { + // Set as authenticating (isConnected will be false) + server._serverState = 'authenticating'; + // Apply any auths, we don't try to catch any errors here + // as there are nowhere to simply propagate them to + self._apply_auths(server.db, function(err, result) { + server._serverState = 'connected'; + server._reconnectInProgreess = false; + server._commandsStore.execute_queries(); + server._commandsStore.execute_writes(); + }); + } + }); + } + } + + // If we have a parser error we are in an unknown state, close everything and emit + // error + connectionPool.on("parseError", function(message) { + // If pool connection is already closed + if(server._serverState === 'disconnected' + || server._serverState === 'destroyed') return; + // Set server state to disconnected + server._serverState = 'disconnected'; + // If we have a callback return the error + if(typeof callback === 'function') { + // ensure no callbacks get called twice + var internalCallback = callback; + callback = null; + // Perform callback + internalCallback(new Error("connection closed due to parseError"), null, server); + } else if(server.isSetMember()) { + if(server.listeners("parseError") && server.listeners("parseError").length > 0) server.emit("parseError", new Error("connection closed due to parseError"), server); + } else { + if(eventReceiver.listeners("parseError") && eventReceiver.listeners("parseError").length > 0) eventReceiver.emit("parseError", new Error("connection closed due to parseError"), server); + } + + // If we are a single server connection fire errors correctly + if(!server.isSetMember()) { + // Fire all callback errors + server.__executeAllCallbacksWithError(new Error("connection closed due to parseError")); + // Emit error + server._emitAcrossAllDbInstances(server, eventReceiver, "parseError", server, null, true); + } + }); + + // Boot up connection poole, pass in a locator of callbacks + connectionPool.start(); +} + +/** + * @ignore + */ +Server.prototype.allRawConnections = function() { + return this.connectionPool.getAllConnections(); +} + +/** + * Check if a writer can be provided + * @ignore + */ +var canCheckoutWriter = function(self, read) { + // We cannot write to an arbiter or secondary server + if(self.isMasterDoc && self.isMasterDoc['arbiterOnly'] == true) { + return new Error("Cannot write to an arbiter"); + } if(self.isMasterDoc && self.isMasterDoc['secondary'] == true) { + return new Error("Cannot write to a secondary"); + } else if(read == true && self._readPreference == ReadPreference.SECONDARY && self.isMasterDoc && self.isMasterDoc['ismaster'] == true) { + return new Error("Cannot read from primary when secondary only specified"); + } else if(!self.isMasterDoc) { + return new Error("Cannot determine state of server"); + } + + // Return no error + return null; +} + +/** + * @ignore + */ +Server.prototype.checkoutWriter = function(read) { + if(read == true) return this.connectionPool.checkoutConnection(); + // Check if are allowed to do a checkout (if we try to use an arbiter f.ex) + var result = canCheckoutWriter(this, read); + // If the result is null check out a writer + if(result == null && this.connectionPool != null) { + return this.connectionPool.checkoutConnection(); + } else if(result == null) { + return null; + } else { + return result; + } +} + +/** + * Check if a reader can be provided + * @ignore + */ +var canCheckoutReader = function(self) { + // We cannot write to an arbiter or secondary server + if(self.isMasterDoc && self.isMasterDoc['arbiterOnly'] == true) { + return new Error("Cannot write to an arbiter"); + } else if(self._readPreference != null) { + // If the read preference is Primary and the instance is not a master return an error + if((self._readPreference == ReadPreference.PRIMARY) && self.isMasterDoc && self.isMasterDoc['ismaster'] != true) { + return new Error("Read preference is Server.PRIMARY and server is not master"); + } else if(self._readPreference == ReadPreference.SECONDARY && self.isMasterDoc && self.isMasterDoc['ismaster'] == true) { + return new Error("Cannot read from primary when secondary only specified"); + } + } else if(!self.isMasterDoc) { + return new Error("Cannot determine state of server"); + } + + // Return no error + return null; +} + +/** + * @ignore + */ +Server.prototype.checkoutReader = function(read) { + // Check if are allowed to do a checkout (if we try to use an arbiter f.ex) + var result = canCheckoutReader(this); + // If the result is null check out a writer + if(result == null && this.connectionPool != null) { + return this.connectionPool.checkoutConnection(); + } else if(result == null) { + return null; + } else { + return result; + } +} + +/** + * @ignore + */ +Server.prototype.enableRecordQueryStats = function(enable) { + this.recordQueryStats = enable; +} + +/** + * Internal statistics object used for calculating average and standard devitation on + * running queries + * @ignore + */ +var RunningStats = function() { + var self = this; + this.m_n = 0; + this.m_oldM = 0.0; + this.m_oldS = 0.0; + this.m_newM = 0.0; + this.m_newS = 0.0; + + // Define getters + Object.defineProperty(this, "numDataValues", { enumerable: true + , get: function () { return this.m_n; } + }); + + Object.defineProperty(this, "mean", { enumerable: true + , get: function () { return (this.m_n > 0) ? this.m_newM : 0.0; } + }); + + Object.defineProperty(this, "variance", { enumerable: true + , get: function () { return ((this.m_n > 1) ? this.m_newS/(this.m_n - 1) : 0.0); } + }); + + Object.defineProperty(this, "standardDeviation", { enumerable: true + , get: function () { return Math.sqrt(this.variance); } + }); + + Object.defineProperty(this, "sScore", { enumerable: true + , get: function () { + var bottom = this.mean + this.standardDeviation; + if(bottom == 0) return 0; + return ((2 * this.mean * this.standardDeviation)/(bottom)); + } + }); +} + +/** + * @ignore + */ +RunningStats.prototype.push = function(x) { + // Update the number of samples + this.m_n = this.m_n + 1; + // See Knuth TAOCP vol 2, 3rd edition, page 232 + if(this.m_n == 1) { + this.m_oldM = this.m_newM = x; + this.m_oldS = 0.0; + } else { + this.m_newM = this.m_oldM + (x - this.m_oldM) / this.m_n; + this.m_newS = this.m_oldS + (x - this.m_oldM) * (x - this.m_newM); + + // set up for next iteration + this.m_oldM = this.m_newM; + this.m_oldS = this.m_newS; + } +} + +/** + * @ignore + */ +Object.defineProperty(Server.prototype, "autoReconnect", { enumerable: true + , get: function () { + return this.options['auto_reconnect'] == null ? false : this.options['auto_reconnect']; + } +}); + +/** + * @ignore + */ +Object.defineProperty(Server.prototype, "connection", { enumerable: true + , get: function () { + return this.internalConnection; + } + , set: function(connection) { + this.internalConnection = connection; + } +}); + +/** + * @ignore + */ +Object.defineProperty(Server.prototype, "master", { enumerable: true + , get: function () { + return this.internalMaster; + } + , set: function(value) { + this.internalMaster = value; + } +}); + +/** + * @ignore + */ +Object.defineProperty(Server.prototype, "primary", { enumerable: true + , get: function () { + return this; + } +}); + +/** + * Getter for query Stats + * @ignore + */ +Object.defineProperty(Server.prototype, "queryStats", { enumerable: true + , get: function () { + return this._state.runtimeStats.queryStats; + } +}); + +/** + * @ignore + */ +Object.defineProperty(Server.prototype, "runtimeStats", { enumerable: true + , get: function () { + return this._state.runtimeStats; + } +}); + +/** + * Get Read Preference method + * @ignore + */ +Object.defineProperty(Server.prototype, "readPreference", { enumerable: true + , get: function () { + if(this._readPreference == null && this.readSecondary) { + return Server.READ_SECONDARY; + } else if(this._readPreference == null && !this.readSecondary) { + return Server.READ_PRIMARY; + } else { + return this._readPreference; + } + } +}); + +/** + * @ignore + */ +exports.Server = Server; diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/url_parser.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/url_parser.js new file mode 100644 index 0000000..347aee0 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/url_parser.js @@ -0,0 +1,251 @@ +var fs = require('fs'), + ReadPreference = require('./read_preference').ReadPreference; + +exports.parse = function(url, options) { + // Ensure we have a default options object if none set + options = options || {}; + // Variables + var connection_part = ''; + var auth_part = ''; + var query_string_part = ''; + var dbName = 'admin'; + + // Must start with mongodb + if(url.indexOf("mongodb://") != 0) + throw Error("URL must be in the format mongodb://user:pass@host:port/dbname"); + // If we have a ? mark cut the query elements off + if(url.indexOf("?") != -1) { + query_string_part = url.substr(url.indexOf("?") + 1); + connection_part = url.substring("mongodb://".length, url.indexOf("?")) + } else { + connection_part = url.substring("mongodb://".length); + } + + // Check if we have auth params + if(connection_part.indexOf("@") != -1) { + auth_part = connection_part.split("@")[0]; + connection_part = connection_part.split("@")[1]; + } + + // Check if the connection string has a db + if(connection_part.indexOf(".sock") != -1) { + if(connection_part.indexOf(".sock/") != -1) { + dbName = connection_part.split(".sock/")[1]; + connection_part = connection_part.split("/", connection_part.indexOf(".sock") + ".sock".length); + } + } else if(connection_part.indexOf("/") != -1) { + dbName = connection_part.split("/")[1]; + connection_part = connection_part.split("/")[0]; + } + + // Result object + var object = {}; + + // Pick apart the authentication part of the string + var authPart = auth_part || ''; + var auth = authPart.split(':', 2); + if(options['uri_decode_auth']){ + auth[0] = decodeURIComponent(auth[0]); + if(auth[1]){ + auth[1] = decodeURIComponent(auth[1]); + } + } + + // Add auth to final object if we have 2 elements + if(auth.length == 2) object.auth = {user: auth[0], password: auth[1]}; + + // Variables used for temporary storage + var hostPart; + var urlOptions; + var servers; + var serverOptions = {socketOptions: {}}; + var dbOptions = {read_preference_tags: []}; + var replSetServersOptions = {socketOptions: {}}; + // Add server options to final object + object.server_options = serverOptions; + object.db_options = dbOptions; + object.rs_options = replSetServersOptions; + object.mongos_options = {}; + + // Let's check if we are using a domain socket + if(url.match(/\.sock/)) { + // Split out the socket part + var domainSocket = url.substring( + url.indexOf("mongodb://") + "mongodb://".length + , url.lastIndexOf(".sock") + ".sock".length); + // Clean out any auth stuff if any + if(domainSocket.indexOf("@") != -1) domainSocket = domainSocket.split("@")[1]; + servers = [{domain_socket: domainSocket}]; + } else { + // Split up the db + hostPart = connection_part; + // Parse all server results + servers = hostPart.split(',').map(function(h) { + var hostPort = h.split(':', 2); + var _host = hostPort[0] || 'localhost'; + var _port = hostPort[1] != null ? parseInt(hostPort[1], 10) : 27017; + // Check for localhost?safe=true style case + if(_host.indexOf("?") != -1) _host = _host.split(/\?/)[0]; + + // Return the mapped object + return {host: _host, port: _port}; + }); + } + + // Get the db name + object.dbName = dbName || 'admin'; + // Split up all the options + urlOptions = (query_string_part || '').split(/[&;]/); + // Ugh, we have to figure out which options go to which constructor manually. + urlOptions.forEach(function(opt) { + if(!opt) return; + var splitOpt = opt.split('='), name = splitOpt[0], value = splitOpt[1]; + // Options implementations + switch(name) { + case 'slaveOk': + case 'slave_ok': + serverOptions.slave_ok = (value == 'true'); + dbOptions.slaveOk = (value == 'true'); + break; + case 'maxPoolSize': + case 'poolSize': + serverOptions.poolSize = parseInt(value, 10); + replSetServersOptions.poolSize = parseInt(value, 10); + break; + case 'autoReconnect': + case 'auto_reconnect': + serverOptions.auto_reconnect = (value == 'true'); + break; + case 'minPoolSize': + throw new Error("minPoolSize not supported"); + case 'maxIdleTimeMS': + throw new Error("maxIdleTimeMS not supported"); + case 'waitQueueMultiple': + throw new Error("waitQueueMultiple not supported"); + case 'waitQueueTimeoutMS': + throw new Error("waitQueueTimeoutMS not supported"); + case 'uuidRepresentation': + throw new Error("uuidRepresentation not supported"); + case 'ssl': + if(value == 'prefer') { + serverOptions.ssl = value; + replSetServersOptions.ssl = value; + break; + } + serverOptions.ssl = (value == 'true'); + replSetServersOptions.ssl = (value == 'true'); + break; + case 'replicaSet': + case 'rs_name': + replSetServersOptions.rs_name = value; + break; + case 'reconnectWait': + replSetServersOptions.reconnectWait = parseInt(value, 10); + break; + case 'retries': + replSetServersOptions.retries = parseInt(value, 10); + break; + case 'readSecondary': + case 'read_secondary': + replSetServersOptions.read_secondary = (value == 'true'); + break; + case 'fsync': + dbOptions.fsync = (value == 'true'); + break; + case 'journal': + dbOptions.journal = (value == 'true'); + break; + case 'safe': + dbOptions.safe = (value == 'true'); + break; + case 'nativeParser': + case 'native_parser': + dbOptions.native_parser = (value == 'true'); + break; + case 'connectTimeoutMS': + serverOptions.socketOptions.connectTimeoutMS = parseInt(value, 10); + replSetServersOptions.socketOptions.connectTimeoutMS = parseInt(value, 10); + break; + case 'socketTimeoutMS': + serverOptions.socketOptions.socketTimeoutMS = parseInt(value, 10); + replSetServersOptions.socketOptions.socketTimeoutMS = parseInt(value, 10); + break; + case 'w': + dbOptions.w = parseInt(value, 10); + break; + case 'authSource': + dbOptions.authSource = value; + break; + case 'gssapiServiceName': + dbOptions.gssapiServiceName = value; + break; + case 'authMechanism': + if(value == 'GSSAPI') { + // If no password provided decode only the principal + if(object.auth == null) { + var urlDecodeAuthPart = decodeURIComponent(authPart); + if(urlDecodeAuthPart.indexOf("@") == -1) throw new Error("GSSAPI requires a provided principal"); + object.auth = {user: urlDecodeAuthPart, password: null}; + } else { + object.auth.user = decodeURIComponent(object.auth.user); + } + } + + // Only support GSSAPI or MONGODB-CR for now + if(value != 'GSSAPI' + && value != 'MONGODB-CR' + && value != 'PLAIN') + throw new Error("only GSSAPI, PLAIN or MONGODB-CR is supported by authMechanism"); + + // Authentication mechanism + dbOptions.authMechanism = value; + break; + case 'wtimeoutMS': + dbOptions.wtimeoutMS = parseInt(value, 10); + break; + case 'readPreference': + if(!ReadPreference.isValid(value)) throw new Error("readPreference must be either primary/primaryPreferred/secondary/secondaryPreferred/nearest"); + dbOptions.read_preference = value; + break; + case 'readPreferenceTags': + // Contains the tag object + var tagObject = {}; + if(value == null || value == '') { + dbOptions.read_preference_tags.push(tagObject); + break; + } + + // Split up the tags + var tags = value.split(/\,/); + for(var i = 0; i < tags.length; i++) { + var parts = tags[i].trim().split(/\:/); + tagObject[parts[0]] = parts[1]; + } + + // Set the preferences tags + dbOptions.read_preference_tags.push(tagObject); + break; + default: + break; + } + }); + + // No tags: should be null (not []) + if(dbOptions.read_preference_tags.length === 0) { + dbOptions.read_preference_tags = null; + } + + // Validate if there are an invalid write concern combinations + if((dbOptions.w == -1 || dbOptions.w == 0) && ( + dbOptions.journal == true + || dbOptions.fsync == true + || dbOptions.safe == true)) throw new Error("w set to -1 or 0 cannot be combined with safe/w/journal/fsync") + + // If no read preference set it to primary + if(!dbOptions.read_preference) dbOptions.read_preference = 'primary'; + + // Add servers to result + object.servers = servers; + // Returned parsed object + return object; +} diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/cursor.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/cursor.js new file mode 100644 index 0000000..7beca60 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/cursor.js @@ -0,0 +1,952 @@ +var QueryCommand = require('./commands/query_command').QueryCommand, + GetMoreCommand = require('./commands/get_more_command').GetMoreCommand, + KillCursorCommand = require('./commands/kill_cursor_command').KillCursorCommand, + Long = require('bson').Long, + ReadPreference = require('./connection/read_preference').ReadPreference, + CursorStream = require('./cursorstream'), + timers = require('timers'), + utils = require('./utils'); + +// Set processor, setImmediate if 0.10 otherwise nextTick +var processor = require('./utils').processor(); + +/** + * Constructor for a cursor object that handles all the operations on query result + * using find. This cursor object is unidirectional and cannot traverse backwards. Clients should not be creating a cursor directly, + * but use find to acquire a cursor. (INTERNAL TYPE) + * + * Options + * - **skip** {Number} skip number of documents to skip. + * - **limit** {Number}, limit the number of results to return. -1 has a special meaning and is used by Db.eval. A value of 1 will also be treated as if it were -1. + * - **sort** {Array | Object}, set to sort the documents coming back from the query. Array of indexes, [['a', 1]] etc. + * - **hint** {Object}, hint force the query to use a specific index. + * - **explain** {Boolean}, explain return the explaination of the query. + * - **snapshot** {Boolean}, snapshot Snapshot mode assures no duplicates are returned. + * - **timeout** {Boolean}, timeout allow the query to timeout. + * - **tailable** {Boolean}, tailable allow the cursor to be tailable. + * - **awaitdata** {Boolean}, awaitdata allow the cursor to wait for data, only applicable for tailable cursor. + * - **batchSize** {Number}, batchSize the number of the subset of results to request the database to return for every request. This should initially be greater than 1 otherwise the database will automatically close the cursor. The batch size can be set to 1 with cursorInstance.batchSize after performing the initial query to the database. + * - **raw** {Boolean}, raw return all query documents as raw buffers (default false). + * - **read** {Boolean}, read specify override of read from source (primary/secondary). + * - **returnKey** {Boolean}, returnKey only return the index key. + * - **maxScan** {Number}, maxScan limit the number of items to scan. + * - **min** {Number}, min set index bounds. + * - **max** {Number}, max set index bounds. + * - **showDiskLoc** {Boolean}, showDiskLoc show disk location of results. + * - **comment** {String}, comment you can put a $comment field on a query to make looking in the profiler logs simpler. + * - **numberOfRetries** {Number}, numberOfRetries if using awaidata specifies the number of times to retry on timeout. + * - **dbName** {String}, dbName override the default dbName. + * - **tailableRetryInterval** {Number}, tailableRetryInterval specify the miliseconds between getMores on tailable cursor. + * - **exhaust** {Boolean}, exhaust have the server send all the documents at once as getMore packets. + * - **partial** {Boolean}, partial have the sharded system return a partial result from mongos. + * + * @class Represents a Cursor. + * @param {Db} db the database object to work with. + * @param {Collection} collection the collection to query. + * @param {Object} selector the query selector. + * @param {Object} fields an object containing what fields to include or exclude from objects returned. + * @param {Object} [options] additional options for the collection. +*/ +function Cursor(db, collection, selector, fields, options) { + this.db = db; + this.collection = collection; + this.selector = selector; + this.fields = fields; + options = !options ? {} : options; + + this.skipValue = options.skip == null ? 0 : options.skip; + this.limitValue = options.limit == null ? 0 : options.limit; + this.sortValue = options.sort; + this.hint = options.hint; + this.explainValue = options.explain; + this.snapshot = options.snapshot; + this.timeout = options.timeout == null ? true : options.timeout; + this.tailable = options.tailable; + this.awaitdata = options.awaitdata; + this.numberOfRetries = options.numberOfRetries == null ? 5 : options.numberOfRetries; + this.currentNumberOfRetries = this.numberOfRetries; + this.batchSizeValue = options.batchSize == null ? 0 : options.batchSize; + this.raw = options.raw == null ? false : options.raw; + this.read = options.read == null ? ReadPreference.PRIMARY : options.read; + this.returnKey = options.returnKey; + this.maxScan = options.maxScan; + this.min = options.min; + this.max = options.max; + this.showDiskLoc = options.showDiskLoc; + this.comment = options.comment; + this.tailableRetryInterval = options.tailableRetryInterval || 100; + this.exhaust = options.exhaust || false; + this.partial = options.partial || false; + this.slaveOk = options.slaveOk || false; + + this.totalNumberOfRecords = 0; + this.items = []; + this.cursorId = Long.fromInt(0); + + // This name + this.dbName = options.dbName; + + // State variables for the cursor + this.state = Cursor.INIT; + // Keep track of the current query run + this.queryRun = false; + this.getMoreTimer = false; + + // If we are using a specific db execute against it + if(this.dbName != null) { + this.collectionName = this.dbName + "." + this.collection.collectionName; + } else { + this.collectionName = (this.db.databaseName ? this.db.databaseName + "." : '') + this.collection.collectionName; + } +}; + +/** + * Resets this cursor to its initial state. All settings like the query string, + * tailable, batchSizeValue, skipValue and limits are preserved. + * + * @return {Cursor} returns itself with rewind applied. + * @api public + */ +Cursor.prototype.rewind = function() { + var self = this; + + if (self.state != Cursor.INIT) { + if (self.state != Cursor.CLOSED) { + self.close(function() {}); + } + + self.numberOfReturned = 0; + self.totalNumberOfRecords = 0; + self.items = []; + self.cursorId = Long.fromInt(0); + self.state = Cursor.INIT; + self.queryRun = false; + } + + return self; +}; + + +/** + * Returns an array of documents. The caller is responsible for making sure that there + * is enough memory to store the results. Note that the array only contain partial + * results when this cursor had been previouly accessed. In that case, + * cursor.rewind() can be used to reset the cursor. + * + * @param {Function} callback This will be called after executing this method successfully. The first parameter will contain the Error object if an error occured, or null otherwise. The second parameter will contain an array of BSON deserialized objects as a result of the query. + * @return {null} + * @api public + */ +Cursor.prototype.toArray = function(callback) { + var self = this; + + if(!callback) { + throw new Error('callback is mandatory'); + } + + if(this.tailable) { + callback(new Error("Tailable cursor cannot be converted to array"), null); + } else if(this.state != Cursor.CLOSED) { + // return toArrayExhaust(self, callback); + // If we are using exhaust we can't use the quick fire method + if(self.exhaust) return toArrayExhaust(self, callback); + // Quick fire using trampoline to avoid nextTick + self.nextObject({noReturn: true}, function(err, result) { + if(err) return callback(utils.toError(err), null); + if(self.cursorId.toString() == "0") { + self.state = Cursor.CLOSED; + return callback(null, self.items); + } + + // Let's issue getMores until we have no more records waiting + getAllByGetMore(self, function(err, done) { + self.state = Cursor.CLOSED; + if(err) return callback(utils.toError(err), null); + // Let's release the internal list + var items = self.items; + self.items = null; + // Return all the items + callback(null, items); + }); + }) + + } else { + callback(new Error("Cursor is closed"), null); + } +} + +var toArrayExhaust = function(self, callback) { + var items = []; + + self.each(function(err, item) { + if(err != null) { + return callback(utils.toError(err), null); + } + + if(item != null && Array.isArray(items)) { + items.push(item); + } else { + var resultItems = items; + items = null; + self.items = []; + callback(null, resultItems); + } + }); +} + +var getAllByGetMore = function(self, callback) { + getMore(self, {noReturn: true}, function(err, result) { + if(err) return callback(utils.toError(err)); + if(result == null) return callback(null, null); + if(self.cursorId.toString() == "0") return callback(null, null); + getAllByGetMore(self, callback); + }) +} + +/** + * Iterates over all the documents for this cursor. As with **{cursor.toArray}**, + * not all of the elements will be iterated if this cursor had been previouly accessed. + * In that case, **{cursor.rewind}** can be used to reset the cursor. However, unlike + * **{cursor.toArray}**, the cursor will only hold a maximum of batch size elements + * at any given time if batch size is specified. Otherwise, the caller is responsible + * for making sure that the entire result can fit the memory. + * + * @param {Function} callback this will be called for while iterating every document of the query result. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the document. + * @return {null} + * @api public + */ +Cursor.prototype.each = function(callback) { + var self = this; + var fn; + + if (!callback) { + throw new Error('callback is mandatory'); + } + + if(this.state != Cursor.CLOSED) { + // If we are using exhaust we can't use the quick fire method + if(self.exhaust) return eachExhaust(self, callback); + // Quick fire using trampoline to avoid nextTick + if(this.items.length > 0) { + // Trampoline all the entries + while(fn = loop(self, callback)) fn(self, callback); + // Call each again + self.each(callback); + } else { + self.nextObject(function(err, item) { + + if(err) { + self.state = Cursor.CLOSED; + return callback(utils.toError(err), item); + } + + if(item == null) return callback(null, null); + callback(null, item); + self.each(callback); + }) + } + } else { + callback(new Error("Cursor is closed"), null); + } +} + +// Special for exhaust command as we don't initiate the actual result sets +// the server just sends them as they arrive meaning we need to get the IO event +// loop happen so we can receive more data from the socket or we return to early +// after the first fetch and loose all the incoming getMore's automatically issued +// from the server. +var eachExhaust = function(self, callback) { + //FIX: stack overflow (on deep callback) (cred: https://github.com/limp/node-mongodb-native/commit/27da7e4b2af02035847f262b29837a94bbbf6ce2) + processor(function(){ + // Fetch the next object until there is no more objects + self.nextObject(function(err, item) { + if(err != null) return callback(err, null); + if(item != null) { + callback(null, item); + eachExhaust(self, callback); + } else { + // Close the cursor if done + self.state = Cursor.CLOSED; + callback(err, null); + } + }); + }); +} + +// Trampoline emptying the number of retrieved items +// without incurring a nextTick operation +var loop = function(self, callback) { + // No more items we are done + if(self.items.length == 0) return; + // Get the next document + var doc = self.items.shift(); + // Callback + callback(null, doc); + // Loop + return loop; +} + +/** + * Determines how many result the query for this cursor will return + * + * @param {Boolean} applySkipLimit if set to true will apply the skip and limits set on the cursor. Defaults to false. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the number of results or null if an error occured. + * @return {null} + * @api public + */ +Cursor.prototype.count = function(applySkipLimit, callback) { + if(typeof applySkipLimit == 'function') { + callback = applySkipLimit; + applySkipLimit = false; + } + + var options = {}; + if(applySkipLimit) { + if(typeof this.skipValue == 'number') options.skip = this.skipValue; + if(typeof this.limitValue == 'number') options.limit = this.limitValue; + } + + // Call count command + this.collection.count(this.selector, options, callback); +}; + +/** + * Sets the sort parameter of this cursor to the given value. + * + * This method has the following method signatures: + * (keyOrList, callback) + * (keyOrList, direction, callback) + * + * @param {String|Array|Object} keyOrList This can be a string or an array. If passed as a string, the string will be the field to sort. If passed an array, each element will represent a field to be sorted and should be an array that contains the format [string, direction]. + * @param {String|Number} direction this determines how the results are sorted. "asc", "ascending" or 1 for asceding order while "desc", "desceding or -1 for descending order. Note that the strings are case insensitive. + * @param {Function} callback this will be called after executing this method. The first parameter will contain an error object when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution. + * @return {Cursor} an instance of this object. + * @api public + */ +Cursor.prototype.sort = function(keyOrList, direction, callback) { + callback = callback || function(){}; + if(typeof direction === "function") { callback = direction; direction = null; } + + if(this.tailable) { + callback(new Error("Tailable cursor doesn't support sorting"), null); + } else if(this.queryRun == true || this.state == Cursor.CLOSED) { + callback(new Error("Cursor is closed"), null); + } else { + var order = keyOrList; + + if(direction != null) { + order = [[keyOrList, direction]]; + } + + this.sortValue = order; + callback(null, this); + } + return this; +}; + +/** + * Sets the limit parameter of this cursor to the given value. + * + * @param {Number} limit the new limit. + * @param {Function} [callback] this optional callback will be called after executing this method. The first parameter will contain an error object when the limit given is not a valid number or when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution. + * @return {Cursor} an instance of this object. + * @api public + */ +Cursor.prototype.limit = function(limit, callback) { + if(this.tailable) { + if(callback) { + callback(new Error("Tailable cursor doesn't support limit"), null); + } else { + throw new Error("Tailable cursor doesn't support limit"); + } + } else if(this.queryRun == true || this.state == Cursor.CLOSED) { + if(callback) { + callback(new Error("Cursor is closed"), null); + } else { + throw new Error("Cursor is closed"); + } + } else { + if(limit != null && limit.constructor != Number) { + if(callback) { + callback(new Error("limit requires an integer"), null); + } else { + throw new Error("limit requires an integer"); + } + } else { + this.limitValue = limit; + if(callback) return callback(null, this); + } + } + + return this; +}; + +/** + * Sets the read preference for the cursor + * + * @param {String} the read preference for the cursor, one of Server.READ_PRIMARY, Server.READ_SECONDARY, Server.READ_SECONDARY_ONLY + * @param {Function} [callback] this optional callback will be called after executing this method. The first parameter will contain an error object when the read preference given is not a valid number or when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution. + * @return {Cursor} an instance of this object. + * @api public + */ +Cursor.prototype.setReadPreference = function(readPreference, tags, callback) { + if(typeof tags == 'function') callback = tags; + + var _mode = readPreference != null && typeof readPreference == 'object' ? readPreference.mode : readPreference; + + if(this.queryRun == true || this.state == Cursor.CLOSED) { + if(callback == null) throw new Error("Cannot change read preference on executed query or closed cursor"); + callback(new Error("Cannot change read preference on executed query or closed cursor")); + } else if(_mode != null && _mode != 'primary' + && _mode != 'secondaryOnly' && _mode != 'secondary' + && _mode != 'nearest' && _mode != 'primaryPreferred' && _mode != 'secondaryPreferred') { + if(callback == null) throw new Error("only readPreference of primary, secondary, secondaryPreferred, primaryPreferred or nearest supported"); + callback(new Error("only readPreference of primary, secondary, secondaryPreferred, primaryPreferred or nearest supported")); + } else { + this.read = readPreference; + if(callback != null) callback(null, this); + } + + return this; +} + +/** + * Sets the skip parameter of this cursor to the given value. + * + * @param {Number} skip the new skip value. + * @param {Function} [callback] this optional callback will be called after executing this method. The first parameter will contain an error object when the skip value given is not a valid number or when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution. + * @return {Cursor} an instance of this object. + * @api public + */ +Cursor.prototype.skip = function(skip, callback) { + callback = callback || function(){}; + + if(this.tailable) { + callback(new Error("Tailable cursor doesn't support skip"), null); + } else if(this.queryRun == true || this.state == Cursor.CLOSED) { + callback(new Error("Cursor is closed"), null); + } else { + if(skip != null && skip.constructor != Number) { + callback(new Error("skip requires an integer"), null); + } else { + this.skipValue = skip; + callback(null, this); + } + } + + return this; +}; + +/** + * Sets the batch size parameter of this cursor to the given value. + * + * @param {Number} batchSize the new batch size. + * @param {Function} [callback] this optional callback will be called after executing this method. The first parameter will contain an error object when the batchSize given is not a valid number or when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution. + * @return {Cursor} an instance of this object. + * @api public + */ +Cursor.prototype.batchSize = function(batchSize, callback) { + if(this.state == Cursor.CLOSED) { + if(callback != null) { + return callback(new Error("Cursor is closed"), null); + } else { + throw new Error("Cursor is closed"); + } + } else if(batchSize != null && batchSize.constructor != Number) { + if(callback != null) { + return callback(new Error("batchSize requires an integer"), null); + } else { + throw new Error("batchSize requires an integer"); + } + } else { + this.batchSizeValue = batchSize; + if(callback != null) return callback(null, this); + } + + return this; +}; + +/** + * The limit used for the getMore command + * + * @return {Number} The number of records to request per batch. + * @ignore + * @api private + */ +var limitRequest = function(self) { + var requestedLimit = self.limitValue; + var absLimitValue = Math.abs(self.limitValue); + var absBatchValue = Math.abs(self.batchSizeValue); + + if(absLimitValue > 0) { + if (absBatchValue > 0) { + requestedLimit = Math.min(absLimitValue, absBatchValue); + } + } else { + requestedLimit = self.batchSizeValue; + } + + return requestedLimit; +}; + + +/** + * Generates a QueryCommand object using the parameters of this cursor. + * + * @return {QueryCommand} The command object + * @ignore + * @api private + */ +var generateQueryCommand = function(self) { + // Unpack the options + var queryOptions = QueryCommand.OPTS_NONE; + if(!self.timeout) { + queryOptions |= QueryCommand.OPTS_NO_CURSOR_TIMEOUT; + } + + if(self.tailable != null) { + queryOptions |= QueryCommand.OPTS_TAILABLE_CURSOR; + self.skipValue = self.limitValue = 0; + + // if awaitdata is set + if(self.awaitdata != null) { + queryOptions |= QueryCommand.OPTS_AWAIT_DATA; + } + } + + if(self.exhaust) { + queryOptions |= QueryCommand.OPTS_EXHAUST; + } + + // Unpack the read preference to set slave ok correctly + var read = self.read instanceof ReadPreference ? self.read.mode : self.read; + + // if(self.read == 'secondary') + if(read == ReadPreference.PRIMARY_PREFERRED + || read == ReadPreference.SECONDARY + || read == ReadPreference.SECONDARY_PREFERRED + || read == ReadPreference.NEAREST) { + queryOptions |= QueryCommand.OPTS_SLAVE; + } + + // Override slaveOk from the user + if(self.slaveOk) { + queryOptions |= QueryCommand.OPTS_SLAVE; + } + + if(self.partial) { + queryOptions |= QueryCommand.OPTS_PARTIAL; + } + + // limitValue of -1 is a special case used by Db#eval + var numberToReturn = self.limitValue == -1 ? -1 : limitRequest(self); + + // Check if we need a special selector + if(self.sortValue != null || self.explainValue != null || self.hint != null || self.snapshot != null + || self.returnKey != null || self.maxScan != null || self.min != null || self.max != null + || self.showDiskLoc != null || self.comment != null) { + + // Build special selector + var specialSelector = {'$query':self.selector}; + if(self.sortValue != null) specialSelector['orderby'] = utils.formattedOrderClause(self.sortValue); + if(self.hint != null && self.hint.constructor == Object) specialSelector['$hint'] = self.hint; + if(self.snapshot != null) specialSelector['$snapshot'] = true; + if(self.returnKey != null) specialSelector['$returnKey'] = self.returnKey; + if(self.maxScan != null) specialSelector['$maxScan'] = self.maxScan; + if(self.min != null) specialSelector['$min'] = self.min; + if(self.max != null) specialSelector['$max'] = self.max; + if(self.showDiskLoc != null) specialSelector['$showDiskLoc'] = self.showDiskLoc; + if(self.comment != null) specialSelector['$comment'] = self.comment; + // If we have explain set only return a single document with automatic cursor close + if(self.explainValue != null) { + numberToReturn = (-1)*Math.abs(numberToReturn); + specialSelector['$explain'] = true; + } + + // Return the query + return new QueryCommand(self.db, self.collectionName, queryOptions, self.skipValue, numberToReturn, specialSelector, self.fields); + } else { + return new QueryCommand(self.db, self.collectionName, queryOptions, self.skipValue, numberToReturn, self.selector, self.fields); + } +}; + +/** + * @return {Object} Returns an object containing the sort value of this cursor with + * the proper formatting that can be used internally in this cursor. + * @ignore + * @api private + */ +Cursor.prototype.formattedOrderClause = function() { + return utils.formattedOrderClause(this.sortValue); +}; + +/** + * Converts the value of the sort direction into its equivalent numerical value. + * + * @param sortDirection {String|number} Range of acceptable values: + * 'ascending', 'descending', 'asc', 'desc', 1, -1 + * + * @return {number} The equivalent numerical value + * @throws Error if the given sortDirection is invalid + * @ignore + * @api private + */ +Cursor.prototype.formatSortValue = function(sortDirection) { + return utils.formatSortValue(sortDirection); +}; + +/** + * Gets the next document from the cursor. + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain an error object on error while the second parameter will contain a document from the returned result or null if there are no more results. + * @api public + */ +Cursor.prototype.nextObject = function(options, callback) { + var self = this; + + if(typeof options == 'function') { + callback = options; + options = {}; + } + + if(self.state == Cursor.INIT) { + var cmd; + try { + cmd = generateQueryCommand(self); + } catch (err) { + return callback(err, null); + } + + var queryOptions = {exhaust: self.exhaust, raw:self.raw, read:self.read, connection:self.connection}; + // Execute command + var commandHandler = function(err, result) { + // If on reconnect, the command got given a different connection, switch + // the whole cursor to it. + self.connection = queryOptions.connection; + self.state = Cursor.OPEN; + if(err != null && result == null) return callback(utils.toError(err), null); + + if(err == null && (result == null || result.documents == null || !Array.isArray(result.documents))) { + return self.close(function() {callback(new Error("command failed to return results"), null);}); + } + + if(err == null && result && result.documents[0] && result.documents[0]['$err']) { + return self.close(function() {callback(utils.toError(result.documents[0]['$err']), null);}); + } + + self.queryRun = true; + self.state = Cursor.OPEN; // Adjust the state of the cursor + self.cursorId = result.cursorId; + self.totalNumberOfRecords = result.numberReturned; + + // Add the new documents to the list of items, using forloop to avoid + // new array allocations and copying + for(var i = 0; i < result.documents.length; i++) { + self.items.push(result.documents[i]); + } + + // If we have noReturn set just return (not modifying the internal item list) + // used for toArray + if(options.noReturn) { + return callback(null, true); + } + + // Ignore callbacks until the cursor is dead for exhausted + if(self.exhaust && result.cursorId.toString() == "0") { + self.nextObject(callback); + } else if(self.exhaust == false || self.exhaust == null) { + self.nextObject(callback); + } + }; + + // If we have no connection set on this cursor check one out + if(self.connection == null) { + try { + self.connection = self.db.serverConfig.checkoutReader(this.read); + // Add to the query options + queryOptions.connection = self.connection; + } catch(err) { + return callback(utils.toError(err), null); + } + } + + // Execute the command + self.db._executeQueryCommand(cmd, queryOptions, commandHandler); + // Set the command handler to null + commandHandler = null; + } else if(self.items.length) { + callback(null, self.items.shift()); + } else if(self.cursorId.greaterThan(Long.fromInt(0))) { + getMore(self, callback); + } else { + // Force cursor to stay open + return self.close(function() {callback(null, null);}); + } +} + +/** + * Gets more results from the database if any. + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain an error object on error while the second parameter will contain a document from the returned result or null if there are no more results. + * @ignore + * @api private + */ +var getMore = function(self, options, callback) { + var limit = 0; + + if(typeof options == 'function') { + callback = options; + options = {}; + } + + if(self.state == Cursor.GET_MORE) return callback(null, null); + + // Set get more in progress + self.state = Cursor.GET_MORE; + + // Set options + if (!self.tailable && self.limitValue > 0) { + limit = self.limitValue - self.totalNumberOfRecords; + if (limit < 1) { + self.close(function() {callback(null, null);}); + return; + } + } + + try { + var getMoreCommand = new GetMoreCommand( + self.db + , self.collectionName + , limitRequest(self) + , self.cursorId + ); + + // Set up options + var command_options = {read: self.read, raw: self.raw, connection:self.connection }; + + // Execute the command + self.db._executeQueryCommand(getMoreCommand, command_options, function(err, result) { + var cbValue; + + // Get more done + self.state = Cursor.OPEN; + + if(err != null) { + self.state = Cursor.CLOSED; + return callback(utils.toError(err), null); + } + + // Ensure we get a valid result + if(!result || !result.documents) { + self.state = Cursor.CLOSED; + return callback(utils.toError("command failed to return results"), null) + } + + // If the QueryFailure flag is set + if((result.responseFlag & (1 << 1)) != 0) { + self.state = Cursor.CLOSED; + return callback(utils.toError("QueryFailure flag set on getmore command"), null); + } + + try { + var isDead = 1 === result.responseFlag && result.cursorId.isZero(); + + self.cursorId = result.cursorId; + self.totalNumberOfRecords += result.numberReturned; + + // Determine if there's more documents to fetch + if(result.numberReturned > 0) { + if (self.limitValue > 0) { + var excessResult = self.totalNumberOfRecords - self.limitValue; + + if (excessResult > 0) { + result.documents.splice(-1 * excessResult, excessResult); + } + } + + // Reset the tries for awaitdata if we are using it + self.currentNumberOfRetries = self.numberOfRetries; + // Get the documents + for(var i = 0; i < result.documents.length; i++) { + self.items.push(result.documents[i]); + } + + // Don's shift a document out as we need it for toArray + if(options.noReturn) { + cbValue = true; + } else { + cbValue = self.items.shift(); + } + } else if(self.tailable && !isDead && self.awaitdata) { + // Excute the tailable cursor once more, will timeout after ~4 sec if awaitdata used + self.currentNumberOfRetries = self.currentNumberOfRetries - 1; + if(self.currentNumberOfRetries == 0) { + self.close(function() { + callback(new Error("tailable cursor timed out"), null); + }); + } else { + getMore(self, callback); + } + } else if(self.tailable && !isDead) { + self.getMoreTimer = setTimeout(function() { getMore(self, callback); }, self.tailableRetryInterval); + } else { + self.close(function() {callback(null, null); }); + } + + result = null; + } catch(err) { + callback(utils.toError(err), null); + } + if (cbValue != null) callback(null, cbValue); + }); + + getMoreCommand = null; + } catch(err) { + // Get more done + self.state = Cursor.OPEN; + + var handleClose = function() { + callback(utils.toError(err), null); + }; + + self.close(handleClose); + handleClose = null; + } +} + +/** + * Gets a detailed information about how the query is performed on this cursor and how + * long it took the database to process it. + * + * @param {Function} callback this will be called after executing this method. The first parameter will always be null while the second parameter will be an object containing the details. + * @api public + */ +Cursor.prototype.explain = function(callback) { + var limit = (-1)*Math.abs(this.limitValue); + + // Create a new cursor and fetch the plan + var cursor = new Cursor(this.db, this.collection, this.selector, this.fields, { + skip: this.skipValue + , limit:limit + , sort: this.sortValue + , hint: this.hint + , explain: true + , snapshot: this.snapshot + , timeout: this.timeout + , tailable: this.tailable + , batchSize: this.batchSizeValue + , slaveOk: this.slaveOk + , raw: this.raw + , read: this.read + , returnKey: this.returnKey + , maxScan: this.maxScan + , min: this.min + , max: this.max + , showDiskLoc: this.showDiskLoc + , comment: this.comment + , awaitdata: this.awaitdata + , numberOfRetries: this.numberOfRetries + , dbName: this.dbName + }); + + // Fetch the explaination document + cursor.nextObject(function(err, item) { + if(err != null) return callback(utils.toError(err), null); + // close the cursor + cursor.close(function(err, result) { + if(err != null) return callback(utils.toError(err), null); + callback(null, item); + }); + }); +}; + +/** + * Returns a Node ReadStream interface for this cursor. + * + * Options + * - **transform** {Function} function of type function(object) { return transformed }, allows for transformation of data before emitting. + * + * @return {CursorStream} returns a stream object. + * @api public + */ +Cursor.prototype.stream = function stream(options) { + return new CursorStream(this, options); +} + +/** + * Close the cursor. + * + * @param {Function} callback this will be called after executing this method. The first parameter will always contain null while the second parameter will contain a reference to this cursor. + * @return {null} + * @api public + */ +Cursor.prototype.close = function(callback) { + var self = this + this.getMoreTimer && clearTimeout(this.getMoreTimer); + // Close the cursor if not needed + if(this.cursorId instanceof Long && this.cursorId.greaterThan(Long.fromInt(0))) { + try { + var command = new KillCursorCommand(this.db, [this.cursorId]); + // Added an empty callback to ensure we don't throw any null exceptions + this.db._executeQueryCommand(command, {read:self.read, raw:self.raw, connection:self.connection}); + } catch(err) {} + } + + // Null out the connection + self.connection = null; + // Reset cursor id + this.cursorId = Long.fromInt(0); + // Set to closed status + this.state = Cursor.CLOSED; + + if(callback) { + callback(null, self); + self.items = []; + } + + return this; +}; + +/** + * Check if the cursor is closed or open. + * + * @return {Boolean} returns the state of the cursor. + * @api public + */ +Cursor.prototype.isClosed = function() { + return this.state == Cursor.CLOSED ? true : false; +}; + +/** + * Init state + * + * @classconstant INIT + **/ +Cursor.INIT = 0; + +/** + * Cursor open + * + * @classconstant OPEN + **/ +Cursor.OPEN = 1; + +/** + * Cursor closed + * + * @classconstant CLOSED + **/ +Cursor.CLOSED = 2; + +/** + * Cursor performing a get more + * + * @classconstant OPEN + **/ +Cursor.GET_MORE = 3; + +/** + * @ignore + * @api private + */ +exports.Cursor = Cursor; diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/cursorstream.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/cursorstream.js new file mode 100644 index 0000000..90b425b --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/cursorstream.js @@ -0,0 +1,164 @@ +var timers = require('timers'); + +// Set processor, setImmediate if 0.10 otherwise nextTick +var processor = require('./utils').processor(); + +/** + * Module dependecies. + */ +var Stream = require('stream').Stream; + +/** + * CursorStream + * + * Returns a stream interface for the **cursor**. + * + * Options + * - **transform** {Function} function of type function(object) { return transformed }, allows for transformation of data before emitting. + * + * Events + * - **data** {function(item) {}} the data event triggers when a document is ready. + * - **error** {function(err) {}} the error event triggers if an error happens. + * - **close** {function() {}} the end event triggers when there is no more documents available. + * + * @class Represents a CursorStream. + * @param {Cursor} cursor a cursor object that the stream wraps. + * @return {Stream} + */ +function CursorStream(cursor, options) { + if(!(this instanceof CursorStream)) return new CursorStream(cursor); + options = options ? options : {}; + + Stream.call(this); + + this.readable = true; + this.paused = false; + this._cursor = cursor; + this._destroyed = null; + this.options = options; + + // give time to hook up events + var self = this; + process.nextTick(function() { + self._init(); + }); +} + +/** + * Inherit from Stream + * @ignore + * @api private + */ +CursorStream.prototype.__proto__ = Stream.prototype; + +/** + * Flag stating whether or not this stream is readable. + */ +CursorStream.prototype.readable; + +/** + * Flag stating whether or not this stream is paused. + */ +CursorStream.prototype.paused; + +/** + * Initialize the cursor. + * @ignore + * @api private + */ +CursorStream.prototype._init = function () { + if (this._destroyed) return; + this._next(); +} + +/** + * Pull the next document from the cursor. + * @ignore + * @api private + */ +CursorStream.prototype._next = function () { + if(this.paused || this._destroyed) return; + + var self = this; + // Get the next object + processor(function() { + if(self.paused || self._destroyed) return; + + self._cursor.nextObject(function (err, doc) { + self._onNextObject(err, doc); + }); + }); +} + +/** + * Handle each document as its returned from the cursor. + * @ignore + * @api private + */ +CursorStream.prototype._onNextObject = function (err, doc) { + if(err) return this.destroy(err); + + // when doc is null we hit the end of the cursor + if(!doc && (this._cursor.state == 1 || this._cursor.state == 2)) { + this.emit('end') + return this.destroy(); + } else if(doc) { + var data = typeof this.options.transform == 'function' ? this.options.transform(doc) : doc; + this.emit('data', data); + this._next(); + } +} + +/** + * Pauses the stream. + * + * @api public + */ +CursorStream.prototype.pause = function () { + this.paused = true; +} + +/** + * Resumes the stream. + * + * @api public + */ +CursorStream.prototype.resume = function () { + var self = this; + + // Don't do anything if we are not paused + if(!this.paused) return; + if(!this._cursor.state == 3) return; + + process.nextTick(function() { + self.paused = false; + // Only trigger more fetching if the cursor is open + self._next(); + }) +} + +/** + * Destroys the stream, closing the underlying + * cursor. No more events will be emitted. + * + * @api public + */ +CursorStream.prototype.destroy = function (err) { + if (this._destroyed) return; + this._destroyed = true; + this.readable = false; + + this._cursor.close(); + + if(err) { + this.emit('error', err); + } + + this.emit('close'); +} + +// TODO - maybe implement the raw option to pass binary? +//CursorStream.prototype.setEncoding = function () { +//} + +module.exports = exports = CursorStream; diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/db.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/db.js new file mode 100644 index 0000000..7dc2e47 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/db.js @@ -0,0 +1,1954 @@ +/** + * Module dependencies. + * @ignore + */ +var QueryCommand = require('./commands/query_command').QueryCommand + , DbCommand = require('./commands/db_command').DbCommand + , MongoReply = require('./responses/mongo_reply').MongoReply + , Admin = require('./admin').Admin + , Collection = require('./collection').Collection + , Server = require('./connection/server').Server + , ReplSet = require('./connection/repl_set/repl_set').ReplSet + , ReadPreference = require('./connection/read_preference').ReadPreference + , Mongos = require('./connection/mongos').Mongos + , Cursor = require('./cursor').Cursor + , EventEmitter = require('events').EventEmitter + , inherits = require('util').inherits + , crypto = require('crypto') + , timers = require('timers') + , utils = require('./utils') + , mongodb_cr_authenticate = require('./auth/mongodb_cr.js').authenticate + , mongodb_gssapi_authenticate = require('./auth/mongodb_gssapi.js').authenticate + , mongodb_sspi_authenticate = require('./auth/mongodb_sspi.js').authenticate + , mongodb_plain_authenticate = require('./auth/mongodb_plain.js').authenticate; + +var hasKerberos = false; +// Check if we have a the kerberos library +try { + require('kerberos'); + hasKerberos = true; +} catch(err) {} + +// Set processor, setImmediate if 0.10 otherwise nextTick +var processor = require('./utils').processor(); + +/** + * Create a new Db instance. + * + * Options + * - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST). + * - **native_parser** {Boolean, default:false}, use c++ bson parser. + * - **forceServerObjectId** {Boolean, default:false}, force server to create _id fields instead of client. + * - **pkFactory** {Object}, object overriding the basic ObjectID primary key generation. + * - **serializeFunctions** {Boolean, default:false}, serialize functions. + * - **raw** {Boolean, default:false}, peform operations using raw bson buffers. + * - **recordQueryStats** {Boolean, default:false}, record query statistics during execution. + * - **retryMiliSeconds** {Number, default:5000}, number of miliseconds between retries. + * - **numberOfRetries** {Number, default:5}, number of retries off connection. + * - **logger** {Object, default:null}, an object representing a logger that you want to use, needs to support functions debug, log, error **({error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}})**. + * - **slaveOk** {Number, default:null}, force setting of SlaveOk flag on queries (only use when explicitly connecting to a secondary server). + * - **promoteLongs** {Boolean, default:true}, when deserializing a Long will fit it into a Number if it's smaller than 53 bits + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @class Represents a Db + * @param {String} databaseName name of the database. + * @param {Object} serverConfig server config object. + * @param {Object} [options] additional options for the collection. + */ +function Db(databaseName, serverConfig, options) { + if(!(this instanceof Db)) return new Db(databaseName, serverConfig, options); + EventEmitter.call(this); + + var self = this; + this.databaseName = databaseName; + this.serverConfig = serverConfig; + this.options = options == null ? {} : options; + // State to check against if the user force closed db + this._applicationClosed = false; + // Fetch the override flag if any + var overrideUsedFlag = this.options['override_used_flag'] == null ? false : this.options['override_used_flag']; + + // Verify that nobody is using this config + if(!overrideUsedFlag && this.serverConfig != null && typeof this.serverConfig == 'object' && this.serverConfig._isUsed && this.serverConfig._isUsed()) { + throw new Error("A Server or ReplSet instance cannot be shared across multiple Db instances"); + } else if(!overrideUsedFlag && typeof this.serverConfig == 'object'){ + // Set being used + this.serverConfig._used = true; + } + + // Allow slaveOk override + this.slaveOk = this.options["slave_ok"] == null ? false : this.options["slave_ok"]; + this.slaveOk = this.options["slaveOk"] == null ? this.slaveOk : this.options["slaveOk"]; + + // Ensure we have a valid db name + validateDatabaseName(databaseName); + + // Contains all the connections for the db + try { + this.native_parser = this.options.native_parser; + // The bson lib + var bsonLib = this.bsonLib = this.options.native_parser ? require('bson').BSONNative : require('bson').BSONPure; + // Fetch the serializer object + var BSON = bsonLib.BSON; + + // Create a new instance + this.bson = new BSON([bsonLib.Long, bsonLib.ObjectID, bsonLib.Binary, bsonLib.Code, bsonLib.DBRef, bsonLib.Symbol, bsonLib.Double, bsonLib.Timestamp, bsonLib.MaxKey, bsonLib.MinKey]); + this.bson.promoteLongs = this.options.promoteLongs == null ? true : this.options.promoteLongs; + + // Backward compatibility to access types + this.bson_deserializer = bsonLib; + this.bson_serializer = bsonLib; + + // Add any overrides to the serializer and deserializer + this.bson_deserializer.promoteLongs = this.options.promoteLongs == null ? true : this.options.promoteLongs; + } catch (err) { + // If we tried to instantiate the native driver + var msg = "Native bson parser not compiled, please compile " + + "or avoid using native_parser=true"; + throw Error(msg); + } + + // Internal state of the server + this._state = 'disconnected'; + + this.pkFactory = this.options.pk == null ? bsonLib.ObjectID : this.options.pk; + this.forceServerObjectId = this.options.forceServerObjectId != null ? this.options.forceServerObjectId : false; + + // Added safe + this.safe = this.options.safe == null ? false : this.options.safe; + + // If we have not specified a "safe mode" we just print a warning to the console + if(this.options.safe == null && this.options.w == null && this.options.journal == null && this.options.fsync == null) { + console.log("========================================================================================"); + console.log("= Please ensure that you set the default write concern for the database by setting ="); + console.log("= one of the options ="); + console.log("= ="); + console.log("= w: (value of > -1 or the string 'majority'), where < 1 means ="); + console.log("= no write acknowlegement ="); + console.log("= journal: true/false, wait for flush to journal before acknowlegement ="); + console.log("= fsync: true/false, wait for flush to file system before acknowlegement ="); + console.log("= ="); + console.log("= For backward compatibility safe is still supported and ="); + console.log("= allows values of [true | false | {j:true} | {w:n, wtimeout:n} | {fsync:true}] ="); + console.log("= the default value is false which means the driver receives does not ="); + console.log("= return the information of the success/error of the insert/update/remove ="); + console.log("= ="); + console.log("= ex: new Db(new Server('localhost', 27017), {safe:false}) ="); + console.log("= ="); + console.log("= http://www.mongodb.org/display/DOCS/getLastError+Command ="); + console.log("= ="); + console.log("= The default of no acknowlegement will change in the very near future ="); + console.log("= ="); + console.log("= This message will disappear when the default safe is set on the driver Db ="); + console.log("========================================================================================"); + } + + // Internal states variables + this.notReplied ={}; + this.isInitializing = true; + this.openCalled = false; + + // Command queue, keeps a list of incoming commands that need to be executed once the connection is up + this.commands = []; + + // Set up logger + this.logger = this.options.logger != null + && (typeof this.options.logger.debug == 'function') + && (typeof this.options.logger.error == 'function') + && (typeof this.options.logger.log == 'function') + ? this.options.logger : {error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}}; + + // Associate the logger with the server config + this.serverConfig.logger = this.logger; + if(this.serverConfig.strategyInstance) this.serverConfig.strategyInstance.logger = this.logger; + this.tag = new Date().getTime(); + // Just keeps list of events we allow + this.eventHandlers = {error:[], parseError:[], poolReady:[], message:[], close:[]}; + + // Controls serialization options + this.serializeFunctions = this.options.serializeFunctions != null ? this.options.serializeFunctions : false; + + // Raw mode + this.raw = this.options.raw != null ? this.options.raw : false; + + // Record query stats + this.recordQueryStats = this.options.recordQueryStats != null ? this.options.recordQueryStats : false; + + // If we have server stats let's make sure the driver objects have it enabled + if(this.recordQueryStats == true) { + this.serverConfig.enableRecordQueryStats(true); + } + + // Retry information + this.retryMiliSeconds = this.options.retryMiliSeconds != null ? this.options.retryMiliSeconds : 1000; + this.numberOfRetries = this.options.numberOfRetries != null ? this.options.numberOfRetries : 60; + + // Set default read preference if any + this.readPreference = this.options.readPreference; + + // Set read preference on serverConfig if none is set + // but the db one was + if(this.serverConfig.options.readPreference == null + && this.readPreference != null) { + this.serverConfig.setReadPreference(this.readPreference); + } + + // Ensure we keep a reference to this db + this.serverConfig._dbStore.add(this); +}; + +/** + * @ignore + */ +function validateDatabaseName(databaseName) { + if(typeof databaseName !== 'string') throw new Error("database name must be a string"); + if(databaseName.length === 0) throw new Error("database name cannot be the empty string"); + if(databaseName == '$external') return; + + var invalidChars = [" ", ".", "$", "/", "\\"]; + for(var i = 0; i < invalidChars.length; i++) { + if(databaseName.indexOf(invalidChars[i]) != -1) throw new Error("database names cannot contain the character '" + invalidChars[i] + "'"); + } +} + +/** + * @ignore + */ +inherits(Db, EventEmitter); + +/** + * Initialize the database connection. + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the index information or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.open = function(callback) { + var self = this; + + // Check that the user has not called this twice + if(this.openCalled) { + // Close db + this.close(); + // Throw error + throw new Error("db object already connecting, open cannot be called multiple times"); + } + + // If we have a specified read preference + if(this.readPreference != null) this.serverConfig.setReadPreference(this.readPreference); + + // Set that db has been opened + this.openCalled = true; + + // Set the status of the server + self._state = 'connecting'; + + // Set up connections + if(self.serverConfig instanceof Server || self.serverConfig instanceof ReplSet || self.serverConfig instanceof Mongos) { + // Ensure we have the original options passed in for the server config + var connect_options = {}; + for(var name in self.serverConfig.options) { + connect_options[name] = self.serverConfig.options[name] + } + connect_options.firstCall = true; + + // Attempt to connect + self.serverConfig.connect(self, connect_options, function(err, result) { + if(err != null) { + // Set that db has been closed + self.openCalled = false; + // Return error from connection + return callback(err, null); + } + // Set the status of the server + self._state = 'connected'; + // If we have queued up commands execute a command to trigger replays + if(self.commands.length > 0) _execute_queued_command(self); + // Callback + process.nextTick(function() { + try { + callback(null, self); + } catch(err) { + self.close(); + throw err; + } + }); + }); + } else { + try { + callback(Error("Server parameter must be of type Server, ReplSet or Mongos"), null); + } catch(err) { + self.close(); + throw err; + } + } +}; + +/** + * Create a new Db instance sharing the current socket connections. + * + * @param {String} dbName the name of the database we want to use. + * @return {Db} a db instance using the new database. + * @api public + */ +Db.prototype.db = function(dbName) { + // Copy the options and add out internal override of the not shared flag + var options = {}; + for(var key in this.options) { + options[key] = this.options[key]; + } + + // Add override flag + options['override_used_flag'] = true; + // Check if the db already exists and reuse if it's the case + var db = this.serverConfig._dbStore.fetch(dbName); + + // Create a new instance + if(!db) { + db = new Db(dbName, this.serverConfig, options); + } + + // Return the db object + return db; +} + +/** + * Close the current db connection, including all the child db instances. Emits close event if no callback is provided. + * + * @param {Boolean} [forceClose] connection can never be reused. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.close = function(forceClose, callback) { + var self = this; + // Ensure we force close all connections + this._applicationClosed = false; + + if(typeof forceClose == 'function') { + callback = forceClose; + } else if(typeof forceClose == 'boolean') { + this._applicationClosed = forceClose; + } + + this.serverConfig.close(function(err, result) { + // You can reuse the db as everything is shut down + self.openCalled = false; + // If we have a callback call it + if(callback) callback(err, result); + }); +}; + +/** + * Access the Admin database + * + * @param {Function} [callback] returns the results. + * @return {Admin} the admin db object. + * @api public + */ +Db.prototype.admin = function(callback) { + if(callback == null) return new Admin(this); + callback(null, new Admin(this)); +}; + +/** + * Returns a cursor to all the collection information. + * + * @param {String} [collectionName] the collection name we wish to retrieve the information from. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the options or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.collectionsInfo = function(collectionName, callback) { + if(callback == null && typeof collectionName == 'function') { callback = collectionName; collectionName = null; } + // Create selector + var selector = {}; + // If we are limiting the access to a specific collection name + if(collectionName != null) selector.name = this.databaseName + "." + collectionName; + + // Return Cursor + // callback for backward compatibility + if(callback) { + callback(null, new Cursor(this, new Collection(this, DbCommand.SYSTEM_NAMESPACE_COLLECTION), selector)); + } else { + return new Cursor(this, new Collection(this, DbCommand.SYSTEM_NAMESPACE_COLLECTION), selector); + } +}; + +/** + * Get the list of all collection names for the specified db + * + * Options + * - **namesOnly** {String, default:false}, Return only the full collection namespace. + * + * @param {String} [collectionName] the collection name we wish to filter by. + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the collection names or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.collectionNames = function(collectionName, options, callback) { + var self = this; + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + collectionName = args.length ? args.shift() : null; + options = args.length ? args.shift() || {} : {}; + + // Ensure no breaking behavior + if(collectionName != null && typeof collectionName == 'object') { + options = collectionName; + collectionName = null; + } + + // Let's make our own callback to reuse the existing collections info method + self.collectionsInfo(collectionName, function(err, cursor) { + if(err != null) return callback(err, null); + + cursor.toArray(function(err, documents) { + if(err != null) return callback(err, null); + + // List of result documents that have been filtered + var filtered_documents = documents.filter(function(document) { + return !(document.name.indexOf(self.databaseName) == -1 || document.name.indexOf('$') != -1); + }); + + // If we are returning only the names + if(options.namesOnly) { + filtered_documents = filtered_documents.map(function(document) { return document.name }); + } + + // Return filtered items + callback(null, filtered_documents); + }); + }); +}; + +/** + * Fetch a specific collection (containing the actual collection information). If the application does not use strict mode you can + * can use it without a callback in the following way. var collection = db.collection('mycollection'); + * + * Options +* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * - **serializeFunctions** {Boolean, default:false}, serialize functions on the document. + * - **raw** {Boolean, default:false}, perform all operations using raw bson objects. + * - **pkFactory** {Object}, object overriding the basic ObjectID primary key generation. + * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST). + * - **strict**, (Boolean, default:false) returns an error if the collection does not exist + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @param {String} collectionName the collection name we wish to access. + * @param {Object} [options] returns option results. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the collection or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.collection = function(collectionName, options, callback) { + var self = this; + if(typeof options === "function") { callback = options; options = {}; } + // Execute safe + + if(options && (options.strict)) { + self.collectionNames(collectionName, function(err, collections) { + if(err != null) return callback(err, null); + + if(collections.length == 0) { + return callback(new Error("Collection " + collectionName + " does not exist. Currently in safe mode."), null); + } else { + try { + var collection = new Collection(self, collectionName, self.pkFactory, options); + } catch(err) { + return callback(err, null); + } + return callback(null, collection); + } + }); + } else { + try { + var collection = new Collection(self, collectionName, self.pkFactory, options); + } catch(err) { + if(callback == null) { + throw err; + } else { + return callback(err, null); + } + } + + // If we have no callback return collection object + return callback == null ? collection : callback(null, collection); + } +}; + +/** + * Fetch all collections for the current db. + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the collections or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.collections = function(callback) { + var self = this; + // Let's get the collection names + self.collectionNames(function(err, documents) { + if(err != null) return callback(err, null); + var collections = []; + documents.forEach(function(document) { + collections.push(new Collection(self, document.name.replace(self.databaseName + ".", ''), self.pkFactory)); + }); + // Return the collection objects + callback(null, collections); + }); +}; + +/** + * Evaluate javascript on the server + * + * Options + * - **nolock** {Boolean, default:false}, Tell MongoDB not to block on the evaulation of the javascript. + * + * @param {Code} code javascript to execute on server. + * @param {Object|Array} [parameters] the parameters for the call. + * @param {Object} [options] the options + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from eval or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.eval = function(code, parameters, options, callback) { + // Unpack calls + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + parameters = args.length ? args.shift() : parameters; + options = args.length ? args.shift() || {} : {}; + + var finalCode = code; + var finalParameters = []; + // If not a code object translate to one + if(!(finalCode instanceof this.bsonLib.Code)) { + finalCode = new this.bsonLib.Code(finalCode); + } + + // Ensure the parameters are correct + if(parameters != null && parameters.constructor != Array && typeof parameters !== 'function') { + finalParameters = [parameters]; + } else if(parameters != null && parameters.constructor == Array && typeof parameters !== 'function') { + finalParameters = parameters; + } + + // Create execution selector + var selector = {'$eval':finalCode, 'args':finalParameters}; + // Check if the nolock parameter is passed in + if(options['nolock']) { + selector['nolock'] = options['nolock']; + } + + // Set primary read preference + options.readPreference = ReadPreference.PRIMARY; + + // Execute the eval + this.collection(DbCommand.SYSTEM_COMMAND_COLLECTION).findOne(selector, options, function(err, result) { + if(err) return callback(err); + + if(result && result.ok == 1) { + callback(null, result.retval); + } else if(result) { + callback(new Error("eval failed: " + result.errmsg), null); return; + } else { + callback(err, result); + } + }); +}; + +/** + * Dereference a dbref, against a db + * + * @param {DBRef} dbRef db reference object we wish to resolve. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from dereference or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.dereference = function(dbRef, callback) { + var db = this; + // If we have a db reference then let's get the db first + if(dbRef.db != null) db = this.db(dbRef.db); + // Fetch the collection and find the reference + var collection = db.collection(dbRef.namespace); + collection.findOne({'_id':dbRef.oid}, function(err, result) { + callback(err, result); + }); +}; + +/** + * Logout user from server, fire off on all connections and remove all auth info + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from logout or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.logout = function(options, callback) { + var self = this; + // Unpack calls + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + options = args.length ? args.shift() || {} : {}; + + // Number of connections we need to logout from + var numberOfConnections = this.serverConfig.allRawConnections().length; + + // Let's generate the logout command object + var logoutCommand = DbCommand.logoutCommand(self, {logout:1}, options); + self._executeQueryCommand(logoutCommand, {onAll:true}, function(err, result) { + // Count down + numberOfConnections = numberOfConnections - 1; + // Work around the case where the number of connections are 0 + if(numberOfConnections <= 0 && typeof callback == 'function') { + var internalCallback = callback; + callback = null; + + // Remove the db from auths + self.serverConfig.auth.remove(self.databaseName); + + // Handle error result + utils.handleSingleCommandResultReturn(true, false, internalCallback)(err, result); + } + }); +} + +/** + * Authenticate a user against the server. + * authMechanism + * Options + * - **authSource** {String}, The database that the credentials are for, + * different from the name of the current DB, for example admin + * - **authMechanism** {String, default:MONGODB-CR}, The authentication mechanism to use, GSSAPI or MONGODB-CR + * + * @param {String} username username. + * @param {String} password password. + * @param {Object} [options] the options + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from authentication or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.authenticate = function(username, password, options, callback) { + var self = this; + + if(typeof callback === 'undefined') { + callback = options; + options = {}; + } + + // Set default mechanism + if(!options.authMechanism) { + options.authMechanism = 'MONGODB-CR'; + } else if(options.authMechanism != 'GSSAPI' + && options.authMechanism != 'MONGODB-CR' + && options.authMechanism != 'PLAIN') { + return callback(new Error("only GSSAPI, PLAIN or MONGODB-CR is supported by authMechanism")); + } + + // the default db to authenticate against is 'this' + // if authententicate is called from a retry context, it may be another one, like admin + var authdb = options.authdb ? options.authdb : self.databaseName; + authdb = options.authSource ? options.authSource : authdb; + + // Callback + var _callback = function(err, result) { + if(self.listeners("authenticated").length > 9) { + self.emit("authenticated", err, result); + } + + // Return to caller + callback(err, result); + } + + // If classic auth delegate to auth command + if(options.authMechanism == 'MONGODB-CR') { + mongodb_cr_authenticate(self, username, password, authdb, options, _callback); + } else if(options.authMechanism == 'PLAIN') { + mongodb_plain_authenticate(self, username, password, options, _callback); + } else if(options.authMechanism == 'GSSAPI') { + // + // Kerberos library is not installed, throw and error + if(hasKerberos == false) { + console.log("========================================================================================"); + console.log("= Please make sure that you install the Kerberos library to use GSSAPI ="); + console.log("= ="); + console.log("= npm install -g kerberos ="); + console.log("= ="); + console.log("= The Kerberos package is not installed by default for simplicities sake ="); + console.log("= and needs to be global install ="); + console.log("========================================================================================"); + throw new Error("Kerberos library not installed"); + } + + if(process.platform == 'win32') { + mongodb_sspi_authenticate(self, username, password, authdb, options, _callback); + } else { + // We have the kerberos library, execute auth process + mongodb_gssapi_authenticate(self, username, password, authdb, options, _callback); + } + } +}; + +/** + * Add a user to the database. + * + * Options + * - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @param {String} username username. + * @param {String} password password. + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from addUser or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.addUser = function(username, password, options, callback) { + var self = this; + var args = Array.prototype.slice.call(arguments, 2); + callback = args.pop(); + options = args.length ? args.shift() || {} : {}; + + // Get the error options + var errorOptions = _getWriteConcern(this, options, callback); + errorOptions.w = errorOptions.w == null ? 1 : errorOptions.w; + // Use node md5 generator + var md5 = crypto.createHash('md5'); + // Generate keys used for authentication + md5.update(username + ":mongo:" + password); + var userPassword = md5.digest('hex'); + // Fetch a user collection + var collection = this.collection(DbCommand.SYSTEM_USER_COLLECTION); + // Check if we are inserting the first user + collection.count({}, function(err, count) { + // We got an error (f.ex not authorized) + if(err != null) return callback(err, null); + // Check if the user exists and update i + collection.find({user: username}, {dbName: options['dbName']}).toArray(function(err, documents) { + // We got an error (f.ex not authorized) + if(err != null) return callback(err, null); + // Add command keys + var commandOptions = errorOptions; + commandOptions.dbName = options['dbName']; + commandOptions.upsert = true; + + // We have a user, let's update the password or upsert if not + collection.update({user: username},{$set: {user: username, pwd: userPassword}}, commandOptions, function(err, results) { + if(count == 0 && err) { + callback(null, [{user:username, pwd:userPassword}]); + } else if(err) { + callback(err, null) + } else { + callback(null, [{user:username, pwd:userPassword}]); + } + }); + }); + }); +}; + +/** + * Remove a user from a database + * + * Options +* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @param {String} username username. + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from removeUser or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.removeUser = function(username, options, callback) { + var self = this; + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + options = args.length ? args.shift() || {} : {}; + + // Figure out the safe mode settings + var safe = self.safe != null && self.safe == false ? {w: 1} : self.safe; + // Override with options passed in if applicable + safe = options != null && options['safe'] != null ? options['safe'] : safe; + // Ensure it's at least set to safe + safe = safe == null ? {w: 1} : safe; + + // Fetch a user collection + var collection = this.collection(DbCommand.SYSTEM_USER_COLLECTION); + collection.findOne({user: username}, {dbName: options['dbName']}, function(err, user) { + if(user != null) { + // Add command keys + var commandOptions = safe; + commandOptions.dbName = options['dbName']; + + collection.remove({user: username}, commandOptions, function(err, result) { + callback(err, true); + }); + } else { + callback(err, false); + } + }); +}; + +/** + * Creates a collection on a server pre-allocating space, need to create f.ex capped collections. + * + * Options +* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * - **serializeFunctions** {Boolean, default:false}, serialize functions on the document. + * - **raw** {Boolean, default:false}, perform all operations using raw bson objects. + * - **pkFactory** {Object}, object overriding the basic ObjectID primary key generation. + * - **capped** {Boolean, default:false}, create a capped collection. + * - **size** {Number}, the size of the capped collection in bytes. + * - **max** {Number}, the maximum number of documents in the capped collection. + * - **autoIndexId** {Boolean, default:true}, create an index on the _id field of the document, True by default on MongoDB 2.2 or higher off for version < 2.2. + * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST). + * - **strict**, (Boolean, default:false) throws an error if collection already exists + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @param {String} collectionName the collection name we wish to access. + * @param {Object} [options] returns option results. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from createCollection or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.createCollection = function(collectionName, options, callback) { + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + options = args.length ? args.shift() : null; + var self = this; + + // Figure out the safe mode settings + var safe = self.safe != null && self.safe == false ? {w: 1} : self.safe; + // Override with options passed in if applicable + safe = options != null && options['safe'] != null ? options['safe'] : safe; + // Ensure it's at least set to safe + safe = safe == null ? {w: 1} : safe; + + // Check if we have the name + this.collectionNames(collectionName, function(err, collections) { + if(err != null) return callback(err, null); + + var found = false; + collections.forEach(function(collection) { + if(collection.name == self.databaseName + "." + collectionName) found = true; + }); + + // If the collection exists either throw an exception (if db in safe mode) or return the existing collection + if(found && options && options.strict) { + return callback(new Error("Collection " + collectionName + " already exists. Currently in safe mode."), null); + } else if(found){ + try { + var collection = new Collection(self, collectionName, self.pkFactory, options); + } catch(err) { + return callback(err, null); + } + return callback(null, collection); + } + + // Create a new collection and return it + self._executeQueryCommand(DbCommand.createCreateCollectionCommand(self, collectionName, options) + , {read:false, safe:safe} + , utils.handleSingleCommandResultReturn(null, null, function(err, result) { + if(err) return callback(err, null); + // Create collection and return + try { + return callback(null, new Collection(self, collectionName, self.pkFactory, options)); + } catch(err) { + return callback(err, null); + } + })); + }); +}; + +var _getReadConcern = function(self, options) { + if(options.readPreference) return options.readPreference; + if(self.readPreference) return self.readPreference; + return 'primary'; +} + +/** + * Execute a command hash against MongoDB. This lets you acess any commands not available through the api on the server. + * + * @param {Object} selector the command hash to send to the server, ex: {ping:1}. + * @param {Function} callback this will be called after executing this method. The command always return the whole result of the command as the second parameter. + * @return {null} + * @api public + */ +Db.prototype.command = function(selector, options, callback) { + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + options = args.length ? args.shift() || {} : {}; + // Ignore command preference (I know what I'm doing) + var ignoreCommandFilter = options.ignoreCommandFilter ? options.ignoreCommandFilter : false; + + // Set up the options + var cursor = new Cursor(this + , new Collection(this, DbCommand.SYSTEM_COMMAND_COLLECTION), selector, {}, { + limit: -1, timeout: QueryCommand.OPTS_NO_CURSOR_TIMEOUT, dbName: options['dbName'] + }); + + // Set read preference if we set one + var readPreference = options['readPreference'] ? options['readPreference'] : false; + // If we have a connection passed in + cursor.connection = options.connection; + + // Ensure only commands who support read Prefrences are exeuted otherwise override and use Primary + if(readPreference != false && ignoreCommandFilter == false) { + if(selector['group'] || selector['aggregate'] || selector['collStats'] || selector['dbStats'] + || selector['count'] || selector['distinct'] || selector['geoNear'] || selector['geoSearch'] + || selector['geoWalk'] || selector['text'] + || (selector['mapreduce'] && (selector.out == 'inline' || selector.out.inline))) { + // Set the read preference + cursor.setReadPreference(readPreference); + } else { + cursor.setReadPreference(ReadPreference.PRIMARY); + } + } else if(readPreference != false) { + // Force setting the command filter + cursor.setReadPreference(readPreference); + } + + // Get the next result + cursor.nextObject(function(err, result) { + if(err) return callback(err, null); + if(result == null) return callback(new Error("no result returned from command"), null); + callback(null, result); + }); +}; + +/** + * Drop a collection from the database, removing it permanently. New accesses will create a new collection. + * + * @param {String} collectionName the name of the collection we wish to drop. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from dropCollection or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.dropCollection = function(collectionName, callback) { + var self = this; + callback || (callback = function(){}); + + // Drop the collection + this._executeQueryCommand(DbCommand.createDropCollectionCommand(this, collectionName) + , utils.handleSingleCommandResultReturn(true, false, callback) + ); +}; + +/** + * Rename a collection. + * + * Options + * - **dropTarget** {Boolean, default:false}, drop the target name collection if it previously exists. + * + * @param {String} fromCollection the name of the current collection we wish to rename. + * @param {String} toCollection the new name of the collection. + * @param {Object} [options] returns option results. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from renameCollection or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.renameCollection = function(fromCollection, toCollection, options, callback) { + var self = this; + + if(typeof options == 'function') { + callback = options; + options = {} + } + + // Add return new collection + options.new_collection = true; + + // Execute using the collection method + this.collection(fromCollection).rename(toCollection, options, callback); +}; + +/** + * Return last error message for the given connection, note options can be combined. + * + * Options + * - **fsync** {Boolean, default:false}, option forces the database to fsync all files before returning. + * - **j** {Boolean, default:false}, awaits the journal commit before returning, > MongoDB 2.0. + * - **w** {Number}, until a write operation has been replicated to N servers. + * - **wtimeout** {Number}, number of miliseconds to wait before timing out. + * + * Connection Options + * - **connection** {Connection}, fire the getLastError down a specific connection. + * + * @param {Object} [options] returns option results. + * @param {Object} [connectionOptions] returns option results. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from lastError or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.lastError = function(options, connectionOptions, callback) { + // Unpack calls + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + options = args.length ? args.shift() || {} : {}; + connectionOptions = args.length ? args.shift() || {} : {}; + + this._executeQueryCommand(DbCommand.createGetLastErrorCommand(options, this), connectionOptions, function(err, error) { + callback(err, error && error.documents); + }); +}; + +/** + * Legacy method calls. + * + * @ignore + * @api private + */ +Db.prototype.error = Db.prototype.lastError; +Db.prototype.lastStatus = Db.prototype.lastError; + +/** + * Return all errors up to the last time db reset_error_history was called. + * + * Options + * - **connection** {Connection}, fire the getLastError down a specific connection. + * + * @param {Object} [options] returns option results. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from previousErrors or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.previousErrors = function(options, callback) { + // Unpack calls + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + options = args.length ? args.shift() || {} : {}; + + this._executeQueryCommand(DbCommand.createGetPreviousErrorsCommand(this), options, function(err, error) { + callback(err, error.documents); + }); +}; + +/** + * Runs a command on the database. + * @ignore + * @api private + */ +Db.prototype.executeDbCommand = function(command_hash, options, callback) { + if(callback == null) { callback = options; options = {}; } + this._executeQueryCommand(DbCommand.createDbSlaveOkCommand(this, command_hash, options), options, function(err, result) { + if(callback) callback(err, result); + }); +}; + +/** + * Runs a command on the database as admin. + * @ignore + * @api private + */ +Db.prototype.executeDbAdminCommand = function(command_hash, options, callback) { + if(typeof options == 'function') { + callback = options; + options = {} + } + + if(options.readPreference) { + options.read = options.readPreference; + } + + this._executeQueryCommand(DbCommand.createAdminDbCommand(this, command_hash), options, function(err, result) { + if(callback) callback(err, result); + }); +}; + +/** + * Resets the error history of the mongo instance. + * + * Options + * - **connection** {Connection}, fire the getLastError down a specific connection. + * + * @param {Object} [options] returns option results. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from resetErrorHistory or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.resetErrorHistory = function(options, callback) { + // Unpack calls + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + options = args.length ? args.shift() || {} : {}; + + this._executeQueryCommand(DbCommand.createResetErrorHistoryCommand(this), options, function(err, error) { + if(callback) callback(err, error && error.documents); + }); +}; + +/** + * Creates an index on the collection. + * + * Options +* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * - **unique** {Boolean, default:false}, creates an unique index. + * - **sparse** {Boolean, default:false}, creates a sparse index. + * - **background** {Boolean, default:false}, creates the index in the background, yielding whenever possible. + * - **dropDups** {Boolean, default:false}, a unique index cannot be created on a key that has pre-existing duplicate values. If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value + * - **min** {Number}, for geospatial indexes set the lower bound for the co-ordinates. + * - **max** {Number}, for geospatial indexes set the high bound for the co-ordinates. + * - **v** {Number}, specify the format version of the indexes. + * - **expireAfterSeconds** {Number}, allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher) + * - **name** {String}, override the autogenerated index name (useful if the resulting name is larger than 128 bytes) + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * + * @param {String} collectionName name of the collection to create the index on. + * @param {Object} fieldOrSpec fieldOrSpec that defines the index. + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from createIndex or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.createIndex = function(collectionName, fieldOrSpec, options, callback) { + var self = this; + var args = Array.prototype.slice.call(arguments, 2); + callback = args.pop(); + options = args.length ? args.shift() || {} : {}; + options = typeof callback === 'function' ? options : callback; + options = options == null ? {} : options; + + // Get the error options + var errorOptions = _getWriteConcern(this, options, callback); + // Create command + var command = DbCommand.createCreateIndexCommand(this, collectionName, fieldOrSpec, options); + // Default command options + var commandOptions = {}; + + // If we have error conditions set handle them + if(_hasWriteConcern(errorOptions) && typeof callback == 'function') { + // Insert options + commandOptions['read'] = false; + // If we have safe set set async to false + if(errorOptions == null) commandOptions['async'] = true; + + // Set safe option + commandOptions['safe'] = errorOptions; + // If we have an error option + if(typeof errorOptions == 'object') { + var keys = Object.keys(errorOptions); + for(var i = 0; i < keys.length; i++) { + commandOptions[keys[i]] = errorOptions[keys[i]]; + } + } + + // Execute insert command + this._executeInsertCommand(command, commandOptions, function(err, result) { + if(err != null) return callback(err, null); + + result = result && result.documents; + if (result[0].err) { + callback(utils.toError(result[0])); + } else { + callback(null, command.documents[0].name); + } + }); + } else if(_hasWriteConcern(errorOptions) && callback == null) { + throw new Error("Cannot use a writeConcern without a provided callback"); + } else { + // Execute insert command + var result = this._executeInsertCommand(command, commandOptions); + // If no callback just return + if(!callback) return; + // If error return error + if(result instanceof Error) { + return callback(result); + } + // Otherwise just return + return callback(null, null); + } +}; + +/** + * Ensures that an index exists, if it does not it creates it + * + * Options + * - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * - **unique** {Boolean, default:false}, creates an unique index. + * - **sparse** {Boolean, default:false}, creates a sparse index. + * - **background** {Boolean, default:false}, creates the index in the background, yielding whenever possible. + * - **dropDups** {Boolean, default:false}, a unique index cannot be created on a key that has pre-existing duplicate values. If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value + * - **min** {Number}, for geospatial indexes set the lower bound for the co-ordinates. + * - **max** {Number}, for geospatial indexes set the high bound for the co-ordinates. + * - **v** {Number}, specify the format version of the indexes. + * - **expireAfterSeconds** {Number}, allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher) + * - **name** {String}, override the autogenerated index name (useful if the resulting name is larger than 128 bytes) + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @param {String} collectionName name of the collection to create the index on. + * @param {Object} fieldOrSpec fieldOrSpec that defines the index. + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from ensureIndex or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.ensureIndex = function(collectionName, fieldOrSpec, options, callback) { + var self = this; + + if (typeof callback === 'undefined' && typeof options === 'function') { + callback = options; + options = {}; + } + + if (options == null) { + options = {}; + } + + // Get the error options + var errorOptions = _getWriteConcern(this, options, callback); + // Make sure we don't try to do a write concern without a callback + if(_hasWriteConcern(errorOptions) && callback == null) + throw new Error("Cannot use a writeConcern without a provided callback"); + // Create command + var command = DbCommand.createCreateIndexCommand(this, collectionName, fieldOrSpec, options); + var index_name = command.documents[0].name; + + // Default command options + var commandOptions = {}; + // Check if the index allready exists + this.indexInformation(collectionName, function(err, collectionInfo) { + if(err != null) return callback(err, null); + + if(!collectionInfo[index_name]) { + // If we have error conditions set handle them + if(_hasWriteConcern(errorOptions) && typeof callback == 'function') { + // Insert options + commandOptions['read'] = false; + // If we have safe set set async to false + if(errorOptions == null) commandOptions['async'] = true; + + // If we have an error option + if(typeof errorOptions == 'object') { + var keys = Object.keys(errorOptions); + for(var i = 0; i < keys.length; i++) { + commandOptions[keys[i]] = errorOptions[keys[i]]; + } + } + + if(typeof callback === 'function' + && commandOptions.w < 1 && !commandOptions.fsync && !commandOptions.journal) { + commandOptions.w = 1; + } + + self._executeInsertCommand(command, commandOptions, function(err, result) { + // Only callback if we have one specified + if(typeof callback === 'function') { + if(err != null) return callback(err, null); + + result = result && result.documents; + if (result[0].err) { + callback(utils.toError(result[0])); + } else { + callback(null, command.documents[0].name); + } + } + }); + } else { + // Execute insert command + var result = self._executeInsertCommand(command, commandOptions); + // If no callback just return + if(!callback) return; + // If error return error + if(result instanceof Error) { + return callback(result); + } + // Otherwise just return + return callback(null, index_name); + } + } else { + if(typeof callback === 'function') return callback(null, index_name); + } + }); +}; + +/** + * Returns the information available on allocated cursors. + * + * Options + * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST). + * + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from cursorInfo or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.cursorInfo = function(options, callback) { + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + options = args.length ? args.shift() || {} : {}; + + this._executeQueryCommand(DbCommand.createDbSlaveOkCommand(this, {'cursorInfo':1}) + , options + , utils.handleSingleCommandResultReturn(null, null, callback)); +}; + +/** + * Drop an index on a collection. + * + * @param {String} collectionName the name of the collection where the command will drop an index. + * @param {String} indexName name of the index to drop. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from dropIndex or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.dropIndex = function(collectionName, indexName, callback) { + this._executeQueryCommand(DbCommand.createDropIndexCommand(this, collectionName, indexName) + , utils.handleSingleCommandResultReturn(null, null, callback)); +}; + +/** + * Reindex all indexes on the collection + * Warning: reIndex is a blocking operation (indexes are rebuilt in the foreground) and will be slow for large collections. + * + * @param {String} collectionName the name of the collection. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from reIndex or null if an error occured. + * @api public +**/ +Db.prototype.reIndex = function(collectionName, callback) { + this._executeQueryCommand(DbCommand.createReIndexCommand(this, collectionName) + , utils.handleSingleCommandResultReturn(true, false, callback)); +}; + +/** + * Retrieves this collections index info. + * + * Options + * - **full** {Boolean, default:false}, returns the full raw index information. + * - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST). + * + * @param {String} collectionName the name of the collection. + * @param {Object} [options] additional options during update. + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from indexInformation or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.indexInformation = function(collectionName, options, callback) { + if(typeof callback === 'undefined') { + if(typeof options === 'undefined') { + callback = collectionName; + collectionName = null; + } else { + callback = options; + } + options = {}; + } + + // If we specified full information + var full = options['full'] == null ? false : options['full']; + // Build selector for the indexes + var selector = collectionName != null ? {ns: (this.databaseName + "." + collectionName)} : {}; + + // Set read preference if we set one + var readPreference = options['readPreference'] ? options['readPreference'] : ReadPreference.PRIMARY; + + // Iterate through all the fields of the index + this.collection(DbCommand.SYSTEM_INDEX_COLLECTION, function(err, collection) { + // Perform the find for the collection + collection.find(selector).setReadPreference(readPreference).toArray(function(err, indexes) { + if(err != null) return callback(err, null); + // Contains all the information + var info = {}; + + // if full defined just return all the indexes directly + if(full) return callback(null, indexes); + + // Process all the indexes + for(var i = 0; i < indexes.length; i++) { + var index = indexes[i]; + // Let's unpack the object + info[index.name] = []; + for(var name in index.key) { + info[index.name].push([name, index.key[name]]); + } + } + + // Return all the indexes + callback(null, info); + }); + }); +}; + +/** + * Drop a database. + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from dropDatabase or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.dropDatabase = function(callback) { + this._executeQueryCommand(DbCommand.createDropDatabaseCommand(this) + , utils.handleSingleCommandResultReturn(true, false, callback)); +} + +/** + * Get all the db statistics. + * + * Options + * - **scale** {Number}, divide the returned sizes by scale value. + * - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST). + * + * @param {Objects} [options] options for the stats command + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from stats or null if an error occured. + * @return {null} + * @api public + */ +Db.prototype.stats = function stats(options, callback) { + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + // Fetch all commands + options = args.length ? args.shift() || {} : {}; + + // Build command object + var commandObject = { + dbStats:this.collectionName, + } + + // Check if we have the scale value + if(options['scale'] != null) commandObject['scale'] = options['scale']; + + // Execute the command + this.command(commandObject, options, callback); +} + +/** + * @ignore + */ +var __executeQueryCommand = function(self, db_command, options, callback) { + // Options unpacking + var read = options['read'] != null ? options['read'] : false; + var raw = options['raw'] != null ? options['raw'] : self.raw; + var onAll = options['onAll'] != null ? options['onAll'] : false; + var specifiedConnection = options['connection'] != null ? options['connection'] : null; + + // Correct read preference to default primary if set to false, null or primary + if(!(typeof read == 'object') && read._type == 'ReadPreference') { + read = (read == null || read == 'primary' || read == false) ? ReadPreference.PRIMARY : read; + if(!ReadPreference.isValid(read)) return callback(new Error("Illegal readPreference mode specified, " + read)); + } else if(typeof read == 'object' && read._type == 'ReadPreference') { + if(!read.isValid()) return callback(new Error("Illegal readPreference mode specified, " + read.mode)); + } + + // If we have a read preference set and we are a mongos pass the read preference on to the mongos instance, + if(self.serverConfig.isMongos() && read != null && read != false) { + db_command.setMongosReadPreference(read); + } + + // If we got a callback object + if(typeof callback === 'function' && !onAll) { + // Override connection if we passed in a specific connection + var connection = specifiedConnection != null ? specifiedConnection : null; + + if(connection instanceof Error) return callback(connection, null); + + // Fetch either a reader or writer dependent on the specified read option if no connection + // was passed in + if(connection == null) { + connection = self.serverConfig.checkoutReader(read); + } + + if(connection == null) { + return callback(new Error("no open connections")); + } else if(connection instanceof Error || connection['message'] != null) { + return callback(connection); + } + + // Exhaust Option + var exhaust = options.exhaust || false; + + // Register the handler in the data structure + self.serverConfig._registerHandler(db_command, raw, connection, exhaust, callback); + + // Ensure the connection is valid + if(!connection.isConnected()) { + if(read == ReadPreference.PRIMARY + || read == ReadPreference.PRIMARY_PREFERRED + || (read != null && typeof read == 'object' && read.mode) + || read == null) { + + // Save the command + self.serverConfig._commandsStore.read_from_writer( + { type: 'query' + , db_command: db_command + , options: options + , callback: callback + , db: self + , executeQueryCommand: __executeQueryCommand + , executeInsertCommand: __executeInsertCommand + } + ); + } else { + self.serverConfig._commandsStore.read( + { type: 'query' + , db_command: db_command + , options: options + , callback: callback + , db: self + , executeQueryCommand: __executeQueryCommand + , executeInsertCommand: __executeInsertCommand + } + ); + } + } + + // Write the message out and handle any errors if there are any + connection.write(db_command, function(err) { + if(err != null) { + // Call the handler with an error + if(Array.isArray(db_command)) + self.serverConfig._callHandler(db_command[0].getRequestId(), null, err); + else + self.serverConfig._callHandler(db_command.getRequestId(), null, err); + } + }); + } else if(typeof callback === 'function' && onAll) { + var connections = self.serverConfig.allRawConnections(); + var numberOfEntries = connections.length; + // Go through all the connections + for(var i = 0; i < connections.length; i++) { + // Fetch a connection + var connection = connections[i]; + + // Ensure we have a valid connection + if(connection == null) { + return callback(new Error("no open connections")); + } else if(connection instanceof Error) { + return callback(connection); + } + + // Register the handler in the data structure + self.serverConfig._registerHandler(db_command, raw, connection, callback); + + // Write the message out + connection.write(db_command, function(err) { + // Adjust the number of entries we need to process + numberOfEntries = numberOfEntries - 1; + // Remove listener + if(err != null) { + // Clean up listener and return error + self.serverConfig._removeHandler(db_command.getRequestId()); + } + + // No more entries to process callback with the error + if(numberOfEntries <= 0) { + callback(err); + } + }); + + // Update the db_command request id + db_command.updateRequestId(); + } + } else { + // Fetch either a reader or writer dependent on the specified read option + // var connection = read == null || read == 'primary' || read == false ? self.serverConfig.checkoutWriter(true) : self.serverConfig.checkoutReader(read); + var connection = self.serverConfig.checkoutReader(read); + // Override connection if needed + connection = specifiedConnection != null ? specifiedConnection : connection; + // Ensure we have a valid connection + if(connection == null || connection instanceof Error || connection['message'] != null) return null; + // Write the message out + connection.write(db_command, function(err) { + if(err != null) { + // Emit the error + self.emit("error", err); + } + }); + } +} + +/** + * Execute db query command (not safe) + * @ignore + * @api private + */ +Db.prototype._executeQueryCommand = function(db_command, options, callback) { + var self = this; + + // Unpack the parameters + if (typeof callback === 'undefined') { + callback = options; + options = {}; + } + + // fast fail option used for HA, no retry + var failFast = options['failFast'] != null + ? options['failFast'] + : false; + + // Check if the user force closed the command + if(this._applicationClosed) { + var err = new Error("db closed by application"); + if('function' == typeof callback) { + return callback(err, null); + } else { + throw err; + } + } + + if(this.serverConfig.isDestroyed()) + return callback(new Error("Connection was destroyed by application")); + + // Specific connection + var connection = options.connection; + // Check if the connection is actually live + if(connection + && (!connection.isConnected || !connection.isConnected())) connection = null; + + // Get the configuration + var config = this.serverConfig; + var read = options.read; + + if(!connection && !config.canRead(read) && !config.canWrite() && config.isAutoReconnect()) { + if(read == ReadPreference.PRIMARY + || read == ReadPreference.PRIMARY_PREFERRED + || (read != null && typeof read == 'object' && read.mode) + || read == null) { + + // Save the command + self.serverConfig._commandsStore.read_from_writer( + { type: 'query' + , db_command: db_command + , options: options + , callback: callback + , db: self + , executeQueryCommand: __executeQueryCommand + , executeInsertCommand: __executeInsertCommand + } + ); + } else { + self.serverConfig._commandsStore.read( + { type: 'query' + , db_command: db_command + , options: options + , callback: callback + , db: self + , executeQueryCommand: __executeQueryCommand + , executeInsertCommand: __executeInsertCommand + } + ); + } + } else if(!connection && !config.canRead(read) && !config.canWrite() && !config.isAutoReconnect()) { + return callback(new Error("no open connections"), null); + } else { + if(typeof callback == 'function') { + __executeQueryCommand(self, db_command, options, function (err, result, conn) { + callback(err, result, conn); + }); + } else { + __executeQueryCommand(self, db_command, options); + } + } +}; + +/** + * @ignore + */ +var __executeInsertCommand = function(self, db_command, options, callback) { + // Always checkout a writer for this kind of operations + var connection = self.serverConfig.checkoutWriter(); + // Get safe mode + var safe = options['safe'] != null ? options['safe'] : false; + var raw = options['raw'] != null ? options['raw'] : self.raw; + var specifiedConnection = options['connection'] != null ? options['connection'] : null; + // Override connection if needed + connection = specifiedConnection != null ? specifiedConnection : connection; + + // Ensure we have a valid connection + if(typeof callback === 'function') { + // Ensure we have a valid connection + if(connection == null) { + return callback(new Error("no open connections")); + } else if(connection instanceof Error) { + return callback(connection); + } + + var errorOptions = _getWriteConcern(self, options, callback); + if(errorOptions.w > 0 || errorOptions.w == 'majority' || errorOptions.j || errorOptions.journal || errorOptions.fsync) { + // db command is now an array of commands (original command + lastError) + db_command = [db_command, DbCommand.createGetLastErrorCommand(safe, self)]; + // Register the handler in the data structure + self.serverConfig._registerHandler(db_command[1], raw, connection, callback); + } + } + + // If we have no callback and there is no connection + if(connection == null) return null; + if(connection instanceof Error && typeof callback == 'function') return callback(connection, null); + if(connection instanceof Error) return null; + if(connection == null && typeof callback == 'function') return callback(new Error("no primary server found"), null); + + // Ensure we truly are connected + if(!connection.isConnected()) { + return self.serverConfig._commandsStore.write( + { type:'insert' + , 'db_command':db_command + , 'options':options + , 'callback':callback + , db: self + , executeQueryCommand: __executeQueryCommand + , executeInsertCommand: __executeInsertCommand + } + ); + } + + // Write the message out + connection.write(db_command, function(err) { + // Return the callback if it's not a safe operation and the callback is defined + if(typeof callback === 'function' && (safe == null || safe == false)) { + // Perform the callback + callback(err, null); + } else if(typeof callback === 'function') { + // Call the handler with an error + self.serverConfig._callHandler(db_command[1].getRequestId(), null, err); + } else if(typeof callback == 'function' && safe && safe.w == -1) { + // Call the handler with no error + self.serverConfig._callHandler(db_command[1].getRequestId(), null, null); + } else if(!safe || safe.w == -1) { + self.emit("error", err); + } + }); +} + +/** + * Execute an insert Command + * @ignore + * @api private + */ +Db.prototype._executeInsertCommand = function(db_command, options, callback) { + var self = this; + + // Unpack the parameters + if(callback == null && typeof options === 'function') { + callback = options; + options = {}; + } + + // Ensure options are not null + options = options == null ? {} : options; + + // Check if the user force closed the command + if(this._applicationClosed) { + if(typeof callback == 'function') { + return callback(new Error("db closed by application"), null); + } else { + throw new Error("db closed by application"); + } + } + + if(this.serverConfig.isDestroyed()) return callback(new Error("Connection was destroyed by application")); + + // Specific connection + var connection = options.connection; + // Check if the connection is actually live + if(connection + && (!connection.isConnected || !connection.isConnected())) connection = null; + + // Get config + var config = self.serverConfig; + // Check if we are connected + if(!connection && !config.canWrite() && config.isAutoReconnect()) { + self.serverConfig._commandsStore.write( + { type:'insert' + , 'db_command':db_command + , 'options':options + , 'callback':callback + , db: self + , executeQueryCommand: __executeQueryCommand + , executeInsertCommand: __executeInsertCommand + } + ); + } else if(!connection && !config.canWrite() && !config.isAutoReconnect()) { + return callback(new Error("no open connections"), null); + } else { + __executeInsertCommand(self, db_command, options, callback); + } +} + +/** + * Update command is the same + * @ignore + * @api private + */ +Db.prototype._executeUpdateCommand = Db.prototype._executeInsertCommand; +/** + * Remove command is the same + * @ignore + * @api private + */ +Db.prototype._executeRemoveCommand = Db.prototype._executeInsertCommand; + +/** + * Wrap a Mongo error document into an Error instance. + * Deprecated. Use utils.toError instead. + * + * @ignore + * @api private + * @deprecated + */ +Db.prototype.wrap = utils.toError; + +/** + * Default URL + * + * @classconstant DEFAULT_URL + **/ +Db.DEFAULT_URL = 'mongodb://localhost:27017/default'; + +/** + * Connect to MongoDB using a url as documented at + * + * docs.mongodb.org/manual/reference/connection-string/ + * + * Options + * - **uri_decode_auth** {Boolean, default:false} uri decode the user name and password for authentication + * - **db** {Object, default: null} a hash off options to set on the db object, see **Db constructor** + * - **server** {Object, default: null} a hash off options to set on the server objects, see **Server** constructor** + * - **replSet** {Object, default: null} a hash off options to set on the replSet object, see **ReplSet** constructor** + * - **mongos** {Object, default: null} a hash off options to set on the mongos object, see **Mongos** constructor** + * + * @param {String} url connection url for MongoDB. + * @param {Object} [options] optional options for insert command + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the db instance or null if an error occured. + * @return {null} + * @api public + */ +Db.connect = function(url, options, callback) { + // Ensure correct mapping of the callback + if(typeof options == 'function') { + callback = options; + options = {}; + } + + // Ensure same behavior as previous version w:0 + if(url.indexOf("safe") == -1 + && url.indexOf("w") == -1 + && url.indexOf("journal") == -1 && url.indexOf("j") == -1 + && url.indexOf("fsync") == -1) options.w = 0; + + // Avoid circular require problem + var MongoClient = require('./mongo_client.js').MongoClient; + // Attempt to connect + MongoClient.connect.call(MongoClient, url, options, callback); +} + +/** + * State of the db connection + * @ignore + */ +Object.defineProperty(Db.prototype, "state", { enumerable: true + , get: function () { + return this.serverConfig._serverState; + } +}); + +/** + * @ignore + */ +var _hasWriteConcern = function(errorOptions) { + return errorOptions == true + || errorOptions.w > 0 + || errorOptions.w == 'majority' + || errorOptions.j == true + || errorOptions.journal == true + || errorOptions.fsync == true +} + +/** + * @ignore + */ +var _setWriteConcernHash = function(options) { + var finalOptions = {}; + if(options.w != null) finalOptions.w = options.w; + if(options.journal == true) finalOptions.j = options.journal; + if(options.j == true) finalOptions.j = options.j; + if(options.fsync == true) finalOptions.fsync = options.fsync; + if(options.wtimeout != null) finalOptions.wtimeout = options.wtimeout; + return finalOptions; +} + +/** + * @ignore + */ +var _getWriteConcern = function(self, options, callback) { + // Final options + var finalOptions = {w:1}; + // Local options verification + if(options.w != null || typeof options.j == 'boolean' || typeof options.journal == 'boolean' || typeof options.fsync == 'boolean') { + finalOptions = _setWriteConcernHash(options); + } else if(options.safe != null && typeof options.safe == 'object') { + finalOptions = _setWriteConcernHash(options.safe); + } else if(typeof options.safe == "boolean") { + finalOptions = {w: (options.safe ? 1 : 0)}; + } else if(self.options.w != null || typeof self.options.j == 'boolean' || typeof self.options.journal == 'boolean' || typeof self.options.fsync == 'boolean') { + finalOptions = _setWriteConcernHash(self.options); + } else if(self.safe.w != null || typeof self.safe.j == 'boolean' || typeof self.safe.journal == 'boolean' || typeof self.safe.fsync == 'boolean') { + finalOptions = _setWriteConcernHash(self.safe); + } else if(typeof self.safe == "boolean") { + finalOptions = {w: (self.safe ? 1 : 0)}; + } + + // Ensure we don't have an invalid combination of write concerns + if(finalOptions.w < 1 + && (finalOptions.journal == true || finalOptions.j == true || finalOptions.fsync == true)) throw new Error("No acknowlegement using w < 1 cannot be combined with journal:true or fsync:true"); + + // Return the options + return finalOptions; +} + +/** + * Legacy support + * + * @ignore + * @api private + */ +exports.connect = Db.connect; +exports.Db = Db; + +/** + * Remove all listeners to the db instance. + * @ignore + * @api private + */ +Db.prototype.removeAllEventListeners = function() { + this.removeAllListeners("close"); + this.removeAllListeners("error"); + this.removeAllListeners("timeout"); + this.removeAllListeners("parseError"); + this.removeAllListeners("poolReady"); + this.removeAllListeners("message"); +} diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/gridfs/chunk.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/gridfs/chunk.js new file mode 100644 index 0000000..59c6a26 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/gridfs/chunk.js @@ -0,0 +1,221 @@ +var Binary = require('bson').Binary, + ObjectID = require('bson').ObjectID; + +/** + * Class for representing a single chunk in GridFS. + * + * @class + * + * @param file {GridStore} The {@link GridStore} object holding this chunk. + * @param mongoObject {object} The mongo object representation of this chunk. + * + * @throws Error when the type of data field for {@link mongoObject} is not + * supported. Currently supported types for data field are instances of + * {@link String}, {@link Array}, {@link Binary} and {@link Binary} + * from the bson module + * + * @see Chunk#buildMongoObject + */ +var Chunk = exports.Chunk = function(file, mongoObject, writeConcern) { + if(!(this instanceof Chunk)) return new Chunk(file, mongoObject); + + this.file = file; + var self = this; + var mongoObjectFinal = mongoObject == null ? {} : mongoObject; + this.writeConcern = writeConcern || {w:1}; + this.objectId = mongoObjectFinal._id == null ? new ObjectID() : mongoObjectFinal._id; + this.chunkNumber = mongoObjectFinal.n == null ? 0 : mongoObjectFinal.n; + this.data = new Binary(); + + if(mongoObjectFinal.data == null) { + } else if(typeof mongoObjectFinal.data == "string") { + var buffer = new Buffer(mongoObjectFinal.data.length); + buffer.write(mongoObjectFinal.data, 'binary', 0); + this.data = new Binary(buffer); + } else if(Array.isArray(mongoObjectFinal.data)) { + var buffer = new Buffer(mongoObjectFinal.data.length); + buffer.write(mongoObjectFinal.data.join(''), 'binary', 0); + this.data = new Binary(buffer); + } else if(mongoObjectFinal.data instanceof Binary || Object.prototype.toString.call(mongoObjectFinal.data) == "[object Binary]") { + this.data = mongoObjectFinal.data; + } else if(Buffer.isBuffer(mongoObjectFinal.data)) { + } else { + throw Error("Illegal chunk format"); + } + // Update position + this.internalPosition = 0; +}; + +/** + * Writes a data to this object and advance the read/write head. + * + * @param data {string} the data to write + * @param callback {function(*, GridStore)} This will be called after executing + * this method. The first parameter will contain null and the second one + * will contain a reference to this object. + */ +Chunk.prototype.write = function(data, callback) { + this.data.write(data, this.internalPosition); + this.internalPosition = this.data.length(); + if(callback != null) return callback(null, this); + return this; +}; + +/** + * Reads data and advances the read/write head. + * + * @param length {number} The length of data to read. + * + * @return {string} The data read if the given length will not exceed the end of + * the chunk. Returns an empty String otherwise. + */ +Chunk.prototype.read = function(length) { + // Default to full read if no index defined + length = length == null || length == 0 ? this.length() : length; + + if(this.length() - this.internalPosition + 1 >= length) { + var data = this.data.read(this.internalPosition, length); + this.internalPosition = this.internalPosition + length; + return data; + } else { + return ''; + } +}; + +Chunk.prototype.readSlice = function(length) { + if ((this.length() - this.internalPosition) >= length) { + var data = null; + if (this.data.buffer != null) { //Pure BSON + data = this.data.buffer.slice(this.internalPosition, this.internalPosition + length); + } else { //Native BSON + data = new Buffer(length); + length = this.data.readInto(data, this.internalPosition); + } + this.internalPosition = this.internalPosition + length; + return data; + } else { + return null; + } +}; + +/** + * Checks if the read/write head is at the end. + * + * @return {boolean} Whether the read/write head has reached the end of this + * chunk. + */ +Chunk.prototype.eof = function() { + return this.internalPosition == this.length() ? true : false; +}; + +/** + * Reads one character from the data of this chunk and advances the read/write + * head. + * + * @return {string} a single character data read if the the read/write head is + * not at the end of the chunk. Returns an empty String otherwise. + */ +Chunk.prototype.getc = function() { + return this.read(1); +}; + +/** + * Clears the contents of the data in this chunk and resets the read/write head + * to the initial position. + */ +Chunk.prototype.rewind = function() { + this.internalPosition = 0; + this.data = new Binary(); +}; + +/** + * Saves this chunk to the database. Also overwrites existing entries having the + * same id as this chunk. + * + * @param callback {function(*, GridStore)} This will be called after executing + * this method. The first parameter will contain null and the second one + * will contain a reference to this object. + */ +Chunk.prototype.save = function(callback) { + var self = this; + + self.file.chunkCollection(function(err, collection) { + if(err) return callback(err); + + collection.remove({'_id':self.objectId}, self.writeConcern, function(err, result) { + if(err) return callback(err); + + if(self.data.length() > 0) { + self.buildMongoObject(function(mongoObject) { + var options = {forceServerObjectId:true}; + for(var name in self.writeConcern) { + options[name] = self.writeConcern[name]; + } + + collection.insert(mongoObject, options, function(err, collection) { + callback(err, self); + }); + }); + } else { + callback(null, self); + } + }); + }); +}; + +/** + * Creates a mongoDB object representation of this chunk. + * + * @param callback {function(Object)} This will be called after executing this + * method. The object will be passed to the first parameter and will have + * the structure: + * + *
    
    + *        {
    + *          '_id' : , // {number} id for this chunk
    + *          'files_id' : , // {number} foreign key to the file collection
    + *          'n' : , // {number} chunk number
    + *          'data' : , // {bson#Binary} the chunk data itself
    + *        }
    + *        
    + * + * @see MongoDB GridFS Chunk Object Structure + */ +Chunk.prototype.buildMongoObject = function(callback) { + var mongoObject = { + 'files_id': this.file.fileId, + 'n': this.chunkNumber, + 'data': this.data}; + // If we are saving using a specific ObjectId + if(this.objectId != null) mongoObject._id = this.objectId; + + callback(mongoObject); +}; + +/** + * @return {number} the length of the data + */ +Chunk.prototype.length = function() { + return this.data.length(); +}; + +/** + * The position of the read/write head + * @name position + * @lends Chunk# + * @field + */ +Object.defineProperty(Chunk.prototype, "position", { enumerable: true + , get: function () { + return this.internalPosition; + } + , set: function(value) { + this.internalPosition = value; + } +}); + +/** + * The default chunk size + * @constant + */ +Chunk.DEFAULT_CHUNK_SIZE = 1024 * 256; diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/gridfs/grid.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/gridfs/grid.js new file mode 100644 index 0000000..aa695b7 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/gridfs/grid.js @@ -0,0 +1,103 @@ +var GridStore = require('./gridstore').GridStore, + ObjectID = require('bson').ObjectID; + +/** + * A class representation of a simple Grid interface. + * + * @class Represents the Grid. + * @param {Db} db A database instance to interact with. + * @param {String} [fsName] optional different root collection for GridFS. + * @return {Grid} + */ +function Grid(db, fsName) { + + if(!(this instanceof Grid)) return new Grid(db, fsName); + + this.db = db; + this.fsName = fsName == null ? GridStore.DEFAULT_ROOT_COLLECTION : fsName; +} + +/** + * Puts binary data to the grid + * + * Options + * - **_id** {Any}, unique id for this file + * - **root** {String}, root collection to use. Defaults to **{GridStore.DEFAULT_ROOT_COLLECTION}**. + * - **content_type** {String}, mime type of the file. Defaults to **{GridStore.DEFAULT_CONTENT_TYPE}**. + * - **chunk_size** {Number}, size for the chunk. Defaults to **{Chunk.DEFAULT_CHUNK_SIZE}**. + * - **metadata** {Object}, arbitrary data the user wants to store. + * + * @param {Buffer} data buffer with Binary Data. + * @param {Object} [options] the options for the files. + * @param {Function} callback this will be called after this method is executed. The first parameter will contain an Error object if an error occured or null otherwise. The second parameter will contain a reference to this object. + * @return {null} + * @api public + */ +Grid.prototype.put = function(data, options, callback) { + var self = this; + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + options = args.length ? args.shift() : {}; + // If root is not defined add our default one + options['root'] = options['root'] == null ? this.fsName : options['root']; + + // Return if we don't have a buffer object as data + if(!(Buffer.isBuffer(data))) return callback(new Error("Data object must be a buffer object"), null); + // Get filename if we are using it + var filename = options['filename'] || null; + // Get id if we are using it + var id = options['_id'] || null; + // Create gridstore + var gridStore = new GridStore(this.db, id, filename, "w", options); + gridStore.open(function(err, gridStore) { + if(err) return callback(err, null); + + gridStore.write(data, function(err, result) { + if(err) return callback(err, null); + + gridStore.close(function(err, result) { + if(err) return callback(err, null); + callback(null, result); + }) + }) + }) +} + +/** + * Get binary data to the grid + * + * @param {Any} id for file. + * @param {Function} callback this will be called after this method is executed. The first parameter will contain an Error object if an error occured or null otherwise. The second parameter will contain a reference to this object. + * @return {null} + * @api public + */ +Grid.prototype.get = function(id, callback) { + // Create gridstore + var gridStore = new GridStore(this.db, id, null, "r", {root:this.fsName}); + gridStore.open(function(err, gridStore) { + if(err) return callback(err, null); + + // Return the data + gridStore.read(function(err, data) { + return callback(err, data) + }); + }) +} + +/** + * Delete file from grid + * + * @param {Any} id for file. + * @param {Function} callback this will be called after this method is executed. The first parameter will contain an Error object if an error occured or null otherwise. The second parameter will contain a reference to this object. + * @return {null} + * @api public + */ +Grid.prototype.delete = function(id, callback) { + // Create gridstore + GridStore.unlink(this.db, id, {root:this.fsName}, function(err, result) { + if(err) return callback(err, false); + return callback(null, true); + }); +} + +exports.Grid = Grid; diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/gridfs/gridstore.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/gridfs/gridstore.js new file mode 100644 index 0000000..edf6c74 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/gridfs/gridstore.js @@ -0,0 +1,1558 @@ +/** + * @fileOverview GridFS is a tool for MongoDB to store files to the database. + * Because of the restrictions of the object size the database can hold, a + * facility to split a file into several chunks is needed. The {@link GridStore} + * class offers a simplified api to interact with files while managing the + * chunks of split files behind the scenes. More information about GridFS can be + * found here. + */ +var Chunk = require('./chunk').Chunk, + DbCommand = require('../commands/db_command').DbCommand, + ObjectID = require('bson').ObjectID, + Buffer = require('buffer').Buffer, + fs = require('fs'), + timers = require('timers'), + util = require('util'), + inherits = util.inherits, + ReadStream = require('./readstream').ReadStream, + Stream = require('stream'); + +// Set processor, setImmediate if 0.10 otherwise nextTick +var processor = require('../utils').processor(); + +var REFERENCE_BY_FILENAME = 0, + REFERENCE_BY_ID = 1; + +/** + * A class representation of a file stored in GridFS. + * + * Modes + * - **"r"** - read only. This is the default mode. + * - **"w"** - write in truncate mode. Existing data will be overwriten. + * - **w+"** - write in edit mode. + * + * Options + * - **root** {String}, root collection to use. Defaults to **{GridStore.DEFAULT_ROOT_COLLECTION}**. + * - **content_type** {String}, mime type of the file. Defaults to **{GridStore.DEFAULT_CONTENT_TYPE}**. + * - **chunk_size** {Number}, size for the chunk. Defaults to **{Chunk.DEFAULT_CHUNK_SIZE}**. + * - **metadata** {Object}, arbitrary data the user wants to store. + * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST). + * - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * + * @class Represents the GridStore. + * @param {Db} db A database instance to interact with. + * @param {Any} [id] optional unique id for this file + * @param {String} [filename] optional filename for this file, no unique constrain on the field + * @param {String} mode set the mode for this file. + * @param {Object} options optional properties to specify. + * @return {GridStore} + */ +var GridStore = function GridStore(db, id, filename, mode, options) { + if(!(this instanceof GridStore)) return new GridStore(db, id, filename, mode, options); + + var self = this; + this.db = db; + + // Call stream constructor + if(typeof Stream == 'function') { + Stream.call(this); + } else { + // 0.4.X backward compatibility fix + Stream.Stream.call(this); + } + + // Handle options + if(typeof options === 'undefined') options = {}; + // Handle mode + if(typeof mode === 'undefined') { + mode = filename; + filename = undefined; + } else if(typeof mode == 'object') { + options = mode; + mode = filename; + filename = undefined; + } + + if(id instanceof ObjectID) { + this.referenceBy = REFERENCE_BY_ID; + this.fileId = id; + this.filename = filename; + } else if(typeof filename == 'undefined') { + this.referenceBy = REFERENCE_BY_FILENAME; + this.filename = id; + if (mode.indexOf('w') != null) { + this.fileId = new ObjectID(); + } + } else { + this.referenceBy = REFERENCE_BY_ID; + this.fileId = id; + this.filename = filename; + } + + // Set up the rest + this.mode = mode == null ? "r" : mode; + this.options = options == null ? {w:1} : options; + + // If we have no write concerns set w:1 as default + if(this.options.w == null + && this.options.j == null + && this.options.fsync == null) this.options.w = 1; + + // Set the root if overridden + this.root = this.options['root'] == null ? exports.GridStore.DEFAULT_ROOT_COLLECTION : this.options['root']; + this.position = 0; + this.readPreference = this.options.readPreference || 'primary'; + this.writeConcern = _getWriteConcern(this, this.options); + // Set default chunk size + this.internalChunkSize = this.options['chunkSize'] == null ? Chunk.DEFAULT_CHUNK_SIZE : this.options['chunkSize']; +} + +/** + * Code for the streaming capabilities of the gridstore object + * Most code from Aaron heckmanns project https://github.com/aheckmann/gridfs-stream + * Modified to work on the gridstore object itself + * @ignore + */ +if(typeof Stream == 'function') { + GridStore.prototype = { __proto__: Stream.prototype } +} else { + // Node 0.4.X compatibility code + GridStore.prototype = { __proto__: Stream.Stream.prototype } +} + +// Move pipe to _pipe +GridStore.prototype._pipe = GridStore.prototype.pipe; + +/** + * Opens the file from the database and initialize this object. Also creates a + * new one if file does not exist. + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain an **{Error}** object and the second parameter will be null if an error occured. Otherwise, the first parameter will be null and the second will contain the reference to this object. + * @return {null} + * @api public + */ +GridStore.prototype.open = function(callback) { + if( this.mode != "w" && this.mode != "w+" && this.mode != "r"){ + callback(new Error("Illegal mode " + this.mode), null); + return; + } + + var self = this; + + if((self.mode == "w" || self.mode == "w+") && self.db.serverConfig.primary != null) { + // Get files collection + self.collection(function(err, collection) { + if(err) return callback(err); + + // Put index on filename + collection.ensureIndex([['filename', 1]], function(err, index) { + if(err) return callback(err); + + // Get chunk collection + self.chunkCollection(function(err, chunkCollection) { + if(err) return callback(err); + + // Ensure index on chunk collection + chunkCollection.ensureIndex([['files_id', 1], ['n', 1]], function(err, index) { + if(err) return callback(err); + _open(self, callback); + }); + }); + }); + }); + } else { + // Open the gridstore + _open(self, callback); + } +}; + +/** + * Hidding the _open function + * @ignore + * @api private + */ +var _open = function(self, callback) { + self.collection(function(err, collection) { + if(err!==null) { + callback(new Error("at collection: "+err), null); + return; + } + + // Create the query + var query = self.referenceBy == REFERENCE_BY_ID ? {_id:self.fileId} : {filename:self.filename}; + query = null == self.fileId && this.filename == null ? null : query; + + // Fetch the chunks + if(query != null) { + collection.find(query, {readPreference:self.readPreference}, function(err, cursor) { + if(err) return error(err); + + // Fetch the file + cursor.nextObject(function(err, doc) { + if(err) return error(err); + + // Check if the collection for the files exists otherwise prepare the new one + if(doc != null) { + self.fileId = doc._id; + self.filename = doc.filename; + self.contentType = doc.contentType; + self.internalChunkSize = doc.chunkSize; + self.uploadDate = doc.uploadDate; + self.aliases = doc.aliases; + self.length = doc.length; + self.metadata = doc.metadata; + self.internalMd5 = doc.md5; + } else if (self.mode != 'r') { + self.fileId = self.fileId == null ? new ObjectID() : self.fileId; + self.contentType = exports.GridStore.DEFAULT_CONTENT_TYPE; + self.internalChunkSize = self.internalChunkSize == null ? Chunk.DEFAULT_CHUNK_SIZE : self.internalChunkSize; + self.length = 0; + } else { + self.length = 0; + var txtId = self.fileId instanceof ObjectID ? self.fileId.toHexString() : self.fileId; + return error(new Error((self.referenceBy == REFERENCE_BY_ID ? txtId : self.filename) + " does not exist", self)); + } + + // Process the mode of the object + if(self.mode == "r") { + nthChunk(self, 0, function(err, chunk) { + if(err) return error(err); + self.currentChunk = chunk; + self.position = 0; + callback(null, self); + }); + } else if(self.mode == "w") { + // Delete any existing chunks + deleteChunks(self, function(err, result) { + if(err) return error(err); + self.currentChunk = new Chunk(self, {'n':0}, self.writeConcern); + self.contentType = self.options['content_type'] == null ? self.contentType : self.options['content_type']; + self.internalChunkSize = self.options['chunk_size'] == null ? self.internalChunkSize : self.options['chunk_size']; + self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata']; + self.position = 0; + callback(null, self); + }); + } else if(self.mode == "w+") { + nthChunk(self, lastChunkNumber(self), function(err, chunk) { + if(err) return error(err); + // Set the current chunk + self.currentChunk = chunk == null ? new Chunk(self, {'n':0}, self.writeConcern) : chunk; + self.currentChunk.position = self.currentChunk.data.length(); + self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata']; + self.position = self.length; + callback(null, self); + }); + } + }); + }); + } else { + // Write only mode + self.fileId = null == self.fileId ? new ObjectID() : self.fileId; + self.contentType = exports.GridStore.DEFAULT_CONTENT_TYPE; + self.internalChunkSize = self.internalChunkSize == null ? Chunk.DEFAULT_CHUNK_SIZE : self.internalChunkSize; + self.length = 0; + + self.chunkCollection(function(err, collection2) { + if(err) return error(err); + + // No file exists set up write mode + if(self.mode == "w") { + // Delete any existing chunks + deleteChunks(self, function(err, result) { + if(err) return error(err); + self.currentChunk = new Chunk(self, {'n':0}, self.writeConcern); + self.contentType = self.options['content_type'] == null ? self.contentType : self.options['content_type']; + self.internalChunkSize = self.options['chunk_size'] == null ? self.internalChunkSize : self.options['chunk_size']; + self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata']; + self.position = 0; + callback(null, self); + }); + } else if(self.mode == "w+") { + nthChunk(self, lastChunkNumber(self), function(err, chunk) { + if(err) return error(err); + // Set the current chunk + self.currentChunk = chunk == null ? new Chunk(self, {'n':0}, self.writeConcern) : chunk; + self.currentChunk.position = self.currentChunk.data.length(); + self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata']; + self.position = self.length; + callback(null, self); + }); + } + }); + } + }); + + // only pass error to callback once + function error (err) { + if(error.err) return; + callback(error.err = err); + } +}; + +/** + * Stores a file from the file system to the GridFS database. + * + * @param {String|Buffer|FileHandle} file the file to store. + * @param {Function} callback this will be called after this method is executed. The first parameter will be null and the the second will contain the reference to this object. + * @return {null} + * @api public + */ +GridStore.prototype.writeFile = function (file, callback) { + var self = this; + if (typeof file === 'string') { + fs.open(file, 'r', function (err, fd) { + if(err) return callback(err); + self.writeFile(fd, callback); + }); + return; + } + + self.open(function (err, self) { + if(err) return callback(err, self); + + fs.fstat(file, function (err, stats) { + if(err) return callback(err, self); + + var offset = 0; + var index = 0; + var numberOfChunksLeft = Math.min(stats.size / self.chunkSize); + + // Write a chunk + var writeChunk = function() { + fs.read(file, self.chunkSize, offset, 'binary', function(err, data, bytesRead) { + if(err) return callback(err, self); + + offset = offset + bytesRead; + + // Create a new chunk for the data + var chunk = new Chunk(self, {n:index++}, self.writeConcern); + chunk.write(data, function(err, chunk) { + if(err) return callback(err, self); + + chunk.save(function(err, result) { + if(err) return callback(err, self); + + self.position = self.position + data.length; + + // Point to current chunk + self.currentChunk = chunk; + + if(offset >= stats.size) { + fs.close(file); + self.close(function(err, result) { + if(err) return callback(err, self); + return callback(null, self); + }); + } else { + return processor(writeChunk); + } + }); + }); + }); + } + + // Process the first write + processor(writeChunk); + }); + }); +}; + +/** + * Writes some data. This method will work properly only if initialized with mode + * "w" or "w+". + * + * @param string {string} The data to write. + * @param close {boolean=false} opt_argument Closes this file after writing if + * true. + * @param callback {function(*, GridStore)} This will be called after executing + * this method. The first parameter will contain null and the second one + * will contain a reference to this object. + * + * @ignore + * @api private + */ +var writeBuffer = function(self, buffer, close, callback) { + if(typeof close === "function") { callback = close; close = null; } + var finalClose = (close == null) ? false : close; + + if(self.mode[0] != "w") { + callback(new Error((self.referenceBy == REFERENCE_BY_ID ? self.toHexString() : self.filename) + " not opened for writing"), null); + } else { + if(self.currentChunk.position + buffer.length >= self.chunkSize) { + // Write out the current Chunk and then keep writing until we have less data left than a chunkSize left + // to a new chunk (recursively) + var previousChunkNumber = self.currentChunk.chunkNumber; + var leftOverDataSize = self.chunkSize - self.currentChunk.position; + var firstChunkData = buffer.slice(0, leftOverDataSize); + var leftOverData = buffer.slice(leftOverDataSize); + // A list of chunks to write out + var chunksToWrite = [self.currentChunk.write(firstChunkData)]; + // If we have more data left than the chunk size let's keep writing new chunks + while(leftOverData.length >= self.chunkSize) { + // Create a new chunk and write to it + var newChunk = new Chunk(self, {'n': (previousChunkNumber + 1)}, self.writeConcern); + var firstChunkData = leftOverData.slice(0, self.chunkSize); + leftOverData = leftOverData.slice(self.chunkSize); + // Update chunk number + previousChunkNumber = previousChunkNumber + 1; + // Write data + newChunk.write(firstChunkData); + // Push chunk to save list + chunksToWrite.push(newChunk); + } + + // Set current chunk with remaining data + self.currentChunk = new Chunk(self, {'n': (previousChunkNumber + 1)}, self.writeConcern); + // If we have left over data write it + if(leftOverData.length > 0) self.currentChunk.write(leftOverData); + + // Update the position for the gridstore + self.position = self.position + buffer.length; + // Total number of chunks to write + var numberOfChunksToWrite = chunksToWrite.length; + // Write out all the chunks and then return + for(var i = 0; i < chunksToWrite.length; i++) { + var chunk = chunksToWrite[i]; + chunk.save(function(err, result) { + if(err) return callback(err); + + numberOfChunksToWrite = numberOfChunksToWrite - 1; + + if(numberOfChunksToWrite <= 0) { + return callback(null, self); + } + }) + } + } else { + // Update the position for the gridstore + self.position = self.position + buffer.length; + // We have less data than the chunk size just write it and callback + self.currentChunk.write(buffer); + callback(null, self); + } + } +}; + +/** + * Creates a mongoDB object representation of this object. + * + * @param callback {function(object)} This will be called after executing this + * method. The object will be passed to the first parameter and will have + * the structure: + * + *
    
    + *        {
    + *          '_id' : , // {number} id for this file
    + *          'filename' : , // {string} name for this file
    + *          'contentType' : , // {string} mime type for this file
    + *          'length' : , // {number} size of this file?
    + *          'chunksize' : , // {number} chunk size used by this file
    + *          'uploadDate' : , // {Date}
    + *          'aliases' : , // {array of string}
    + *          'metadata' : , // {string}
    + *        }
    + *        
    + * + * @ignore + * @api private + */ +var buildMongoObject = function(self, callback) { + // // Keeps the final chunk number + // var chunkNumber = 0; + // var previousChunkSize = 0; + // // Get the correct chunk Number, if we have an empty chunk return the previous chunk number + // if(null != self.currentChunk && self.currentChunk.chunkNumber > 0 && self.currentChunk.position == 0) { + // chunkNumber = self.currentChunk.chunkNumber - 1; + // } else { + // chunkNumber = self.currentChunk.chunkNumber; + // previousChunkSize = self.currentChunk.position; + // } + + // // Calcuate the length + // var length = self.currentChunk != null ? (chunkNumber * self.chunkSize + previousChunkSize) : 0; + var mongoObject = { + '_id': self.fileId, + 'filename': self.filename, + 'contentType': self.contentType, + 'length': self.position ? self.position : 0, + 'chunkSize': self.chunkSize, + 'uploadDate': self.uploadDate, + 'aliases': self.aliases, + 'metadata': self.metadata + }; + + var md5Command = {filemd5:self.fileId, root:self.root}; + self.db.command(md5Command, function(err, results) { + mongoObject.md5 = results.md5; + callback(mongoObject); + }); +}; + +/** + * Saves this file to the database. This will overwrite the old entry if it + * already exists. This will work properly only if mode was initialized to + * "w" or "w+". + * + * @param {Function} callback this will be called after executing this method. Passes an **{Error}** object to the first parameter and null to the second if an error occured. Otherwise, passes null to the first and a reference to this object to the second. + * @return {null} + * @api public + */ +GridStore.prototype.close = function(callback) { + var self = this; + + if(self.mode[0] == "w") { + if(self.currentChunk != null && self.currentChunk.position > 0) { + self.currentChunk.save(function(err, chunk) { + if(err && typeof callback == 'function') return callback(err); + + self.collection(function(err, files) { + if(err && typeof callback == 'function') return callback(err); + + // Build the mongo object + if(self.uploadDate != null) { + files.remove({'_id':self.fileId}, {safe:true}, function(err, collection) { + if(err && typeof callback == 'function') return callback(err); + + buildMongoObject(self, function(mongoObject) { + files.save(mongoObject, self.writeConcern, function(err) { + if(typeof callback == 'function') + callback(err, mongoObject); + }); + }); + }); + } else { + self.uploadDate = new Date(); + buildMongoObject(self, function(mongoObject) { + files.save(mongoObject, self.writeConcern, function(err) { + if(typeof callback == 'function') + callback(err, mongoObject); + }); + }); + } + }); + }); + } else { + self.collection(function(err, files) { + if(err && typeof callback == 'function') return callback(err); + + self.uploadDate = new Date(); + buildMongoObject(self, function(mongoObject) { + files.save(mongoObject, self.writeConcern, function(err) { + if(typeof callback == 'function') + callback(err, mongoObject); + }); + }); + }); + } + } else if(self.mode[0] == "r") { + if(typeof callback == 'function') + callback(null, null); + } else { + if(typeof callback == 'function') + callback(new Error("Illegal mode " + self.mode), null); + } +}; + +/** + * Gets the nth chunk of this file. + * + * @param chunkNumber {number} The nth chunk to retrieve. + * @param callback {function(*, Chunk|object)} This will be called after + * executing this method. null will be passed to the first parameter while + * a new {@link Chunk} instance will be passed to the second parameter if + * the chunk was found or an empty object {} if not. + * + * @ignore + * @api private + */ +var nthChunk = function(self, chunkNumber, callback) { + self.chunkCollection(function(err, collection) { + if(err) return callback(err); + + collection.find({'files_id':self.fileId, 'n':chunkNumber}, {readPreference: self.readPreference}, function(err, cursor) { + if(err) return callback(err); + + cursor.nextObject(function(err, chunk) { + if(err) return callback(err); + + var finalChunk = chunk == null ? {} : chunk; + callback(null, new Chunk(self, finalChunk, self.writeConcern)); + }); + }); + }); +}; + +/** + * + * @ignore + * @api private + */ +GridStore.prototype._nthChunk = function(chunkNumber, callback) { + nthChunk(this, chunkNumber, callback); +} + +/** + * @return {Number} The last chunk number of this file. + * + * @ignore + * @api private + */ +var lastChunkNumber = function(self) { + return Math.floor(self.length/self.chunkSize); +}; + +/** + * Retrieve this file's chunks collection. + * + * @param {Function} callback this will be called after executing this method. An exception object will be passed to the first parameter when an error occured or null otherwise. A new **{Collection}** object will be passed to the second parameter if no error occured. + * @return {null} + * @api public + */ +GridStore.prototype.chunkCollection = function(callback) { + this.db.collection((this.root + ".chunks"), callback); +}; + +/** + * Deletes all the chunks of this file in the database. + * + * @param callback {function(*, boolean)} This will be called after this method + * executes. Passes null to the first and true to the second argument. + * + * @ignore + * @api private + */ +var deleteChunks = function(self, callback) { + if(self.fileId != null) { + self.chunkCollection(function(err, collection) { + if(err) return callback(err, false); + collection.remove({'files_id':self.fileId}, {safe:true}, function(err, result) { + if(err) return callback(err, false); + callback(null, true); + }); + }); + } else { + callback(null, true); + } +}; + +/** + * Deletes all the chunks of this file in the database. + * + * @param {Function} callback this will be called after this method executes. Passes null to the first and true to the second argument. + * @return {null} + * @api public + */ +GridStore.prototype.unlink = function(callback) { + var self = this; + deleteChunks(this, function(err) { + if(err!==null) { + err.message = "at deleteChunks: " + err.message; + return callback(err); + } + + self.collection(function(err, collection) { + if(err!==null) { + err.message = "at collection: " + err.message; + return callback(err); + } + + collection.remove({'_id':self.fileId}, {safe:true}, function(err) { + callback(err, self); + }); + }); + }); +}; + +/** + * Retrieves the file collection associated with this object. + * + * @param {Function} callback this will be called after executing this method. An exception object will be passed to the first parameter when an error occured or null otherwise. A new **{Collection}** object will be passed to the second parameter if no error occured. + * @return {null} + * @api public + */ +GridStore.prototype.collection = function(callback) { + this.db.collection(this.root + ".files", callback); +}; + +/** + * Reads the data of this file. + * + * @param {String} [separator] the character to be recognized as the newline separator. + * @param {Function} callback This will be called after this method is executed. The first parameter will be null and the second parameter will contain an array of strings representing the entire data, each element representing a line including the separator character. + * @return {null} + * @api public + */ +GridStore.prototype.readlines = function(separator, callback) { + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + separator = args.length ? args.shift() : "\n"; + + this.read(function(err, data) { + if(err) return callback(err); + + var items = data.toString().split(separator); + items = items.length > 0 ? items.splice(0, items.length - 1) : []; + for(var i = 0; i < items.length; i++) { + items[i] = items[i] + separator; + } + + callback(null, items); + }); +}; + +/** + * Deletes all the chunks of this file in the database if mode was set to "w" or + * "w+" and resets the read/write head to the initial position. + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain null and the second one will contain a reference to this object. + * @return {null} + * @api public + */ +GridStore.prototype.rewind = function(callback) { + var self = this; + + if(this.currentChunk.chunkNumber != 0) { + if(this.mode[0] == "w") { + deleteChunks(self, function(err, gridStore) { + if(err) return callback(err); + self.currentChunk = new Chunk(self, {'n': 0}, self.writeConcern); + self.position = 0; + callback(null, self); + }); + } else { + self.currentChunk(0, function(err, chunk) { + if(err) return callback(err); + self.currentChunk = chunk; + self.currentChunk.rewind(); + self.position = 0; + callback(null, self); + }); + } + } else { + self.currentChunk.rewind(); + self.position = 0; + callback(null, self); + } +}; + +/** + * Retrieves the contents of this file and advances the read/write head. Works with Buffers only. + * + * There are 3 signatures for this method: + * + * (callback) + * (length, callback) + * (length, buffer, callback) + * + * @param {Number} [length] the number of characters to read. Reads all the characters from the read/write head to the EOF if not specified. + * @param {String|Buffer} [buffer] a string to hold temporary data. This is used for storing the string data read so far when recursively calling this method. + * @param {Function} callback this will be called after this method is executed. null will be passed to the first parameter and a string containing the contents of the buffer concatenated with the contents read from this file will be passed to the second. + * @return {null} + * @api public + */ +GridStore.prototype.read = function(length, buffer, callback) { + var self = this; + + var args = Array.prototype.slice.call(arguments, 0); + callback = args.pop(); + length = args.length ? args.shift() : null; + buffer = args.length ? args.shift() : null; + + // The data is a c-terminated string and thus the length - 1 + var finalLength = length == null ? self.length - self.position : length; + var finalBuffer = buffer == null ? new Buffer(finalLength) : buffer; + // Add a index to buffer to keep track of writing position or apply current index + finalBuffer._index = buffer != null && buffer._index != null ? buffer._index : 0; + + if((self.currentChunk.length() - self.currentChunk.position + finalBuffer._index) >= finalLength) { + var slice = self.currentChunk.readSlice(finalLength - finalBuffer._index); + // Copy content to final buffer + slice.copy(finalBuffer, finalBuffer._index); + // Update internal position + self.position = self.position + finalBuffer.length; + // Check if we don't have a file at all + if(finalLength == 0 && finalBuffer.length == 0) return callback(new Error("File does not exist"), null); + // Else return data + callback(null, finalBuffer); + } else { + var slice = self.currentChunk.readSlice(self.currentChunk.length() - self.currentChunk.position); + // Copy content to final buffer + slice.copy(finalBuffer, finalBuffer._index); + // Update index position + finalBuffer._index += slice.length; + + // Load next chunk and read more + nthChunk(self, self.currentChunk.chunkNumber + 1, function(err, chunk) { + if(err) return callback(err); + + if(chunk.length() > 0) { + self.currentChunk = chunk; + self.read(length, finalBuffer, callback); + } else { + if (finalBuffer._index > 0) { + callback(null, finalBuffer) + } else { + callback(new Error("no chunks found for file, possibly corrupt"), null); + } + } + }); + } +} + +/** + * Retrieves the position of the read/write head of this file. + * + * @param {Function} callback This gets called after this method terminates. null is passed to the first parameter and the position is passed to the second. + * @return {null} + * @api public + */ +GridStore.prototype.tell = function(callback) { + callback(null, this.position); +}; + +/** + * Moves the read/write head to a new location. + * + * There are 3 signatures for this method + * + * Seek Location Modes + * - **GridStore.IO_SEEK_SET**, **(default)** set the position from the start of the file. + * - **GridStore.IO_SEEK_CUR**, set the position from the current position in the file. + * - **GridStore.IO_SEEK_END**, set the position from the end of the file. + * + * @param {Number} [position] the position to seek to + * @param {Number} [seekLocation] seek mode. Use one of the Seek Location modes. + * @param {Function} callback this will be called after executing this method. The first parameter will contain null and the second one will contain a reference to this object. + * @return {null} + * @api public + */ +GridStore.prototype.seek = function(position, seekLocation, callback) { + var self = this; + + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + seekLocation = args.length ? args.shift() : null; + + var seekLocationFinal = seekLocation == null ? exports.GridStore.IO_SEEK_SET : seekLocation; + var finalPosition = position; + var targetPosition = 0; + + // Calculate the position + if(seekLocationFinal == exports.GridStore.IO_SEEK_CUR) { + targetPosition = self.position + finalPosition; + } else if(seekLocationFinal == exports.GridStore.IO_SEEK_END) { + targetPosition = self.length + finalPosition; + } else { + targetPosition = finalPosition; + } + + // Get the chunk + var newChunkNumber = Math.floor(targetPosition/self.chunkSize); + if(newChunkNumber != self.currentChunk.chunkNumber) { + var seekChunk = function() { + nthChunk(self, newChunkNumber, function(err, chunk) { + self.currentChunk = chunk; + self.position = targetPosition; + self.currentChunk.position = (self.position % self.chunkSize); + callback(err, self); + }); + }; + + if(self.mode[0] == 'w') { + self.currentChunk.save(function(err) { + if(err) return callback(err); + seekChunk(); + }); + } else { + seekChunk(); + } + } else { + self.position = targetPosition; + self.currentChunk.position = (self.position % self.chunkSize); + callback(null, self); + } +}; + +/** + * Verify if the file is at EOF. + * + * @return {Boolean} true if the read/write head is at the end of this file. + * @api public + */ +GridStore.prototype.eof = function() { + return this.position == this.length ? true : false; +}; + +/** + * Retrieves a single character from this file. + * + * @param {Function} callback this gets called after this method is executed. Passes null to the first parameter and the character read to the second or null to the second if the read/write head is at the end of the file. + * @return {null} + * @api public + */ +GridStore.prototype.getc = function(callback) { + var self = this; + + if(self.eof()) { + callback(null, null); + } else if(self.currentChunk.eof()) { + nthChunk(self, self.currentChunk.chunkNumber + 1, function(err, chunk) { + self.currentChunk = chunk; + self.position = self.position + 1; + callback(err, self.currentChunk.getc()); + }); + } else { + self.position = self.position + 1; + callback(null, self.currentChunk.getc()); + } +}; + +/** + * Writes a string to the file with a newline character appended at the end if + * the given string does not have one. + * + * @param {String} string the string to write. + * @param {Function} callback this will be called after executing this method. The first parameter will contain null and the second one will contain a reference to this object. + * @return {null} + * @api public + */ +GridStore.prototype.puts = function(string, callback) { + var finalString = string.match(/\n$/) == null ? string + "\n" : string; + this.write(finalString, callback); +}; + +/** + * Returns read stream based on this GridStore file + * + * Events + * - **data** {function(item) {}} the data event triggers when a document is ready. + * - **end** {function() {}} the end event triggers when there is no more documents available. + * - **close** {function() {}} the close event triggers when the stream is closed. + * - **error** {function(err) {}} the error event triggers if an error happens. + * + * @param {Boolean} autoclose if true current GridStore will be closed when EOF and 'close' event will be fired + * @return {null} + * @api public + */ +GridStore.prototype.stream = function(autoclose) { + return new ReadStream(autoclose, this); +}; + +/** +* The collection to be used for holding the files and chunks collection. +* +* @classconstant DEFAULT_ROOT_COLLECTION +**/ +GridStore.DEFAULT_ROOT_COLLECTION = 'fs'; + +/** +* Default file mime type +* +* @classconstant DEFAULT_CONTENT_TYPE +**/ +GridStore.DEFAULT_CONTENT_TYPE = 'binary/octet-stream'; + +/** +* Seek mode where the given length is absolute. +* +* @classconstant IO_SEEK_SET +**/ +GridStore.IO_SEEK_SET = 0; + +/** +* Seek mode where the given length is an offset to the current read/write head. +* +* @classconstant IO_SEEK_CUR +**/ +GridStore.IO_SEEK_CUR = 1; + +/** +* Seek mode where the given length is an offset to the end of the file. +* +* @classconstant IO_SEEK_END +**/ +GridStore.IO_SEEK_END = 2; + +/** + * Checks if a file exists in the database. + * + * Options + * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST). + * + * @param {Db} db the database to query. + * @param {String} name the name of the file to look for. + * @param {String} [rootCollection] the root collection that holds the files and chunks collection. Defaults to **{GridStore.DEFAULT_ROOT_COLLECTION}**. + * @param {Function} callback this will be called after this method executes. Passes null to the first and passes true to the second if the file exists and false otherwise. + * @return {null} + * @api public + */ +GridStore.exist = function(db, fileIdObject, rootCollection, options, callback) { + var args = Array.prototype.slice.call(arguments, 2); + callback = args.pop(); + rootCollection = args.length ? args.shift() : null; + options = args.length ? args.shift() : {}; + + // Establish read preference + var readPreference = options.readPreference || 'primary'; + // Fetch collection + var rootCollectionFinal = rootCollection != null ? rootCollection : GridStore.DEFAULT_ROOT_COLLECTION; + db.collection(rootCollectionFinal + ".files", function(err, collection) { + if(err) return callback(err); + + // Build query + var query = (typeof fileIdObject == 'string' || Object.prototype.toString.call(fileIdObject) == '[object RegExp]' ) + ? {'filename':fileIdObject} + : {'_id':fileIdObject}; // Attempt to locate file + + collection.find(query, {readPreference:readPreference}, function(err, cursor) { + if(err) return callback(err); + + cursor.nextObject(function(err, item) { + if(err) return callback(err); + callback(null, item == null ? false : true); + }); + }); + }); +}; + +/** + * Gets the list of files stored in the GridFS. + * + * @param {Db} db the database to query. + * @param {String} [rootCollection] the root collection that holds the files and chunks collection. Defaults to **{GridStore.DEFAULT_ROOT_COLLECTION}**. + * @param {Function} callback this will be called after this method executes. Passes null to the first and passes an array of strings containing the names of the files. + * @return {null} + * @api public + */ +GridStore.list = function(db, rootCollection, options, callback) { + var args = Array.prototype.slice.call(arguments, 1); + callback = args.pop(); + rootCollection = args.length ? args.shift() : null; + options = args.length ? args.shift() : {}; + + // Ensure we have correct values + if(rootCollection != null && typeof rootCollection == 'object') { + options = rootCollection; + rootCollection = null; + } + + // Establish read preference + var readPreference = options.readPreference || 'primary'; + // Check if we are returning by id not filename + var byId = options['id'] != null ? options['id'] : false; + // Fetch item + var rootCollectionFinal = rootCollection != null ? rootCollection : GridStore.DEFAULT_ROOT_COLLECTION; + var items = []; + db.collection((rootCollectionFinal + ".files"), function(err, collection) { + if(err) return callback(err); + + collection.find({}, {readPreference:readPreference}, function(err, cursor) { + if(err) return callback(err); + + cursor.each(function(err, item) { + if(item != null) { + items.push(byId ? item._id : item.filename); + } else { + callback(err, items); + } + }); + }); + }); +}; + +/** + * Reads the contents of a file. + * + * This method has the following signatures + * + * (db, name, callback) + * (db, name, length, callback) + * (db, name, length, offset, callback) + * (db, name, length, offset, options, callback) + * + * @param {Db} db the database to query. + * @param {String} name the name of the file. + * @param {Number} [length] the size of data to read. + * @param {Number} [offset] the offset from the head of the file of which to start reading from. + * @param {Object} [options] the options for the file. + * @param {Function} callback this will be called after this method executes. A string with an error message will be passed to the first parameter when the length and offset combination exceeds the length of the file while an Error object will be passed if other forms of error occured, otherwise, a string is passed. The second parameter will contain the data read if successful or null if an error occured. + * @return {null} + * @api public + */ +GridStore.read = function(db, name, length, offset, options, callback) { + var args = Array.prototype.slice.call(arguments, 2); + callback = args.pop(); + length = args.length ? args.shift() : null; + offset = args.length ? args.shift() : null; + options = args.length ? args.shift() : null; + + new GridStore(db, name, "r", options).open(function(err, gridStore) { + if(err) return callback(err); + // Make sure we are not reading out of bounds + if(offset && offset >= gridStore.length) return callback("offset larger than size of file", null); + if(length && length > gridStore.length) return callback("length is larger than the size of the file", null); + if(offset && length && (offset + length) > gridStore.length) return callback("offset and length is larger than the size of the file", null); + + if(offset != null) { + gridStore.seek(offset, function(err, gridStore) { + if(err) return callback(err); + gridStore.read(length, callback); + }); + } else { + gridStore.read(length, callback); + } + }); +}; + +/** + * Reads the data of this file. + * + * @param {Db} db the database to query. + * @param {String} name the name of the file. + * @param {String} [separator] the character to be recognized as the newline separator. + * @param {Object} [options] file options. + * @param {Function} callback this will be called after this method is executed. The first parameter will be null and the second parameter will contain an array of strings representing the entire data, each element representing a line including the separator character. + * @return {null} + * @api public + */ +GridStore.readlines = function(db, name, separator, options, callback) { + var args = Array.prototype.slice.call(arguments, 2); + callback = args.pop(); + separator = args.length ? args.shift() : null; + options = args.length ? args.shift() : null; + + var finalSeperator = separator == null ? "\n" : separator; + new GridStore(db, name, "r", options).open(function(err, gridStore) { + if(err) return callback(err); + gridStore.readlines(finalSeperator, callback); + }); +}; + +/** + * Deletes the chunks and metadata information of a file from GridFS. + * + * @param {Db} db the database to interact with. + * @param {String|Array} names the name/names of the files to delete. + * @param {Object} [options] the options for the files. + * @callback {Function} this will be called after this method is executed. The first parameter will contain an Error object if an error occured or null otherwise. The second parameter will contain a reference to this object. + * @return {null} + * @api public + */ +GridStore.unlink = function(db, names, options, callback) { + var self = this; + var args = Array.prototype.slice.call(arguments, 2); + callback = args.pop(); + options = args.length ? args.shift() : null; + + if(names.constructor == Array) { + var tc = 0; + for(var i = 0; i < names.length; i++) { + ++tc; + self.unlink(db, names[i], options, function(result) { + if(--tc == 0) { + callback(null, self); + } + }); + } + } else { + new GridStore(db, names, "w", options).open(function(err, gridStore) { + if(err) return callback(err); + deleteChunks(gridStore, function(err, result) { + if(err) return callback(err); + gridStore.collection(function(err, collection) { + if(err) return callback(err); + collection.remove({'_id':gridStore.fileId}, {safe:true}, function(err, collection) { + callback(err, self); + }); + }); + }); + }); + } +}; + +/** + * Returns the current chunksize of the file. + * + * @field chunkSize + * @type {Number} + * @getter + * @setter + * @property return number of bytes in the current chunkSize. + */ +Object.defineProperty(GridStore.prototype, "chunkSize", { enumerable: true + , get: function () { + return this.internalChunkSize; + } + , set: function(value) { + if(!(this.mode[0] == "w" && this.position == 0 && this.uploadDate == null)) { + this.internalChunkSize = this.internalChunkSize; + } else { + this.internalChunkSize = value; + } + } +}); + +/** + * The md5 checksum for this file. + * + * @field md5 + * @type {Number} + * @getter + * @setter + * @property return this files md5 checksum. + */ +Object.defineProperty(GridStore.prototype, "md5", { enumerable: true + , get: function () { + return this.internalMd5; + } +}); + +/** + * GridStore Streaming methods + * Handles the correct return of the writeable stream status + * @ignore + */ +Object.defineProperty(GridStore.prototype, "writable", { enumerable: true + , get: function () { + if(this._writeable == null) { + this._writeable = this.mode != null && this.mode.indexOf("w") != -1; + } + // Return the _writeable + return this._writeable; + } + , set: function(value) { + this._writeable = value; + } +}); + +/** + * Handles the correct return of the readable stream status + * @ignore + */ +Object.defineProperty(GridStore.prototype, "readable", { enumerable: true + , get: function () { + if(this._readable == null) { + this._readable = this.mode != null && this.mode.indexOf("r") != -1; + } + return this._readable; + } + , set: function(value) { + this._readable = value; + } +}); + +GridStore.prototype.paused; + +/** + * Handles the correct setting of encoding for the stream + * @ignore + */ +GridStore.prototype.setEncoding = fs.ReadStream.prototype.setEncoding; + +/** + * Handles the end events + * @ignore + */ +GridStore.prototype.end = function end(data) { + var self = this; + // allow queued data to write before closing + if(!this.writable) return; + this.writable = false; + + if(data) { + this._q.push(data); + } + + this.on('drain', function () { + self.close(function (err) { + if (err) return _error(self, err); + self.emit('close'); + }); + }); + + _flush(self); +} + +/** + * Handles the normal writes to gridstore + * @ignore + */ +var _writeNormal = function(self, data, close, callback) { + // If we have a buffer write it using the writeBuffer method + if(Buffer.isBuffer(data)) { + return writeBuffer(self, data, close, callback); + } else { + // Wrap the string in a buffer and write + return writeBuffer(self, new Buffer(data, 'binary'), close, callback); + } +} + +/** + * Writes some data. This method will work properly only if initialized with mode "w" or "w+". + * + * @param {String|Buffer} data the data to write. + * @param {Boolean} [close] closes this file after writing if set to true. + * @param {Function} callback this will be called after executing this method. The first parameter will contain null and the second one will contain a reference to this object. + * @return {null} + * @api public + */ +GridStore.prototype.write = function write(data, close, callback) { + // If it's a normal write delegate the call + if(typeof close == 'function' || typeof callback == 'function') { + return _writeNormal(this, data, close, callback); + } + + // Otherwise it's a stream write + var self = this; + if (!this.writable) { + throw new Error('GridWriteStream is not writable'); + } + + // queue data until we open. + if (!this._opened) { + // Set up a queue to save data until gridstore object is ready + this._q = []; + _openStream(self); + this._q.push(data); + return false; + } + + // Push data to queue + this._q.push(data); + _flush(this); + // Return write successful + return true; +} + +/** + * Handles the destroy part of a stream + * @ignore + */ +GridStore.prototype.destroy = function destroy() { + // close and do not emit any more events. queued data is not sent. + if(!this.writable) return; + this.readable = false; + if(this.writable) { + this.writable = false; + this._q.length = 0; + this.emit('close'); + } +} + +/** + * Handles the destroySoon part of a stream + * @ignore + */ +GridStore.prototype.destroySoon = function destroySoon() { + // as soon as write queue is drained, destroy. + // may call destroy immediately if no data is queued. + if(!this._q.length) { + return this.destroy(); + } + this._destroying = true; +} + +/** + * Handles the pipe part of the stream + * @ignore + */ +GridStore.prototype.pipe = function(destination, options) { + var self = this; + // Open the gridstore + this.open(function(err, result) { + if(err) _errorRead(self, err); + if(!self.readable) return; + // Set up the pipe + self._pipe(destination, options); + // Emit the stream is open + self.emit('open'); + // Read from the stream + _read(self); + }) +} + +/** + * Internal module methods + * @ignore + */ +var _read = function _read(self) { + if (!self.readable || self.paused || self.reading) { + return; + } + + self.reading = true; + var stream = self._stream = self.stream(); + stream.paused = self.paused; + + stream.on('data', function (data) { + if (self._decoder) { + var str = self._decoder.write(data); + if (str.length) self.emit('data', str); + } else { + self.emit('data', data); + } + }); + + stream.on('end', function (data) { + self.emit('end', data); + }); + + stream.on('error', function (data) { + _errorRead(self, data); + }); + + stream.on('close', function (data) { + self.emit('close', data); + }); + + self.pause = function () { + // native doesn't always pause. + // bypass its pause() method to hack it + self.paused = stream.paused = true; + } + + self.resume = function () { + if(!self.paused) return; + + self.paused = false; + stream.resume(); + self.readable = stream.readable; + } + + self.destroy = function () { + self.readable = false; + stream.destroy(); + } +} + +/** + * pause + * @ignore + */ +GridStore.prototype.pause = function pause () { + // Overridden when the GridStore opens. + this.paused = true; +} + +/** + * resume + * @ignore + */ +GridStore.prototype.resume = function resume () { + // Overridden when the GridStore opens. + this.paused = false; +} + +/** + * Internal module methods + * @ignore + */ +var _flush = function _flush(self, _force) { + if (!self._opened) return; + if (!_force && self._flushing) return; + self._flushing = true; + + // write the entire q to gridfs + if (!self._q.length) { + self._flushing = false; + self.emit('drain'); + + if(self._destroying) { + self.destroy(); + } + return; + } + + self.write(self._q.shift(), function (err, store) { + if (err) return _error(self, err); + self.emit('progress', store.position); + _flush(self, true); + }); +} + +var _openStream = function _openStream (self) { + if(self._opening == true) return; + self._opening = true; + + // Open the store + self.open(function (err, gridstore) { + if (err) return _error(self, err); + self._opened = true; + self.emit('open'); + _flush(self); + }); +} + +var _error = function _error(self, err) { + self.destroy(); + self.emit('error', err); +} + +var _errorRead = function _errorRead (self, err) { + self.readable = false; + self.emit('error', err); +} + +/** + * @ignore + */ +var _hasWriteConcern = function(errorOptions) { + return errorOptions == true + || errorOptions.w > 0 + || errorOptions.w == 'majority' + || errorOptions.j == true + || errorOptions.journal == true + || errorOptions.fsync == true +} + +/** + * @ignore + */ +var _setWriteConcernHash = function(options) { + var finalOptions = {}; + if(options.w != null) finalOptions.w = options.w; + if(options.journal == true) finalOptions.j = options.journal; + if(options.j == true) finalOptions.j = options.j; + if(options.fsync == true) finalOptions.fsync = options.fsync; + if(options.wtimeout != null) finalOptions.wtimeout = options.wtimeout; + return finalOptions; +} + +/** + * @ignore + */ +var _getWriteConcern = function(self, options, callback) { + // Final options + var finalOptions = {w:1}; + options = options || {}; + // Local options verification + if(options.w != null || typeof options.j == 'boolean' || typeof options.journal == 'boolean' || typeof options.fsync == 'boolean') { + finalOptions = _setWriteConcernHash(options); + } else if(typeof options.safe == "boolean") { + finalOptions = {w: (options.safe ? 1 : 0)}; + } else if(options.safe != null && typeof options.safe == 'object') { + finalOptions = _setWriteConcernHash(options.safe); + } else if(self.db.safe.w != null || typeof self.db.safe.j == 'boolean' || typeof self.db.safe.journal == 'boolean' || typeof self.db.safe.fsync == 'boolean') { + finalOptions = _setWriteConcernHash(self.db.safe); + } else if(self.db.options.w != null || typeof self.db.options.j == 'boolean' || typeof self.db.options.journal == 'boolean' || typeof self.db.options.fsync == 'boolean') { + finalOptions = _setWriteConcernHash(self.db.options); + } else if(typeof self.db.safe == "boolean") { + finalOptions = {w: (self.db.safe ? 1 : 0)}; + } + + // Ensure we don't have an invalid combination of write concerns + if(finalOptions.w < 1 + && (finalOptions.journal == true || finalOptions.j == true || finalOptions.fsync == true)) throw new Error("No acknowlegement using w < 1 cannot be combined with journal:true or fsync:true"); + + // Return the options + return finalOptions; +} + +/** + * @ignore + * @api private + */ +exports.GridStore = GridStore; diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/gridfs/readstream.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/gridfs/readstream.js new file mode 100644 index 0000000..30ea725 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/gridfs/readstream.js @@ -0,0 +1,192 @@ +var Stream = require('stream').Stream, + timers = require('timers'), + util = require('util'); + +// Set processor, setImmediate if 0.10 otherwise nextTick +var processor = require('../utils').processor(); + +/** + * ReadStream + * + * Returns a stream interface for the **file**. + * + * Events + * - **data** {function(item) {}} the data event triggers when a document is ready. + * - **end** {function() {}} the end event triggers when there is no more documents available. + * - **close** {function() {}} the close event triggers when the stream is closed. + * - **error** {function(err) {}} the error event triggers if an error happens. + * + * @class Represents a GridFS File Stream. + * @param {Boolean} autoclose automatically close file when the stream reaches the end. + * @param {GridStore} cursor a cursor object that the stream wraps. + * @return {ReadStream} + */ +function ReadStream(autoclose, gstore) { + if (!(this instanceof ReadStream)) return new ReadStream(autoclose, gstore); + Stream.call(this); + + this.autoclose = !!autoclose; + this.gstore = gstore; + + this.finalLength = gstore.length - gstore.position; + this.completedLength = 0; + this.currentChunkNumber = gstore.currentChunk.chunkNumber; + + this.paused = false; + this.readable = true; + this.pendingChunk = null; + this.executing = false; + + // Calculate the number of chunks + this.numberOfChunks = Math.ceil(gstore.length/gstore.chunkSize); + + // This seek start position inside the current chunk + this.seekStartPosition = gstore.position - (this.currentChunkNumber * gstore.chunkSize); + + var self = this; + processor(function() { + self._execute(); + }); +}; + +/** + * Inherit from Stream + * @ignore + * @api private + */ +ReadStream.prototype.__proto__ = Stream.prototype; + +/** + * Flag stating whether or not this stream is readable. + */ +ReadStream.prototype.readable; + +/** + * Flag stating whether or not this stream is paused. + */ +ReadStream.prototype.paused; + +/** + * @ignore + * @api private + */ +ReadStream.prototype._execute = function() { + if(this.paused === true || this.readable === false) { + return; + } + + var gstore = this.gstore; + var self = this; + // Set that we are executing + this.executing = true; + + var last = false; + var toRead = 0; + + if(gstore.currentChunk.chunkNumber >= (this.numberOfChunks - 1)) { + self.executing = false; + last = true; + } + + // Data setup + var data = null; + + // Read a slice (with seek set if none) + if(this.seekStartPosition > 0 && (gstore.currentChunk.length() - this.seekStartPosition) > 0) { + data = gstore.currentChunk.readSlice(gstore.currentChunk.length() - this.seekStartPosition); + this.seekStartPosition = 0; + } else { + data = gstore.currentChunk.readSlice(gstore.currentChunk.length()); + } + + // Return the data + if(data != null && gstore.currentChunk.chunkNumber == self.currentChunkNumber) { + self.currentChunkNumber = self.currentChunkNumber + 1; + self.completedLength += data.length; + self.pendingChunk = null; + self.emit("data", data); + } + + if(last === true) { + self.readable = false; + self.emit("end"); + + if(self.autoclose === true) { + if(gstore.mode[0] == "w") { + gstore.close(function(err, doc) { + if (err) { + self.emit("error", err); + return; + } + self.readable = false; + self.emit("close", doc); + }); + } else { + self.readable = false; + self.emit("close"); + } + } + } else { + gstore._nthChunk(gstore.currentChunk.chunkNumber + 1, function(err, chunk) { + if(err) { + self.readable = false; + self.emit("error", err); + self.executing = false; + return; + } + + self.pendingChunk = chunk; + if(self.paused === true) { + self.executing = false; + return; + } + + gstore.currentChunk = self.pendingChunk; + self._execute(); + }); + } +}; + +/** + * Pauses this stream, then no farther events will be fired. + * + * @ignore + * @api public + */ +ReadStream.prototype.pause = function() { + if(!this.executing) { + this.paused = true; + } +}; + +/** + * Destroys the stream, then no farther events will be fired. + * + * @ignore + * @api public + */ +ReadStream.prototype.destroy = function() { + this.readable = false; + // Emit close event + this.emit("close"); +}; + +/** + * Resumes this stream. + * + * @ignore + * @api public + */ +ReadStream.prototype.resume = function() { + if(this.paused === false || !this.readable) { + return; + } + + this.paused = false; + var self = this; + processor(function() { + self._execute(); + }); +}; + +exports.ReadStream = ReadStream; diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/index.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/index.js new file mode 100644 index 0000000..91d28df --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/index.js @@ -0,0 +1,69 @@ +try { + exports.BSONPure = require('bson').BSONPure; + exports.BSONNative = require('bson').BSONNative; +} catch(err) { + // do nothing +} + +// export the driver version +exports.version = require('../../package').version; + +[ 'commands/base_command' + , 'admin' + , 'collection' + , 'connection/read_preference' + , 'connection/connection' + , 'connection/server' + , 'connection/mongos' + , 'connection/repl_set/repl_set' + , 'mongo_client' + , 'cursor' + , 'db' + , 'mongo_client' + , 'gridfs/grid' + , 'gridfs/chunk' + , 'gridfs/gridstore'].forEach(function (path) { + var module = require('./' + path); + for (var i in module) { + exports[i] = module[i]; + } +}); + +// backwards compat +exports.ReplSetServers = exports.ReplSet; +// Add BSON Classes +exports.Binary = require('bson').Binary; +exports.Code = require('bson').Code; +exports.DBRef = require('bson').DBRef; +exports.Double = require('bson').Double; +exports.Long = require('bson').Long; +exports.MinKey = require('bson').MinKey; +exports.MaxKey = require('bson').MaxKey; +exports.ObjectID = require('bson').ObjectID; +exports.Symbol = require('bson').Symbol; +exports.Timestamp = require('bson').Timestamp; +// Add BSON Parser +exports.BSON = require('bson').BSONPure.BSON; + +// Get the Db object +var Db = require('./db').Db; +// Set up the connect function +var connect = Db.connect; +var obj = connect; +// Map all values to the exports value +for(var name in exports) { + obj[name] = exports[name]; +} + +// Add the pure and native backward compatible functions +exports.pure = exports.native = function() { + return obj; +} + +// Map all values to the exports value +for(var name in exports) { + connect[name] = exports[name]; +} + +// Set our exports to be the connect function +module.exports = connect; diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/mongo_client.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/mongo_client.js new file mode 100644 index 0000000..a7372bf --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/mongo_client.js @@ -0,0 +1,419 @@ +var Db = require('./db').Db + , Server = require('./connection/server').Server + , Mongos = require('./connection/mongos').Mongos + , ReplSet = require('./connection/repl_set/repl_set').ReplSet + , ReadPreference = require('./connection/read_preference').ReadPreference + , inherits = require('util').inherits + , EventEmitter = require('events').EventEmitter + , parse = require('./connection/url_parser').parse; + +/** + * Create a new MongoClient instance. + * + * Options + * - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write + * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option) + * - **fsync**, (Boolean, default:false) write waits for fsync before returning + * - **journal**, (Boolean, default:false) write waits for journal sync before returning + * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST). + * - **native_parser** {Boolean, default:false}, use c++ bson parser. + * - **forceServerObjectId** {Boolean, default:false}, force server to create _id fields instead of client. + * - **pkFactory** {Object}, object overriding the basic ObjectID primary key generation. + * - **serializeFunctions** {Boolean, default:false}, serialize functions. + * - **raw** {Boolean, default:false}, peform operations using raw bson buffers. + * - **recordQueryStats** {Boolean, default:false}, record query statistics during execution. + * - **retryMiliSeconds** {Number, default:5000}, number of miliseconds between retries. + * - **numberOfRetries** {Number, default:5}, number of retries off connection. + * + * Deprecated Options + * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB. + * + * @class Represents a MongoClient + * @param {Object} serverConfig server config object. + * @param {Object} [options] additional options for the collection. + */ +function MongoClient(serverConfig, options) { + if(serverConfig != null) { + options = options == null ? {} : options; + // If no write concern is set set the default to w:1 + if(options != null && !options.journal && !options.w && !options.fsync) { + options.w = 1; + } + + // The internal db instance we are wrapping + this._db = new Db('test', serverConfig, options); + } +} + +/** + * @ignore + */ +inherits(MongoClient, EventEmitter); + +/** + * Connect to MongoDB using a url as documented at + * + * docs.mongodb.org/manual/reference/connection-string/ + * + * Options + * - **uri_decode_auth** {Boolean, default:false} uri decode the user name and password for authentication + * - **db** {Object, default: null} a hash off options to set on the db object, see **Db constructor** + * - **server** {Object, default: null} a hash off options to set on the server objects, see **Server** constructor** + * - **replSet** {Object, default: null} a hash off options to set on the replSet object, see **ReplSet** constructor** + * - **mongos** {Object, default: null} a hash off options to set on the mongos object, see **Mongos** constructor** + * + * @param {String} url connection url for MongoDB. + * @param {Object} [options] optional options for insert command + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the initialized db object or null if an error occured. + * @return {null} + * @api public + */ +MongoClient.prototype.connect = function(url, options, callback) { + var self = this; + + if(typeof options == 'function') { + callback = options; + options = {}; + } + + MongoClient.connect(url, options, function(err, db) { + if(err) return callback(err, db); + // Store internal db instance reference + self._db = db; + // Emit open and perform callback + self.emit("open", err, db); + callback(err, db); + }); +} + +/** + * Initialize the database connection. + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the connected mongoclient or null if an error occured. + * @return {null} + * @api public + */ +MongoClient.prototype.open = function(callback) { + // Self reference + var self = this; + // Open the db + this._db.open(function(err, db) { + if(err) return callback(err, null); + // Emit open event + self.emit("open", err, db); + // Callback + callback(null, self); + }) +} + +/** + * Close the current db connection, including all the child db instances. Emits close event if no callback is provided. + * + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the close method or null if an error occured. + * @return {null} + * @api public + */ +MongoClient.prototype.close = function(callback) { + this._db.close(callback); +} + +/** + * Create a new Db instance sharing the current socket connections. + * + * @param {String} dbName the name of the database we want to use. + * @return {Db} a db instance using the new database. + * @api public + */ +MongoClient.prototype.db = function(dbName) { + return this._db.db(dbName); +} + +/** + * Connect to MongoDB using a url as documented at + * + * docs.mongodb.org/manual/reference/connection-string/ + * + * Options + * - **uri_decode_auth** {Boolean, default:false} uri decode the user name and password for authentication + * - **db** {Object, default: null} a hash off options to set on the db object, see **Db constructor** + * - **server** {Object, default: null} a hash off options to set on the server objects, see **Server** constructor** + * - **replSet** {Object, default: null} a hash off options to set on the replSet object, see **ReplSet** constructor** + * - **mongos** {Object, default: null} a hash off options to set on the mongos object, see **Mongos** constructor** + * + * @param {String} url connection url for MongoDB. + * @param {Object} [options] optional options for insert command + * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the initialized db object or null if an error occured. + * @return {null} + * @api public + */ +MongoClient.connect = function(url, options, callback) { + var args = Array.prototype.slice.call(arguments, 1); + callback = typeof args[args.length - 1] == 'function' ? args.pop() : null; + options = args.length ? args.shift() : null; + options = options || {}; + + // Set default empty server options + var serverOptions = options.server || {}; + var mongosOptions = options.mongos || {}; + var replSetServersOptions = options.replSet || options.replSetServers || {}; + var dbOptions = options.db || {}; + + // If callback is null throw an exception + if(callback == null) + throw new Error("no callback function provided"); + + // Parse the string + var object = parse(url, options); + // Merge in any options for db in options object + if(dbOptions) { + for(var name in dbOptions) object.db_options[name] = dbOptions[name]; + } + + // Added the url to the options + object.db_options.url = url; + + // Merge in any options for server in options object + if(serverOptions) { + for(var name in serverOptions) object.server_options[name] = serverOptions[name]; + } + + // Merge in any replicaset server options + if(replSetServersOptions) { + for(var name in replSetServersOptions) object.rs_options[name] = replSetServersOptions[name]; + } + + // Merge in any replicaset server options + if(mongosOptions) { + for(var name in mongosOptions) object.mongos_options[name] = mongosOptions[name]; + } + + // We need to ensure that the list of servers are only either direct members or mongos + // they cannot be a mix of monogs and mongod's + var totalNumberOfServers = object.servers.length; + var totalNumberOfMongosServers = 0; + var totalNumberOfMongodServers = 0; + var serverConfig = null; + var errorServers = {}; + + // Failure modes + if(object.servers.length == 0) throw new Error("connection string must contain at least one seed host"); + + // If we have no db setting for the native parser try to set the c++ one first + object.db_options.native_parser = _setNativeParser(object.db_options); + // If no auto_reconnect is set, set it to true as default for single servers + if(typeof object.server_options.auto_reconnect != 'boolean') { + object.server_options.auto_reconnect = true; + } + + // If we have more than a server, it could be replicaset or mongos list + // need to verify that it's one or the other and fail if it's a mix + // Connect to all servers and run ismaster + for(var i = 0; i < object.servers.length; i++) { + // Set up socket options + var _server_options = {poolSize:1, socketOptions:{connectTimeoutMS:1000}, auto_reconnect:false}; + + // Ensure we have ssl setup for the servers + if(object.rs_options.ssl) { + _server_options.ssl = object.rs_options.ssl; + _server_options.sslValidate = object.rs_options.sslValidate; + _server_options.sslCA = object.rs_options.sslCA; + _server_options.sslCert = object.rs_options.sslCert; + _server_options.sslKey = object.rs_options.sslKey; + _server_options.sslPass = object.rs_options.sslPass; + } else if(object.server_options.ssl) { + _server_options.ssl = object.server_options.ssl; + _server_options.sslValidate = object.server_options.sslValidate; + _server_options.sslCA = object.server_options.sslCA; + _server_options.sslCert = object.server_options.sslCert; + _server_options.sslKey = object.server_options.sslKey; + _server_options.sslPass = object.server_options.sslPass; + } + + // Set up the Server object + var _server = object.servers[i].domain_socket + ? new Server(object.servers[i].domain_socket, _server_options) + : new Server(object.servers[i].host, object.servers[i].port, _server_options); + + var connectFunction = function(__server) { + // Attempt connect + new Db(object.dbName, __server, {safe:false, native_parser:false}).open(function(err, db) { + // Update number of servers + totalNumberOfServers = totalNumberOfServers - 1; + // If no error do the correct checks + if(!err) { + // Close the connection + db.close(true); + var isMasterDoc = db.serverConfig.isMasterDoc; + // Check what type of server we have + if(isMasterDoc.setName) totalNumberOfMongodServers++; + if(isMasterDoc.msg && isMasterDoc.msg == "isdbgrid") totalNumberOfMongosServers++; + } else { + errorServers[__server.host + ":" + __server.port] = __server; + } + + if(totalNumberOfServers == 0) { + // If we have a mix of mongod and mongos, throw an error + if(totalNumberOfMongosServers > 0 && totalNumberOfMongodServers > 0) { + return process.nextTick(function() { + try { + callback(new Error("cannot combine a list of replicaset seeds and mongos seeds")); + } catch (err) { + if(db) db.close(); + throw err + } + }) + } + + if(totalNumberOfMongodServers == 0 && object.servers.length == 1) { + var obj = object.servers[0]; + serverConfig = obj.domain_socket ? + new Server(obj.domain_socket, object.server_options) + : new Server(obj.host, obj.port, object.server_options); + } else if(totalNumberOfMongodServers > 0 || totalNumberOfMongosServers > 0) { + var finalServers = object.servers + .filter(function(serverObj) { + return errorServers[serverObj.host + ":" + serverObj.port] == null; + }) + .map(function(serverObj) { + return new Server(serverObj.host, serverObj.port, object.server_options); + }); + // Clean out any error servers + errorServers = {}; + // Set up the final configuration + if(totalNumberOfMongodServers > 0) { + serverConfig = new ReplSet(finalServers, object.rs_options); + } else { + serverConfig = new Mongos(finalServers, object.mongos_options); + } + } + + if(serverConfig == null) { + return process.nextTick(function() { + try { + callback(new Error("Could not locate any valid servers in initial seed list")); + } catch (err) { + if(db) db.close(); + throw err + } + }); + } + // Ensure no firing off open event before we are ready + serverConfig.emitOpen = false; + // Set up all options etc and connect to the database + _finishConnecting(serverConfig, object, options, callback) + } + }); + } + + // Wrap the context of the call + connectFunction(_server); + } +} + +var _setNativeParser = function(db_options) { + if(typeof db_options.native_parser == 'boolean') return db_options.native_parser; + + try { + require('bson').BSONNative.BSON; + return true; + } catch(err) { + return false; + } +} + +var _finishConnecting = function(serverConfig, object, options, callback) { + // Safe settings + var safe = {}; + // Build the safe parameter if needed + if(object.db_options.journal) safe.j = object.db_options.journal; + if(object.db_options.w) safe.w = object.db_options.w; + if(object.db_options.fsync) safe.fsync = object.db_options.fsync; + if(object.db_options.wtimeoutMS) safe.wtimeout = object.db_options.wtimeoutMS; + + // If we have a read Preference set + if(object.db_options.read_preference) { + var readPreference = new ReadPreference(object.db_options.read_preference); + // If we have the tags set up + if(object.db_options.read_preference_tags) + readPreference = new ReadPreference(object.db_options.read_preference, object.db_options.read_preference_tags); + // Add the read preference + object.db_options.readPreference = readPreference; + } + + // No safe mode if no keys + if(Object.keys(safe).length == 0) safe = false; + + // Add the safe object + object.db_options.safe = safe; + + // Set up the db options + var db = new Db(object.dbName, serverConfig, object.db_options); + // Open the db + db.open(function(err, db){ + if(err) { + return process.nextTick(function() { + try { + callback(err, null); + } catch (err) { + if(db) db.close(); + throw err + } + }); + } + + if(db.options !== null && !db.options.safe && !db.options.journal + && !db.options.w && !db.options.fsync && typeof db.options.w != 'number' + && (db.options.safe == false && object.db_options.url.indexOf("safe=") == -1)) { + db.options.w = 1; + } + + if(err == null && object.auth){ + // What db to authenticate against + var authentication_db = db; + if(object.db_options && object.db_options.authSource) { + authentication_db = db.db(object.db_options.authSource); + } + + // Build options object + var options = {}; + if(object.db_options.authMechanism) options.authMechanism = object.db_options.authMechanism; + if(object.db_options.gssapiServiceName) options.gssapiServiceName = object.db_options.gssapiServiceName; + + // Authenticate + authentication_db.authenticate(object.auth.user, object.auth.password, options, function(err, success){ + if(success){ + process.nextTick(function() { + try { + callback(null, db); + } catch (err) { + if(db) db.close(); + throw err + } + }); + } else { + if(db) db.close(); + process.nextTick(function() { + try { + callback(err ? err : new Error('Could not authenticate user ' + auth[0]), null); + } catch (err) { + if(db) db.close(); + throw err + } + }); + } + }); + } else { + process.nextTick(function() { + try { + callback(err, db); + } catch (err) { + if(db) db.close(); + throw err + } + }) + } + }); +} + + +exports.MongoClient = MongoClient; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js new file mode 100644 index 0000000..21e8cec --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js @@ -0,0 +1,83 @@ +var Long = require('bson').Long + , timers = require('timers'); + +// Set processor, setImmediate if 0.10 otherwise nextTick +var processor = require('../utils').processor(); + +/** + Reply message from mongo db +**/ +var MongoReply = exports.MongoReply = function() { + this.documents = []; + this.index = 0; +}; + +MongoReply.prototype.parseHeader = function(binary_reply, bson) { + // Unpack the standard header first + this.messageLength = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24; + this.index = this.index + 4; + // Fetch the request id for this reply + this.requestId = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24; + this.index = this.index + 4; + // Fetch the id of the request that triggered the response + this.responseTo = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24; + // Skip op-code field + this.index = this.index + 4 + 4; + // Unpack the reply message + this.responseFlag = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24; + this.index = this.index + 4; + // Unpack the cursor id (a 64 bit long integer) + var low_bits = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24; + this.index = this.index + 4; + var high_bits = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24; + this.index = this.index + 4; + this.cursorId = new Long(low_bits, high_bits); + // Unpack the starting from + this.startingFrom = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24; + this.index = this.index + 4; + // Unpack the number of objects returned + this.numberReturned = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24; + this.index = this.index + 4; +} + +MongoReply.prototype.parseBody = function(binary_reply, bson, raw, callback) { + raw = raw == null ? false : raw; + + try { + // Let's unpack all the bson documents, deserialize them and store them + for(var object_index = 0; object_index < this.numberReturned; object_index++) { + var _options = {promoteLongs: bson.promoteLongs}; + + // Read the size of the bson object + var bsonObjectSize = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24; + + // If we are storing the raw responses to pipe straight through + if(raw) { + // Deserialize the object and add to the documents array + this.documents.push(binary_reply.slice(this.index, this.index + bsonObjectSize)); + } else { + // Deserialize the object and add to the documents array + this.documents.push(bson.deserialize(binary_reply.slice(this.index, this.index + bsonObjectSize), _options)); + } + + // Adjust binary index to point to next block of binary bson data + this.index = this.index + bsonObjectSize; + } + + // No error return + callback(null); + } catch(err) { + return callback(err); + } +} + +MongoReply.prototype.is_error = function(){ + if(this.documents.length == 1) { + return this.documents[0].ok == 1 ? false : true; + } + return false; +}; + +MongoReply.prototype.error_message = function() { + return this.documents.length == 1 && this.documents[0].ok == 1 ? '' : this.documents[0].errmsg; +}; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/lib/mongodb/utils.js b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/utils.js new file mode 100644 index 0000000..1e8c623 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/lib/mongodb/utils.js @@ -0,0 +1,173 @@ +var timers = require('timers'); + +/** + * Sort functions, Normalize and prepare sort parameters + */ +var formatSortValue = exports.formatSortValue = function(sortDirection) { + var value = ("" + sortDirection).toLowerCase(); + + switch (value) { + case 'ascending': + case 'asc': + case '1': + return 1; + case 'descending': + case 'desc': + case '-1': + return -1; + default: + throw new Error("Illegal sort clause, must be of the form " + + "[['field1', '(ascending|descending)'], " + + "['field2', '(ascending|descending)']]"); + } +}; + +var formattedOrderClause = exports.formattedOrderClause = function(sortValue) { + var orderBy = {}; + + if (Array.isArray(sortValue)) { + for(var i = 0; i < sortValue.length; i++) { + if(sortValue[i].constructor == String) { + orderBy[sortValue[i]] = 1; + } else { + orderBy[sortValue[i][0]] = formatSortValue(sortValue[i][1]); + } + } + } else if(Object.prototype.toString.call(sortValue) === '[object Object]') { + orderBy = sortValue; + } else if (sortValue.constructor == String) { + orderBy[sortValue] = 1; + } else { + throw new Error("Illegal sort clause, must be of the form " + + "[['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]"); + } + + return orderBy; +}; + +exports.encodeInt = function(value) { + var buffer = new Buffer(4); + buffer[3] = (value >> 24) & 0xff; + buffer[2] = (value >> 16) & 0xff; + buffer[1] = (value >> 8) & 0xff; + buffer[0] = value & 0xff; + return buffer; +} + +exports.encodeIntInPlace = function(value, buffer, index) { + buffer[index + 3] = (value >> 24) & 0xff; + buffer[index + 2] = (value >> 16) & 0xff; + buffer[index + 1] = (value >> 8) & 0xff; + buffer[index] = value & 0xff; +} + +exports.encodeCString = function(string) { + var buf = new Buffer(string, 'utf8'); + return [buf, new Buffer([0])]; +} + +exports.decodeUInt32 = function(array, index) { + return array[index] | array[index + 1] << 8 | array[index + 2] << 16 | array[index + 3] << 24; +} + +// Decode the int +exports.decodeUInt8 = function(array, index) { + return array[index]; +} + +/** + * Context insensitive type checks + */ + +var toString = Object.prototype.toString; + +exports.isObject = function (arg) { + return '[object Object]' == toString.call(arg) +} + +exports.isArray = function (arg) { + return Array.isArray(arg) || + 'object' == typeof arg && '[object Array]' == toString.call(arg) +} + +exports.isDate = function (arg) { + return 'object' == typeof arg && '[object Date]' == toString.call(arg) +} + +exports.isRegExp = function (arg) { + return 'object' == typeof arg && '[object RegExp]' == toString.call(arg) +} + +/** + * Wrap a Mongo error document in an Error instance + * @ignore + * @api private + */ +var toError = function(error) { + if (error instanceof Error) return error; + + var msg = error.err || error.errmsg || error; + var e = new Error(msg); + e.name = 'MongoError'; + + // Get all object keys + var keys = typeof error == 'object' + ? Object.keys(error) + : []; + + for(var i = 0; i < keys.length; i++) { + e[keys[i]] = error[keys[i]]; + } + + return e; +} +exports.toError = toError; + +/** + * Convert a single level object to an array + * @ignore + * @api private + */ +exports.objectToArray = function(object) { + var list = []; + + for(var name in object) { + list.push(object[name]) + } + + return list; +} + +/** + * Handle single command document return + * @ignore + * @api private + */ +exports.handleSingleCommandResultReturn = function(override_value_true, override_value_false, callback) { + return function(err, result, connection) { + if(err) return callback(err, null); + if(!result || !result.documents || result.documents.length == 0) + if(callback) return callback(toError("command failed to return results"), null) + if(result.documents[0].ok == 1) { + if(override_value_true) return callback(null, override_value_true) + if(callback) return callback(null, result.documents[0]); + } + + // Return the error from the document + if(callback) return callback(toError(result.documents[0]), override_value_false); + } +} + +/** + * Return correct processor + * @ignore + * @api private + */ +exports.processor = function() { + // Set processor, setImmediate if 0.10 otherwise nextTick + process.maxTickDepth = Infinity; + var processor = timers.setImmediate ? timers.setImmediate : process.nextTick; + // processor = process.nextTick; + return processor; +} + diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/.travis.yml b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/.travis.yml new file mode 100644 index 0000000..94740d0 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - 0.6 + - 0.8 + - 0.9 # development version of 0.8, may be unstable \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/Makefile b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/Makefile new file mode 100644 index 0000000..77ce4e0 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/Makefile @@ -0,0 +1,19 @@ +NODE = node +NPM = npm +NODEUNIT = node_modules/nodeunit/bin/nodeunit + +all: clean node_gyp + +test: clean node_gyp + npm test + +node_gyp: clean + node-gyp configure build + +clean: + node-gyp clean + +browserify: + node_modules/.bin/onejs build browser_build/package.json browser_build/bson.js + +.PHONY: all diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/README.md b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/README.md new file mode 100644 index 0000000..1a6fc2b --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/README.md @@ -0,0 +1,45 @@ +Javascript + C++ BSON parser +============================ + +This BSON parser is primarily meant for usage with the `mongodb` node.js driver. However thanks to such wonderful tools at `onejs` we are able to package up a BSON parser that will work in the browser aswell. The current build is located in the `browser_build/bson.js` file. + +A simple example on how to use it + + + + + + + + + It's got two simple methods to use in your application. + + * BSON.serialize(object, checkKeys, asBuffer, serializeFunctions) + * @param {Object} object the Javascript object to serialize. + * @param {Boolean} checkKeys the serializer will check if keys are valid. + * @param {Boolean} asBuffer return the serialized object as a Buffer object **(ignore)**. + * @param {Boolean} serializeFunctions serialize the javascript functions **(default:false)** + * @return {TypedArray/Array} returns a TypedArray or Array depending on what your browser supports + + * BSON.deserialize(buffer, options, isArray) + * Options + * **evalFunctions** {Boolean, default:false}, evaluate functions in the BSON document scoped to the object deserialized. + * **cacheFunctions** {Boolean, default:false}, cache evaluated functions for reuse. + * **cacheFunctionsCrc32** {Boolean, default:false}, use a crc32 code for caching, otherwise use the string of the function. + * @param {TypedArray/Array} a TypedArray/Array containing the BSON data + * @param {Object} [options] additional options used for the deserialization. + * @param {Boolean} [isArray] ignore used for recursive parsing. + * @return {Object} returns the deserialized Javascript Object. diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/binding.gyp b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/binding.gyp new file mode 100644 index 0000000..42445d3 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/binding.gyp @@ -0,0 +1,17 @@ +{ + 'targets': [ + { + 'target_name': 'bson', + 'sources': [ 'ext/bson.cc' ], + 'cflags!': [ '-fno-exceptions' ], + 'cflags_cc!': [ '-fno-exceptions' ], + 'conditions': [ + ['OS=="mac"', { + 'xcode_settings': { + 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES' + } + }] + ] + } + ] +} \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/browser_build/bson.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/browser_build/bson.js new file mode 100644 index 0000000..b13f8ee --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/browser_build/bson.js @@ -0,0 +1,4843 @@ +var bson = (function(){ + + var pkgmap = {}, + global = {}, + nativeRequire = typeof require != 'undefined' && require, + lib, ties, main, async; + + function exports(){ return main(); }; + + exports.main = exports; + exports.module = module; + exports.packages = pkgmap; + exports.pkg = pkg; + exports.require = function require(uri){ + return pkgmap.main.index.require(uri); + }; + + + ties = {}; + + aliases = {}; + + + return exports; + +function join() { + return normalize(Array.prototype.join.call(arguments, "/")); +}; + +function normalize(path) { + var ret = [], parts = path.split('/'), cur, prev; + + var i = 0, l = parts.length-1; + for (; i <= l; i++) { + cur = parts[i]; + + if (cur === "." && prev !== undefined) continue; + + if (cur === ".." && ret.length && prev !== ".." && prev !== "." && prev !== undefined) { + ret.pop(); + prev = ret.slice(-1)[0]; + } else { + if (prev === ".") ret.pop(); + ret.push(cur); + prev = cur; + } + } + + return ret.join("/"); +}; + +function dirname(path) { + return path && path.substr(0, path.lastIndexOf("/")) || "."; +}; + +function findModule(workingModule, uri){ + var moduleId = join(dirname(workingModule.id), /\.\/$/.test(uri) ? (uri + 'index') : uri ).replace(/\.js$/, ''), + moduleIndexId = join(moduleId, 'index'), + pkg = workingModule.pkg, + module; + + var i = pkg.modules.length, + id; + + while(i-->0){ + id = pkg.modules[i].id; + + if(id==moduleId || id == moduleIndexId){ + module = pkg.modules[i]; + break; + } + } + + return module; +} + +function newRequire(callingModule){ + function require(uri){ + var module, pkg; + + if(/^\./.test(uri)){ + module = findModule(callingModule, uri); + } else if ( ties && ties.hasOwnProperty( uri ) ) { + return ties[uri]; + } else if ( aliases && aliases.hasOwnProperty( uri ) ) { + return require(aliases[uri]); + } else { + pkg = pkgmap[uri]; + + if(!pkg && nativeRequire){ + try { + pkg = nativeRequire(uri); + } catch (nativeRequireError) {} + + if(pkg) return pkg; + } + + if(!pkg){ + throw new Error('Cannot find module "'+uri+'" @[module: '+callingModule.id+' package: '+callingModule.pkg.name+']'); + } + + module = pkg.index; + } + + if(!module){ + throw new Error('Cannot find module "'+uri+'" @[module: '+callingModule.id+' package: '+callingModule.pkg.name+']'); + } + + module.parent = callingModule; + return module.call(); + }; + + + return require; +} + + +function module(parent, id, wrapper){ + var mod = { pkg: parent, id: id, wrapper: wrapper }, + cached = false; + + mod.exports = {}; + mod.require = newRequire(mod); + + mod.call = function(){ + if(cached) { + return mod.exports; + } + + cached = true; + + global.require = mod.require; + + mod.wrapper(mod, mod.exports, global, global.require); + return mod.exports; + }; + + if(parent.mainModuleId == mod.id){ + parent.index = mod; + parent.parents.length === 0 && ( main = mod.call ); + } + + parent.modules.push(mod); +} + +function pkg(/* [ parentId ...], wrapper */){ + var wrapper = arguments[ arguments.length - 1 ], + parents = Array.prototype.slice.call(arguments, 0, arguments.length - 1), + ctx = wrapper(parents); + + + pkgmap[ctx.name] = ctx; + + arguments.length == 1 && ( pkgmap.main = ctx ); + + return function(modules){ + var id; + for(id in modules){ + module(ctx, id, modules[id]); + } + }; +} + + +}(this)); + +bson.pkg(function(parents){ + + return { + 'name' : 'bson', + 'mainModuleId' : 'bson', + 'modules' : [], + 'parents' : parents + }; + +})({ 'binary': function(module, exports, global, require, undefined){ + /** + * Module dependencies. + */ +if(typeof window === 'undefined') { + var Buffer = require('buffer').Buffer; // TODO just use global Buffer +} + +// Binary default subtype +var BSON_BINARY_SUBTYPE_DEFAULT = 0; + +/** + * @ignore + * @api private + */ +var writeStringToArray = function(data) { + // Create a buffer + var buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(data.length)) : new Array(data.length); + // Write the content to the buffer + for(var i = 0; i < data.length; i++) { + buffer[i] = data.charCodeAt(i); + } + // Write the string to the buffer + return buffer; +} + +/** + * Convert Array ot Uint8Array to Binary String + * + * @ignore + * @api private + */ +var convertArraytoUtf8BinaryString = function(byteArray, startIndex, endIndex) { + var result = ""; + for(var i = startIndex; i < endIndex; i++) { + result = result + String.fromCharCode(byteArray[i]); + } + return result; +}; + +/** + * A class representation of the BSON Binary type. + * + * Sub types + * - **BSON.BSON_BINARY_SUBTYPE_DEFAULT**, default BSON type. + * - **BSON.BSON_BINARY_SUBTYPE_FUNCTION**, BSON function type. + * - **BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY**, BSON byte array type. + * - **BSON.BSON_BINARY_SUBTYPE_UUID**, BSON uuid type. + * - **BSON.BSON_BINARY_SUBTYPE_MD5**, BSON md5 type. + * - **BSON.BSON_BINARY_SUBTYPE_USER_DEFINED**, BSON user defined type. + * + * @class Represents the Binary BSON type. + * @param {Buffer} buffer a buffer object containing the binary data. + * @param {Number} [subType] the option binary type. + * @return {Grid} + */ +function Binary(buffer, subType) { + if(!(this instanceof Binary)) return new Binary(buffer, subType); + + this._bsontype = 'Binary'; + + if(buffer instanceof Number) { + this.sub_type = buffer; + this.position = 0; + } else { + this.sub_type = subType == null ? BSON_BINARY_SUBTYPE_DEFAULT : subType; + this.position = 0; + } + + if(buffer != null && !(buffer instanceof Number)) { + // Only accept Buffer, Uint8Array or Arrays + if(typeof buffer == 'string') { + // Different ways of writing the length of the string for the different types + if(typeof Buffer != 'undefined') { + this.buffer = new Buffer(buffer); + } else if(typeof Uint8Array != 'undefined' || (Object.prototype.toString.call(buffer) == '[object Array]')) { + this.buffer = writeStringToArray(buffer); + } else { + throw new Error("only String, Buffer, Uint8Array or Array accepted"); + } + } else { + this.buffer = buffer; + } + this.position = buffer.length; + } else { + if(typeof Buffer != 'undefined') { + this.buffer = new Buffer(Binary.BUFFER_SIZE); + } else if(typeof Uint8Array != 'undefined'){ + this.buffer = new Uint8Array(new ArrayBuffer(Binary.BUFFER_SIZE)); + } else { + this.buffer = new Array(Binary.BUFFER_SIZE); + } + // Set position to start of buffer + this.position = 0; + } +}; + +/** + * Updates this binary with byte_value. + * + * @param {Character} byte_value a single byte we wish to write. + * @api public + */ +Binary.prototype.put = function put(byte_value) { + // If it's a string and a has more than one character throw an error + if(byte_value['length'] != null && typeof byte_value != 'number' && byte_value.length != 1) throw new Error("only accepts single character String, Uint8Array or Array"); + if(typeof byte_value != 'number' && byte_value < 0 || byte_value > 255) throw new Error("only accepts number in a valid unsigned byte range 0-255"); + + // Decode the byte value once + var decoded_byte = null; + if(typeof byte_value == 'string') { + decoded_byte = byte_value.charCodeAt(0); + } else if(byte_value['length'] != null) { + decoded_byte = byte_value[0]; + } else { + decoded_byte = byte_value; + } + + if(this.buffer.length > this.position) { + this.buffer[this.position++] = decoded_byte; + } else { + if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) { + // Create additional overflow buffer + var buffer = new Buffer(Binary.BUFFER_SIZE + this.buffer.length); + // Combine the two buffers together + this.buffer.copy(buffer, 0, 0, this.buffer.length); + this.buffer = buffer; + this.buffer[this.position++] = decoded_byte; + } else { + var buffer = null; + // Create a new buffer (typed or normal array) + if(Object.prototype.toString.call(this.buffer) == '[object Uint8Array]') { + buffer = new Uint8Array(new ArrayBuffer(Binary.BUFFER_SIZE + this.buffer.length)); + } else { + buffer = new Array(Binary.BUFFER_SIZE + this.buffer.length); + } + + // We need to copy all the content to the new array + for(var i = 0; i < this.buffer.length; i++) { + buffer[i] = this.buffer[i]; + } + + // Reassign the buffer + this.buffer = buffer; + // Write the byte + this.buffer[this.position++] = decoded_byte; + } + } +}; + +/** + * Writes a buffer or string to the binary. + * + * @param {Buffer|String} string a string or buffer to be written to the Binary BSON object. + * @param {Number} offset specify the binary of where to write the content. + * @api public + */ +Binary.prototype.write = function write(string, offset) { + offset = typeof offset == 'number' ? offset : this.position; + + // If the buffer is to small let's extend the buffer + if(this.buffer.length < offset + string.length) { + var buffer = null; + // If we are in node.js + if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) { + buffer = new Buffer(this.buffer.length + string.length); + this.buffer.copy(buffer, 0, 0, this.buffer.length); + } else if(Object.prototype.toString.call(this.buffer) == '[object Uint8Array]') { + // Create a new buffer + buffer = new Uint8Array(new ArrayBuffer(this.buffer.length + string.length)) + // Copy the content + for(var i = 0; i < this.position; i++) { + buffer[i] = this.buffer[i]; + } + } + + // Assign the new buffer + this.buffer = buffer; + } + + if(typeof Buffer != 'undefined' && Buffer.isBuffer(string) && Buffer.isBuffer(this.buffer)) { + string.copy(this.buffer, offset, 0, string.length); + this.position = (offset + string.length) > this.position ? (offset + string.length) : this.position; + // offset = string.length + } else if(typeof Buffer != 'undefined' && typeof string == 'string' && Buffer.isBuffer(this.buffer)) { + this.buffer.write(string, 'binary', offset); + this.position = (offset + string.length) > this.position ? (offset + string.length) : this.position; + // offset = string.length; + } else if(Object.prototype.toString.call(string) == '[object Uint8Array]' + || Object.prototype.toString.call(string) == '[object Array]' && typeof string != 'string') { + for(var i = 0; i < string.length; i++) { + this.buffer[offset++] = string[i]; + } + + this.position = offset > this.position ? offset : this.position; + } else if(typeof string == 'string') { + for(var i = 0; i < string.length; i++) { + this.buffer[offset++] = string.charCodeAt(i); + } + + this.position = offset > this.position ? offset : this.position; + } +}; + +/** + * Reads **length** bytes starting at **position**. + * + * @param {Number} position read from the given position in the Binary. + * @param {Number} length the number of bytes to read. + * @return {Buffer} + * @api public + */ +Binary.prototype.read = function read(position, length) { + length = length && length > 0 + ? length + : this.position; + + // Let's return the data based on the type we have + if(this.buffer['slice']) { + return this.buffer.slice(position, position + length); + } else { + // Create a buffer to keep the result + var buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(length)) : new Array(length); + for(var i = 0; i < length; i++) { + buffer[i] = this.buffer[position++]; + } + } + // Return the buffer + return buffer; +}; + +/** + * Returns the value of this binary as a string. + * + * @return {String} + * @api public + */ +Binary.prototype.value = function value(asRaw) { + asRaw = asRaw == null ? false : asRaw; + + // If it's a node.js buffer object + if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) { + return asRaw ? this.buffer.slice(0, this.position) : this.buffer.toString('binary', 0, this.position); + } else { + if(asRaw) { + // we support the slice command use it + if(this.buffer['slice'] != null) { + return this.buffer.slice(0, this.position); + } else { + // Create a new buffer to copy content to + var newBuffer = Object.prototype.toString.call(this.buffer) == '[object Uint8Array]' ? new Uint8Array(new ArrayBuffer(this.position)) : new Array(this.position); + // Copy content + for(var i = 0; i < this.position; i++) { + newBuffer[i] = this.buffer[i]; + } + // Return the buffer + return newBuffer; + } + } else { + return convertArraytoUtf8BinaryString(this.buffer, 0, this.position); + } + } +}; + +/** + * Length. + * + * @return {Number} the length of the binary. + * @api public + */ +Binary.prototype.length = function length() { + return this.position; +}; + +/** + * @ignore + * @api private + */ +Binary.prototype.toJSON = function() { + return this.buffer != null ? this.buffer.toString('base64') : ''; +} + +/** + * @ignore + * @api private + */ +Binary.prototype.toString = function(format) { + return this.buffer != null ? this.buffer.slice(0, this.position).toString(format) : ''; +} + +Binary.BUFFER_SIZE = 256; + +/** + * Default BSON type + * + * @classconstant SUBTYPE_DEFAULT + **/ +Binary.SUBTYPE_DEFAULT = 0; +/** + * Function BSON type + * + * @classconstant SUBTYPE_DEFAULT + **/ +Binary.SUBTYPE_FUNCTION = 1; +/** + * Byte Array BSON type + * + * @classconstant SUBTYPE_DEFAULT + **/ +Binary.SUBTYPE_BYTE_ARRAY = 2; +/** + * OLD UUID BSON type + * + * @classconstant SUBTYPE_DEFAULT + **/ +Binary.SUBTYPE_UUID_OLD = 3; +/** + * UUID BSON type + * + * @classconstant SUBTYPE_DEFAULT + **/ +Binary.SUBTYPE_UUID = 4; +/** + * MD5 BSON type + * + * @classconstant SUBTYPE_DEFAULT + **/ +Binary.SUBTYPE_MD5 = 5; +/** + * User BSON type + * + * @classconstant SUBTYPE_DEFAULT + **/ +Binary.SUBTYPE_USER_DEFINED = 128; + +/** + * Expose. + */ +exports.Binary = Binary; + + +}, + + + +'binary_parser': function(module, exports, global, require, undefined){ + /** + * Binary Parser. + * Jonas Raoni Soares Silva + * http://jsfromhell.com/classes/binary-parser [v1.0] + */ +var chr = String.fromCharCode; + +var maxBits = []; +for (var i = 0; i < 64; i++) { + maxBits[i] = Math.pow(2, i); +} + +function BinaryParser (bigEndian, allowExceptions) { + if(!(this instanceof BinaryParser)) return new BinaryParser(bigEndian, allowExceptions); + + this.bigEndian = bigEndian; + this.allowExceptions = allowExceptions; +}; + +BinaryParser.warn = function warn (msg) { + if (this.allowExceptions) { + throw new Error(msg); + } + + return 1; +}; + +BinaryParser.decodeFloat = function decodeFloat (data, precisionBits, exponentBits) { + var b = new this.Buffer(this.bigEndian, data); + + b.checkBuffer(precisionBits + exponentBits + 1); + + var bias = maxBits[exponentBits - 1] - 1 + , signal = b.readBits(precisionBits + exponentBits, 1) + , exponent = b.readBits(precisionBits, exponentBits) + , significand = 0 + , divisor = 2 + , curByte = b.buffer.length + (-precisionBits >> 3) - 1; + + do { + for (var byteValue = b.buffer[ ++curByte ], startBit = precisionBits % 8 || 8, mask = 1 << startBit; mask >>= 1; ( byteValue & mask ) && ( significand += 1 / divisor ), divisor *= 2 ); + } while (precisionBits -= startBit); + + return exponent == ( bias << 1 ) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity : ( 1 + signal * -2 ) * ( exponent || significand ? !exponent ? Math.pow( 2, -bias + 1 ) * significand : Math.pow( 2, exponent - bias ) * ( 1 + significand ) : 0 ); +}; + +BinaryParser.decodeInt = function decodeInt (data, bits, signed, forceBigEndian) { + var b = new this.Buffer(this.bigEndian || forceBigEndian, data) + , x = b.readBits(0, bits) + , max = maxBits[bits]; //max = Math.pow( 2, bits ); + + return signed && x >= max / 2 + ? x - max + : x; +}; + +BinaryParser.encodeFloat = function encodeFloat (data, precisionBits, exponentBits) { + var bias = maxBits[exponentBits - 1] - 1 + , minExp = -bias + 1 + , maxExp = bias + , minUnnormExp = minExp - precisionBits + , n = parseFloat(data) + , status = isNaN(n) || n == -Infinity || n == +Infinity ? n : 0 + , exp = 0 + , len = 2 * bias + 1 + precisionBits + 3 + , bin = new Array(len) + , signal = (n = status !== 0 ? 0 : n) < 0 + , intPart = Math.floor(n = Math.abs(n)) + , floatPart = n - intPart + , lastBit + , rounded + , result + , i + , j; + + for (i = len; i; bin[--i] = 0); + + for (i = bias + 2; intPart && i; bin[--i] = intPart % 2, intPart = Math.floor(intPart / 2)); + + for (i = bias + 1; floatPart > 0 && i; (bin[++i] = ((floatPart *= 2) >= 1) - 0 ) && --floatPart); + + for (i = -1; ++i < len && !bin[i];); + + if (bin[(lastBit = precisionBits - 1 + (i = (exp = bias + 1 - i) >= minExp && exp <= maxExp ? i + 1 : bias + 1 - (exp = minExp - 1))) + 1]) { + if (!(rounded = bin[lastBit])) { + for (j = lastBit + 2; !rounded && j < len; rounded = bin[j++]); + } + + for (j = lastBit + 1; rounded && --j >= 0; (bin[j] = !bin[j] - 0) && (rounded = 0)); + } + + for (i = i - 2 < 0 ? -1 : i - 3; ++i < len && !bin[i];); + + if ((exp = bias + 1 - i) >= minExp && exp <= maxExp) { + ++i; + } else if (exp < minExp) { + exp != bias + 1 - len && exp < minUnnormExp && this.warn("encodeFloat::float underflow"); + i = bias + 1 - (exp = minExp - 1); + } + + if (intPart || status !== 0) { + this.warn(intPart ? "encodeFloat::float overflow" : "encodeFloat::" + status); + exp = maxExp + 1; + i = bias + 2; + + if (status == -Infinity) { + signal = 1; + } else if (isNaN(status)) { + bin[i] = 1; + } + } + + for (n = Math.abs(exp + bias), j = exponentBits + 1, result = ""; --j; result = (n % 2) + result, n = n >>= 1); + + for (n = 0, j = 0, i = (result = (signal ? "1" : "0") + result + bin.slice(i, i + precisionBits).join("")).length, r = []; i; j = (j + 1) % 8) { + n += (1 << j) * result.charAt(--i); + if (j == 7) { + r[r.length] = String.fromCharCode(n); + n = 0; + } + } + + r[r.length] = n + ? String.fromCharCode(n) + : ""; + + return (this.bigEndian ? r.reverse() : r).join(""); +}; + +BinaryParser.encodeInt = function encodeInt (data, bits, signed, forceBigEndian) { + var max = maxBits[bits]; + + if (data >= max || data < -(max / 2)) { + this.warn("encodeInt::overflow"); + data = 0; + } + + if (data < 0) { + data += max; + } + + for (var r = []; data; r[r.length] = String.fromCharCode(data % 256), data = Math.floor(data / 256)); + + for (bits = -(-bits >> 3) - r.length; bits--; r[r.length] = "\0"); + + return ((this.bigEndian || forceBigEndian) ? r.reverse() : r).join(""); +}; + +BinaryParser.toSmall = function( data ){ return this.decodeInt( data, 8, true ); }; +BinaryParser.fromSmall = function( data ){ return this.encodeInt( data, 8, true ); }; +BinaryParser.toByte = function( data ){ return this.decodeInt( data, 8, false ); }; +BinaryParser.fromByte = function( data ){ return this.encodeInt( data, 8, false ); }; +BinaryParser.toShort = function( data ){ return this.decodeInt( data, 16, true ); }; +BinaryParser.fromShort = function( data ){ return this.encodeInt( data, 16, true ); }; +BinaryParser.toWord = function( data ){ return this.decodeInt( data, 16, false ); }; +BinaryParser.fromWord = function( data ){ return this.encodeInt( data, 16, false ); }; +BinaryParser.toInt = function( data ){ return this.decodeInt( data, 32, true ); }; +BinaryParser.fromInt = function( data ){ return this.encodeInt( data, 32, true ); }; +BinaryParser.toLong = function( data ){ return this.decodeInt( data, 64, true ); }; +BinaryParser.fromLong = function( data ){ return this.encodeInt( data, 64, true ); }; +BinaryParser.toDWord = function( data ){ return this.decodeInt( data, 32, false ); }; +BinaryParser.fromDWord = function( data ){ return this.encodeInt( data, 32, false ); }; +BinaryParser.toQWord = function( data ){ return this.decodeInt( data, 64, true ); }; +BinaryParser.fromQWord = function( data ){ return this.encodeInt( data, 64, true ); }; +BinaryParser.toFloat = function( data ){ return this.decodeFloat( data, 23, 8 ); }; +BinaryParser.fromFloat = function( data ){ return this.encodeFloat( data, 23, 8 ); }; +BinaryParser.toDouble = function( data ){ return this.decodeFloat( data, 52, 11 ); }; +BinaryParser.fromDouble = function( data ){ return this.encodeFloat( data, 52, 11 ); }; + +// Factor out the encode so it can be shared by add_header and push_int32 +BinaryParser.encode_int32 = function encode_int32 (number, asArray) { + var a, b, c, d, unsigned; + unsigned = (number < 0) ? (number + 0x100000000) : number; + a = Math.floor(unsigned / 0xffffff); + unsigned &= 0xffffff; + b = Math.floor(unsigned / 0xffff); + unsigned &= 0xffff; + c = Math.floor(unsigned / 0xff); + unsigned &= 0xff; + d = Math.floor(unsigned); + return asArray ? [chr(a), chr(b), chr(c), chr(d)] : chr(a) + chr(b) + chr(c) + chr(d); +}; + +BinaryParser.encode_int64 = function encode_int64 (number) { + var a, b, c, d, e, f, g, h, unsigned; + unsigned = (number < 0) ? (number + 0x10000000000000000) : number; + a = Math.floor(unsigned / 0xffffffffffffff); + unsigned &= 0xffffffffffffff; + b = Math.floor(unsigned / 0xffffffffffff); + unsigned &= 0xffffffffffff; + c = Math.floor(unsigned / 0xffffffffff); + unsigned &= 0xffffffffff; + d = Math.floor(unsigned / 0xffffffff); + unsigned &= 0xffffffff; + e = Math.floor(unsigned / 0xffffff); + unsigned &= 0xffffff; + f = Math.floor(unsigned / 0xffff); + unsigned &= 0xffff; + g = Math.floor(unsigned / 0xff); + unsigned &= 0xff; + h = Math.floor(unsigned); + return chr(a) + chr(b) + chr(c) + chr(d) + chr(e) + chr(f) + chr(g) + chr(h); +}; + +/** + * UTF8 methods + */ + +// Take a raw binary string and return a utf8 string +BinaryParser.decode_utf8 = function decode_utf8 (binaryStr) { + var len = binaryStr.length + , decoded = '' + , i = 0 + , c = 0 + , c1 = 0 + , c2 = 0 + , c3; + + while (i < len) { + c = binaryStr.charCodeAt(i); + if (c < 128) { + decoded += String.fromCharCode(c); + i++; + } else if ((c > 191) && (c < 224)) { + c2 = binaryStr.charCodeAt(i+1); + decoded += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); + i += 2; + } else { + c2 = binaryStr.charCodeAt(i+1); + c3 = binaryStr.charCodeAt(i+2); + decoded += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + i += 3; + } + } + + return decoded; +}; + +// Encode a cstring +BinaryParser.encode_cstring = function encode_cstring (s) { + return unescape(encodeURIComponent(s)) + BinaryParser.fromByte(0); +}; + +// Take a utf8 string and return a binary string +BinaryParser.encode_utf8 = function encode_utf8 (s) { + var a = "" + , c; + + for (var n = 0, len = s.length; n < len; n++) { + c = s.charCodeAt(n); + + if (c < 128) { + a += String.fromCharCode(c); + } else if ((c > 127) && (c < 2048)) { + a += String.fromCharCode((c>>6) | 192) ; + a += String.fromCharCode((c&63) | 128); + } else { + a += String.fromCharCode((c>>12) | 224); + a += String.fromCharCode(((c>>6) & 63) | 128); + a += String.fromCharCode((c&63) | 128); + } + } + + return a; +}; + +BinaryParser.hprint = function hprint (s) { + var number; + + for (var i = 0, len = s.length; i < len; i++) { + if (s.charCodeAt(i) < 32) { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(16) + : s.charCodeAt(i).toString(16); + process.stdout.write(number + " ") + } else { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(16) + : s.charCodeAt(i).toString(16); + process.stdout.write(number + " ") + } + } + + process.stdout.write("\n\n"); +}; + +BinaryParser.ilprint = function hprint (s) { + var number; + + for (var i = 0, len = s.length; i < len; i++) { + if (s.charCodeAt(i) < 32) { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(10) + : s.charCodeAt(i).toString(10); + + require('util').debug(number+' : '); + } else { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(10) + : s.charCodeAt(i).toString(10); + require('util').debug(number+' : '+ s.charAt(i)); + } + } +}; + +BinaryParser.hlprint = function hprint (s) { + var number; + + for (var i = 0, len = s.length; i < len; i++) { + if (s.charCodeAt(i) < 32) { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(16) + : s.charCodeAt(i).toString(16); + require('util').debug(number+' : '); + } else { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(16) + : s.charCodeAt(i).toString(16); + require('util').debug(number+' : '+ s.charAt(i)); + } + } +}; + +/** + * BinaryParser buffer constructor. + */ +function BinaryParserBuffer (bigEndian, buffer) { + this.bigEndian = bigEndian || 0; + this.buffer = []; + this.setBuffer(buffer); +}; + +BinaryParserBuffer.prototype.setBuffer = function setBuffer (data) { + var l, i, b; + + if (data) { + i = l = data.length; + b = this.buffer = new Array(l); + for (; i; b[l - i] = data.charCodeAt(--i)); + this.bigEndian && b.reverse(); + } +}; + +BinaryParserBuffer.prototype.hasNeededBits = function hasNeededBits (neededBits) { + return this.buffer.length >= -(-neededBits >> 3); +}; + +BinaryParserBuffer.prototype.checkBuffer = function checkBuffer (neededBits) { + if (!this.hasNeededBits(neededBits)) { + throw new Error("checkBuffer::missing bytes"); + } +}; + +BinaryParserBuffer.prototype.readBits = function readBits (start, length) { + //shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni) + + function shl (a, b) { + for (; b--; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1); + return a; + } + + if (start < 0 || length <= 0) { + return 0; + } + + this.checkBuffer(start + length); + + var offsetLeft + , offsetRight = start % 8 + , curByte = this.buffer.length - ( start >> 3 ) - 1 + , lastByte = this.buffer.length + ( -( start + length ) >> 3 ) + , diff = curByte - lastByte + , sum = ((this.buffer[ curByte ] >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1)) + (diff && (offsetLeft = (start + length) % 8) ? (this.buffer[lastByte++] & ((1 << offsetLeft) - 1)) << (diff-- << 3) - offsetRight : 0); + + for(; diff; sum += shl(this.buffer[lastByte++], (diff-- << 3) - offsetRight)); + + return sum; +}; + +/** + * Expose. + */ +BinaryParser.Buffer = BinaryParserBuffer; + +exports.BinaryParser = BinaryParser; + +}, + + + +'bson': function(module, exports, global, require, undefined){ + var Long = require('./long').Long + , Double = require('./double').Double + , Timestamp = require('./timestamp').Timestamp + , ObjectID = require('./objectid').ObjectID + , Symbol = require('./symbol').Symbol + , Code = require('./code').Code + , MinKey = require('./min_key').MinKey + , MaxKey = require('./max_key').MaxKey + , DBRef = require('./db_ref').DBRef + , Binary = require('./binary').Binary + , BinaryParser = require('./binary_parser').BinaryParser + , writeIEEE754 = require('./float_parser').writeIEEE754 + , readIEEE754 = require('./float_parser').readIEEE754 + +// To ensure that 0.4 of node works correctly +var isDate = function isDate(d) { + return typeof d === 'object' && Object.prototype.toString.call(d) === '[object Date]'; +} + +/** + * Create a new BSON instance + * + * @class Represents the BSON Parser + * @return {BSON} instance of BSON Parser. + */ +function BSON () {}; + +/** + * @ignore + * @api private + */ +// BSON MAX VALUES +BSON.BSON_INT32_MAX = 0x7FFFFFFF; +BSON.BSON_INT32_MIN = -0x80000000; + +BSON.BSON_INT64_MAX = Math.pow(2, 63) - 1; +BSON.BSON_INT64_MIN = -Math.pow(2, 63); + +// JS MAX PRECISE VALUES +BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. +BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. + +// Internal long versions +var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000); // Any integer up to 2^53 can be precisely represented by a double. +var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000); // Any integer down to -2^53 can be precisely represented by a double. + +/** + * Number BSON Type + * + * @classconstant BSON_DATA_NUMBER + **/ +BSON.BSON_DATA_NUMBER = 1; +/** + * String BSON Type + * + * @classconstant BSON_DATA_STRING + **/ +BSON.BSON_DATA_STRING = 2; +/** + * Object BSON Type + * + * @classconstant BSON_DATA_OBJECT + **/ +BSON.BSON_DATA_OBJECT = 3; +/** + * Array BSON Type + * + * @classconstant BSON_DATA_ARRAY + **/ +BSON.BSON_DATA_ARRAY = 4; +/** + * Binary BSON Type + * + * @classconstant BSON_DATA_BINARY + **/ +BSON.BSON_DATA_BINARY = 5; +/** + * ObjectID BSON Type + * + * @classconstant BSON_DATA_OID + **/ +BSON.BSON_DATA_OID = 7; +/** + * Boolean BSON Type + * + * @classconstant BSON_DATA_BOOLEAN + **/ +BSON.BSON_DATA_BOOLEAN = 8; +/** + * Date BSON Type + * + * @classconstant BSON_DATA_DATE + **/ +BSON.BSON_DATA_DATE = 9; +/** + * null BSON Type + * + * @classconstant BSON_DATA_NULL + **/ +BSON.BSON_DATA_NULL = 10; +/** + * RegExp BSON Type + * + * @classconstant BSON_DATA_REGEXP + **/ +BSON.BSON_DATA_REGEXP = 11; +/** + * Code BSON Type + * + * @classconstant BSON_DATA_CODE + **/ +BSON.BSON_DATA_CODE = 13; +/** + * Symbol BSON Type + * + * @classconstant BSON_DATA_SYMBOL + **/ +BSON.BSON_DATA_SYMBOL = 14; +/** + * Code with Scope BSON Type + * + * @classconstant BSON_DATA_CODE_W_SCOPE + **/ +BSON.BSON_DATA_CODE_W_SCOPE = 15; +/** + * 32 bit Integer BSON Type + * + * @classconstant BSON_DATA_INT + **/ +BSON.BSON_DATA_INT = 16; +/** + * Timestamp BSON Type + * + * @classconstant BSON_DATA_TIMESTAMP + **/ +BSON.BSON_DATA_TIMESTAMP = 17; +/** + * Long BSON Type + * + * @classconstant BSON_DATA_LONG + **/ +BSON.BSON_DATA_LONG = 18; +/** + * MinKey BSON Type + * + * @classconstant BSON_DATA_MIN_KEY + **/ +BSON.BSON_DATA_MIN_KEY = 0xff; +/** + * MaxKey BSON Type + * + * @classconstant BSON_DATA_MAX_KEY + **/ +BSON.BSON_DATA_MAX_KEY = 0x7f; + +/** + * Binary Default Type + * + * @classconstant BSON_BINARY_SUBTYPE_DEFAULT + **/ +BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0; +/** + * Binary Function Type + * + * @classconstant BSON_BINARY_SUBTYPE_FUNCTION + **/ +BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1; +/** + * Binary Byte Array Type + * + * @classconstant BSON_BINARY_SUBTYPE_BYTE_ARRAY + **/ +BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2; +/** + * Binary UUID Type + * + * @classconstant BSON_BINARY_SUBTYPE_UUID + **/ +BSON.BSON_BINARY_SUBTYPE_UUID = 3; +/** + * Binary MD5 Type + * + * @classconstant BSON_BINARY_SUBTYPE_MD5 + **/ +BSON.BSON_BINARY_SUBTYPE_MD5 = 4; +/** + * Binary User Defined Type + * + * @classconstant BSON_BINARY_SUBTYPE_USER_DEFINED + **/ +BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128; + +/** + * Calculate the bson size for a passed in Javascript object. + * + * @param {Object} object the Javascript object to calculate the BSON byte size for. + * @param {Boolean} [serializeFunctions] serialize all functions in the object **(default:false)**. + * @return {Number} returns the number of bytes the BSON object will take up. + * @api public + */ +BSON.calculateObjectSize = function calculateObjectSize(object, serializeFunctions) { + var totalLength = (4 + 1); + + if(Array.isArray(object)) { + for(var i = 0; i < object.length; i++) { + totalLength += calculateElement(i.toString(), object[i], serializeFunctions) + } + } else { + // If we have toBSON defined, override the current object + if(object.toBSON) { + object = object.toBSON(); + } + + // Calculate size + for(var key in object) { + totalLength += calculateElement(key, object[key], serializeFunctions) + } + } + + return totalLength; +} + +/** + * @ignore + * @api private + */ +function calculateElement(name, value, serializeFunctions) { + var isBuffer = typeof Buffer !== 'undefined'; + + switch(typeof value) { + case 'string': + return 1 + (!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1 + 4 + (!isBuffer ? numberOfBytes(value) : Buffer.byteLength(value, 'utf8')) + 1; + case 'number': + if(Math.floor(value) === value && value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { + if(value >= BSON.BSON_INT32_MIN && value <= BSON.BSON_INT32_MAX) { // 32 bit + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (4 + 1); + } else { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (8 + 1); + } + } else { // 64 bit + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (8 + 1); + } + case 'undefined': + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (1); + case 'boolean': + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (1 + 1); + case 'object': + if(value == null || value instanceof MinKey || value instanceof MaxKey || value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (1); + } else if(value instanceof ObjectID || value['_bsontype'] == 'ObjectID') { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (12 + 1); + } else if(value instanceof Date || isDate(value)) { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (8 + 1); + } else if(typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (1 + 4 + 1) + value.length; + } else if(value instanceof Long || value instanceof Double || value instanceof Timestamp + || value['_bsontype'] == 'Long' || value['_bsontype'] == 'Double' || value['_bsontype'] == 'Timestamp') { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (8 + 1); + } else if(value instanceof Code || value['_bsontype'] == 'Code') { + // Calculate size depending on the availability of a scope + if(value.scope != null && Object.keys(value.scope).length > 0) { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + 4 + 4 + (!isBuffer ? numberOfBytes(value.code.toString()) : Buffer.byteLength(value.code.toString(), 'utf8')) + 1 + BSON.calculateObjectSize(value.scope, serializeFunctions); + } else { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + 4 + (!isBuffer ? numberOfBytes(value.code.toString()) : Buffer.byteLength(value.code.toString(), 'utf8')) + 1; + } + } else if(value instanceof Binary || value['_bsontype'] == 'Binary') { + // Check what kind of subtype we have + if(value.sub_type == Binary.SUBTYPE_BYTE_ARRAY) { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (value.position + 1 + 4 + 1 + 4); + } else { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (value.position + 1 + 4 + 1); + } + } else if(value instanceof Symbol || value['_bsontype'] == 'Symbol') { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + ((!isBuffer ? numberOfBytes(value.value) : Buffer.byteLength(value.value, 'utf8')) + 4 + 1 + 1); + } else if(value instanceof DBRef || value['_bsontype'] == 'DBRef') { + // Set up correct object for serialization + var ordered_values = { + '$ref': value.namespace + , '$id' : value.oid + }; + + // Add db reference if it exists + if(null != value.db) { + ordered_values['$db'] = value.db; + } + + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + BSON.calculateObjectSize(ordered_values, serializeFunctions); + } else if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]') { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + (!isBuffer ? numberOfBytes(value.source) : Buffer.byteLength(value.source, 'utf8')) + 1 + + (value.global ? 1 : 0) + (value.ignoreCase ? 1 : 0) + (value.multiline ? 1 : 0) + 1 + } else { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + BSON.calculateObjectSize(value, serializeFunctions) + 1; + } + case 'function': + // WTF for 0.4.X where typeof /someregexp/ === 'function' + if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]' || String.call(value) == '[object RegExp]') { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + (!isBuffer ? numberOfBytes(value.source) : Buffer.byteLength(value.source, 'utf8')) + 1 + + (value.global ? 1 : 0) + (value.ignoreCase ? 1 : 0) + (value.multiline ? 1 : 0) + 1 + } else { + if(serializeFunctions && value.scope != null && Object.keys(value.scope).length > 0) { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + 4 + 4 + (!isBuffer ? numberOfBytes(value.toString()) : Buffer.byteLength(value.toString(), 'utf8')) + 1 + BSON.calculateObjectSize(value.scope, serializeFunctions); + } else if(serializeFunctions) { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + 4 + (!isBuffer ? numberOfBytes(value.toString()) : Buffer.byteLength(value.toString(), 'utf8')) + 1; + } + } + } + + return 0; +} + +/** + * Serialize a Javascript object using a predefined Buffer and index into the buffer, useful when pre-allocating the space for serialization. + * + * @param {Object} object the Javascript object to serialize. + * @param {Boolean} checkKeys the serializer will check if keys are valid. + * @param {Buffer} buffer the Buffer you pre-allocated to store the serialized BSON object. + * @param {Number} index the index in the buffer where we wish to start serializing into. + * @param {Boolean} serializeFunctions serialize the javascript functions **(default:false)**. + * @return {Number} returns the new write index in the Buffer. + * @api public + */ +BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object, checkKeys, buffer, index, serializeFunctions) { + // Default setting false + serializeFunctions = serializeFunctions == null ? false : serializeFunctions; + // Write end information (length of the object) + var size = buffer.length; + // Write the size of the object + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + return serializeObject(object, checkKeys, buffer, index, serializeFunctions) - 1; +} + +/** + * @ignore + * @api private + */ +var serializeObject = function(object, checkKeys, buffer, index, serializeFunctions) { + // Process the object + if(Array.isArray(object)) { + for(var i = 0; i < object.length; i++) { + index = packElement(i.toString(), object[i], checkKeys, buffer, index, serializeFunctions); + } + } else { + // If we have toBSON defined, override the current object + if(object.toBSON) { + object = object.toBSON(); + } + + // Serialize the object + for(var key in object) { + // Check the key and throw error if it's illegal + if (key != '$db' && key != '$ref' && key != '$id') { + // dollars and dots ok + BSON.checkKey(key, !checkKeys); + } + + // Pack the element + index = packElement(key, object[key], checkKeys, buffer, index, serializeFunctions); + } + } + + // Write zero + buffer[index++] = 0; + return index; +} + +var stringToBytes = function(str) { + var ch, st, re = []; + for (var i = 0; i < str.length; i++ ) { + ch = str.charCodeAt(i); // get char + st = []; // set up "stack" + do { + st.push( ch & 0xFF ); // push byte to stack + ch = ch >> 8; // shift value down by 1 byte + } + while ( ch ); + // add stack contents to result + // done because chars have "wrong" endianness + re = re.concat( st.reverse() ); + } + // return an array of bytes + return re; +} + +var numberOfBytes = function(str) { + var ch, st, re = 0; + for (var i = 0; i < str.length; i++ ) { + ch = str.charCodeAt(i); // get char + st = []; // set up "stack" + do { + st.push( ch & 0xFF ); // push byte to stack + ch = ch >> 8; // shift value down by 1 byte + } + while ( ch ); + // add stack contents to result + // done because chars have "wrong" endianness + re = re + st.length; + } + // return an array of bytes + return re; +} + +/** + * @ignore + * @api private + */ +var writeToTypedArray = function(buffer, string, index) { + var bytes = stringToBytes(string); + for(var i = 0; i < bytes.length; i++) { + buffer[index + i] = bytes[i]; + } + return bytes.length; +} + +/** + * @ignore + * @api private + */ +var supportsBuffer = typeof Buffer != 'undefined'; + +/** + * @ignore + * @api private + */ +var packElement = function(name, value, checkKeys, buffer, index, serializeFunctions) { + var startIndex = index; + + switch(typeof value) { + case 'string': + // Encode String type + buffer[index++] = BSON.BSON_DATA_STRING; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + + // Calculate size + var size = supportsBuffer ? Buffer.byteLength(value) + 1 : numberOfBytes(value) + 1; + // Write the size of the string to buffer + buffer[index + 3] = (size >> 24) & 0xff; + buffer[index + 2] = (size >> 16) & 0xff; + buffer[index + 1] = (size >> 8) & 0xff; + buffer[index] = size & 0xff; + // Ajust the index + index = index + 4; + // Write the string + supportsBuffer ? buffer.write(value, index, 'utf8') : writeToTypedArray(buffer, value, index); + // Update index + index = index + size - 1; + // Write zero + buffer[index++] = 0; + // Return index + return index; + case 'number': + // We have an integer value + if(Math.floor(value) === value && value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { + // If the value fits in 32 bits encode as int, if it fits in a double + // encode it as a double, otherwise long + if(value >= BSON.BSON_INT32_MIN && value <= BSON.BSON_INT32_MAX) { + // Set int type 32 bits or less + buffer[index++] = BSON.BSON_DATA_INT; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Write the int value + buffer[index++] = value & 0xff; + buffer[index++] = (value >> 8) & 0xff; + buffer[index++] = (value >> 16) & 0xff; + buffer[index++] = (value >> 24) & 0xff; + } else if(value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { + // Encode as double + buffer[index++] = BSON.BSON_DATA_NUMBER; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Write float + writeIEEE754(buffer, value, index, 'little', 52, 8); + // Ajust index + index = index + 8; + } else { + // Set long type + buffer[index++] = BSON.BSON_DATA_LONG; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + var longVal = Long.fromNumber(value); + var lowBits = longVal.getLowBits(); + var highBits = longVal.getHighBits(); + // Encode low bits + buffer[index++] = lowBits & 0xff; + buffer[index++] = (lowBits >> 8) & 0xff; + buffer[index++] = (lowBits >> 16) & 0xff; + buffer[index++] = (lowBits >> 24) & 0xff; + // Encode high bits + buffer[index++] = highBits & 0xff; + buffer[index++] = (highBits >> 8) & 0xff; + buffer[index++] = (highBits >> 16) & 0xff; + buffer[index++] = (highBits >> 24) & 0xff; + } + } else { + // Encode as double + buffer[index++] = BSON.BSON_DATA_NUMBER; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Write float + writeIEEE754(buffer, value, index, 'little', 52, 8); + // Ajust index + index = index + 8; + } + + return index; + case 'undefined': + // Set long type + buffer[index++] = BSON.BSON_DATA_NULL; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + return index; + case 'boolean': + // Write the type + buffer[index++] = BSON.BSON_DATA_BOOLEAN; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Encode the boolean value + buffer[index++] = value ? 1 : 0; + return index; + case 'object': + if(value === null || value instanceof MinKey || value instanceof MaxKey + || value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') { + // Write the type of either min or max key + if(value === null) { + buffer[index++] = BSON.BSON_DATA_NULL; + } else if(value instanceof MinKey) { + buffer[index++] = BSON.BSON_DATA_MIN_KEY; + } else { + buffer[index++] = BSON.BSON_DATA_MAX_KEY; + } + + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + return index; + } else if(value instanceof ObjectID || value['_bsontype'] == 'ObjectID') { + // Write the type + buffer[index++] = BSON.BSON_DATA_OID; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + + // Write objectid + supportsBuffer ? buffer.write(value.id, index, 'binary') : writeToTypedArray(buffer, value.id, index); + // Ajust index + index = index + 12; + return index; + } else if(value instanceof Date || isDate(value)) { + // Write the type + buffer[index++] = BSON.BSON_DATA_DATE; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + + // Write the date + var dateInMilis = Long.fromNumber(value.getTime()); + var lowBits = dateInMilis.getLowBits(); + var highBits = dateInMilis.getHighBits(); + // Encode low bits + buffer[index++] = lowBits & 0xff; + buffer[index++] = (lowBits >> 8) & 0xff; + buffer[index++] = (lowBits >> 16) & 0xff; + buffer[index++] = (lowBits >> 24) & 0xff; + // Encode high bits + buffer[index++] = highBits & 0xff; + buffer[index++] = (highBits >> 8) & 0xff; + buffer[index++] = (highBits >> 16) & 0xff; + buffer[index++] = (highBits >> 24) & 0xff; + return index; + } else if(typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) { + // Write the type + buffer[index++] = BSON.BSON_DATA_BINARY; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Get size of the buffer (current write point) + var size = value.length; + // Write the size of the string to buffer + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + // Write the default subtype + buffer[index++] = BSON.BSON_BINARY_SUBTYPE_DEFAULT; + // Copy the content form the binary field to the buffer + value.copy(buffer, index, 0, size); + // Adjust the index + index = index + size; + return index; + } else if(value instanceof Long || value instanceof Timestamp || value['_bsontype'] == 'Long' || value['_bsontype'] == 'Timestamp') { + // Write the type + buffer[index++] = value instanceof Long ? BSON.BSON_DATA_LONG : BSON.BSON_DATA_TIMESTAMP; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Write the date + var lowBits = value.getLowBits(); + var highBits = value.getHighBits(); + // Encode low bits + buffer[index++] = lowBits & 0xff; + buffer[index++] = (lowBits >> 8) & 0xff; + buffer[index++] = (lowBits >> 16) & 0xff; + buffer[index++] = (lowBits >> 24) & 0xff; + // Encode high bits + buffer[index++] = highBits & 0xff; + buffer[index++] = (highBits >> 8) & 0xff; + buffer[index++] = (highBits >> 16) & 0xff; + buffer[index++] = (highBits >> 24) & 0xff; + return index; + } else if(value instanceof Double || value['_bsontype'] == 'Double') { + // Encode as double + buffer[index++] = BSON.BSON_DATA_NUMBER; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Write float + writeIEEE754(buffer, value, index, 'little', 52, 8); + // Ajust index + index = index + 8; + return index; + } else if(value instanceof Code || value['_bsontype'] == 'Code') { + if(value.scope != null && Object.keys(value.scope).length > 0) { + // Write the type + buffer[index++] = BSON.BSON_DATA_CODE_W_SCOPE; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Calculate the scope size + var scopeSize = BSON.calculateObjectSize(value.scope, serializeFunctions); + // Function string + var functionString = value.code.toString(); + // Function Size + var codeSize = supportsBuffer ? Buffer.byteLength(functionString) + 1 : numberOfBytes(functionString) + 1; + + // Calculate full size of the object + var totalSize = 4 + codeSize + scopeSize + 4; + + // Write the total size of the object + buffer[index++] = totalSize & 0xff; + buffer[index++] = (totalSize >> 8) & 0xff; + buffer[index++] = (totalSize >> 16) & 0xff; + buffer[index++] = (totalSize >> 24) & 0xff; + + // Write the size of the string to buffer + buffer[index++] = codeSize & 0xff; + buffer[index++] = (codeSize >> 8) & 0xff; + buffer[index++] = (codeSize >> 16) & 0xff; + buffer[index++] = (codeSize >> 24) & 0xff; + + // Write the string + supportsBuffer ? buffer.write(functionString, index, 'utf8') : writeToTypedArray(buffer, functionString, index); + // Update index + index = index + codeSize - 1; + // Write zero + buffer[index++] = 0; + // Serialize the scope object + var scopeObjectBuffer = supportsBuffer ? new Buffer(scopeSize) : new Uint8Array(new ArrayBuffer(scopeSize)); + // Execute the serialization into a seperate buffer + serializeObject(value.scope, checkKeys, scopeObjectBuffer, 0, serializeFunctions); + + // Adjusted scope Size (removing the header) + var scopeDocSize = scopeSize; + // Write scope object size + buffer[index++] = scopeDocSize & 0xff; + buffer[index++] = (scopeDocSize >> 8) & 0xff; + buffer[index++] = (scopeDocSize >> 16) & 0xff; + buffer[index++] = (scopeDocSize >> 24) & 0xff; + + // Write the scopeObject into the buffer + supportsBuffer ? scopeObjectBuffer.copy(buffer, index, 0, scopeSize) : buffer.set(scopeObjectBuffer, index); + // Adjust index, removing the empty size of the doc (5 bytes 0000000005) + index = index + scopeDocSize - 5; + // Write trailing zero + buffer[index++] = 0; + return index + } else { + buffer[index++] = BSON.BSON_DATA_CODE; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Function string + var functionString = value.code.toString(); + // Function Size + var size = supportsBuffer ? Buffer.byteLength(functionString) + 1 : numberOfBytes(functionString) + 1; + // Write the size of the string to buffer + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + // Write the string + supportsBuffer ? buffer.write(functionString, index, 'utf8') : writeToTypedArray(buffer, functionString, index); + // Update index + index = index + size - 1; + // Write zero + buffer[index++] = 0; + return index; + } + } else if(value instanceof Binary || value['_bsontype'] == 'Binary') { + // Write the type + buffer[index++] = BSON.BSON_DATA_BINARY; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Extract the buffer + var data = value.value(true); + // Calculate size + var size = value.position; + // Write the size of the string to buffer + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + // Write the subtype to the buffer + buffer[index++] = value.sub_type; + + // If we have binary type 2 the 4 first bytes are the size + if(value.sub_type == Binary.SUBTYPE_BYTE_ARRAY) { + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + } + + // Write the data to the object + supportsBuffer ? data.copy(buffer, index, 0, value.position) : buffer.set(data, index); + // Ajust index + index = index + value.position; + return index; + } else if(value instanceof Symbol || value['_bsontype'] == 'Symbol') { + // Write the type + buffer[index++] = BSON.BSON_DATA_SYMBOL; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Calculate size + var size = supportsBuffer ? Buffer.byteLength(value.value) + 1 : numberOfBytes(value.value) + 1; + // Write the size of the string to buffer + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + // Write the string + buffer.write(value.value, index, 'utf8'); + // Update index + index = index + size - 1; + // Write zero + buffer[index++] = 0x00; + return index; + } else if(value instanceof DBRef || value['_bsontype'] == 'DBRef') { + // Write the type + buffer[index++] = BSON.BSON_DATA_OBJECT; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Set up correct object for serialization + var ordered_values = { + '$ref': value.namespace + , '$id' : value.oid + }; + + // Add db reference if it exists + if(null != value.db) { + ordered_values['$db'] = value.db; + } + + // Message size + var size = BSON.calculateObjectSize(ordered_values, serializeFunctions); + // Serialize the object + var endIndex = BSON.serializeWithBufferAndIndex(ordered_values, checkKeys, buffer, index, serializeFunctions); + // Write the size of the string to buffer + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + // Write zero for object + buffer[endIndex++] = 0x00; + // Return the end index + return endIndex; + } else if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]') { + // Write the type + buffer[index++] = BSON.BSON_DATA_REGEXP; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + + // Write the regular expression string + supportsBuffer ? buffer.write(value.source, index, 'utf8') : writeToTypedArray(buffer, value.source, index); + // Adjust the index + index = index + (supportsBuffer ? Buffer.byteLength(value.source) : numberOfBytes(value.source)); + // Write zero + buffer[index++] = 0x00; + // Write the parameters + if(value.global) buffer[index++] = 0x73; // s + if(value.ignoreCase) buffer[index++] = 0x69; // i + if(value.multiline) buffer[index++] = 0x6d; // m + // Add ending zero + buffer[index++] = 0x00; + return index; + } else { + // Write the type + buffer[index++] = Array.isArray(value) ? BSON.BSON_DATA_ARRAY : BSON.BSON_DATA_OBJECT; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Adjust the index + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + var endIndex = serializeObject(value, checkKeys, buffer, index + 4, serializeFunctions); + // Write size + var size = endIndex - index; + // Write the size of the string to buffer + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + return endIndex; + } + case 'function': + // WTF for 0.4.X where typeof /someregexp/ === 'function' + if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]' || String.call(value) == '[object RegExp]') { + // Write the type + buffer[index++] = BSON.BSON_DATA_REGEXP; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + + // Write the regular expression string + buffer.write(value.source, index, 'utf8'); + // Adjust the index + index = index + (supportsBuffer ? Buffer.byteLength(value.source) : numberOfBytes(value.source)); + // Write zero + buffer[index++] = 0x00; + // Write the parameters + if(value.global) buffer[index++] = 0x73; // s + if(value.ignoreCase) buffer[index++] = 0x69; // i + if(value.multiline) buffer[index++] = 0x6d; // m + // Add ending zero + buffer[index++] = 0x00; + return index; + } else { + if(serializeFunctions && value.scope != null && Object.keys(value.scope).length > 0) { + // Write the type + buffer[index++] = BSON.BSON_DATA_CODE_W_SCOPE; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Calculate the scope size + var scopeSize = BSON.calculateObjectSize(value.scope, serializeFunctions); + // Function string + var functionString = value.toString(); + // Function Size + var codeSize = supportsBuffer ? Buffer.byteLength(functionString) + 1 : numberOfBytes(functionString) + 1; + + // Calculate full size of the object + var totalSize = 4 + codeSize + scopeSize; + + // Write the total size of the object + buffer[index++] = totalSize & 0xff; + buffer[index++] = (totalSize >> 8) & 0xff; + buffer[index++] = (totalSize >> 16) & 0xff; + buffer[index++] = (totalSize >> 24) & 0xff; + + // Write the size of the string to buffer + buffer[index++] = codeSize & 0xff; + buffer[index++] = (codeSize >> 8) & 0xff; + buffer[index++] = (codeSize >> 16) & 0xff; + buffer[index++] = (codeSize >> 24) & 0xff; + + // Write the string + supportsBuffer ? buffer.write(functionString, index, 'utf8') : writeToTypedArray(buffer, functionString, index); + // Update index + index = index + codeSize - 1; + // Write zero + buffer[index++] = 0; + // Serialize the scope object + var scopeObjectBuffer = new Buffer(scopeSize); + // Execute the serialization into a seperate buffer + serializeObject(value.scope, checkKeys, scopeObjectBuffer, 0, serializeFunctions); + + // Adjusted scope Size (removing the header) + var scopeDocSize = scopeSize - 4; + // Write scope object size + buffer[index++] = scopeDocSize & 0xff; + buffer[index++] = (scopeDocSize >> 8) & 0xff; + buffer[index++] = (scopeDocSize >> 16) & 0xff; + buffer[index++] = (scopeDocSize >> 24) & 0xff; + + // Write the scopeObject into the buffer + scopeObjectBuffer.copy(buffer, index, 0, scopeSize); + + // Adjust index, removing the empty size of the doc (5 bytes 0000000005) + index = index + scopeDocSize - 5; + // Write trailing zero + buffer[index++] = 0; + return index + } else if(serializeFunctions) { + buffer[index++] = BSON.BSON_DATA_CODE; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Function string + var functionString = value.toString(); + // Function Size + var size = supportsBuffer ? Buffer.byteLength(functionString) + 1 : numberOfBytes(functionString) + 1; + // Write the size of the string to buffer + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + // Write the string + supportsBuffer ? buffer.write(functionString, index, 'utf8') : writeToTypedArray(buffer, functionString, index); + // Update index + index = index + size - 1; + // Write zero + buffer[index++] = 0; + return index; + } + } + } + + // If no value to serialize + return index; +} + +/** + * Serialize a Javascript object. + * + * @param {Object} object the Javascript object to serialize. + * @param {Boolean} checkKeys the serializer will check if keys are valid. + * @param {Boolean} asBuffer return the serialized object as a Buffer object **(ignore)**. + * @param {Boolean} serializeFunctions serialize the javascript functions **(default:false)**. + * @return {Buffer} returns the Buffer object containing the serialized object. + * @api public + */ +BSON.serialize = function(object, checkKeys, asBuffer, serializeFunctions) { + // Throw error if we are trying serialize an illegal type + if(object == null || typeof object != 'object' || Array.isArray(object)) + throw new Error("Only javascript objects supported"); + + // Emoty target buffer + var buffer = null; + // Calculate the size of the object + var size = BSON.calculateObjectSize(object, serializeFunctions); + // Fetch the best available type for storing the binary data + if(buffer = typeof Buffer != 'undefined') { + buffer = new Buffer(size); + asBuffer = true; + } else if(typeof Uint8Array != 'undefined') { + buffer = new Uint8Array(new ArrayBuffer(size)); + } else { + buffer = new Array(size); + } + + // If asBuffer is false use typed arrays + BSON.serializeWithBufferAndIndex(object, checkKeys, buffer, 0, serializeFunctions); + return buffer; +} + +/** + * Contains the function cache if we have that enable to allow for avoiding the eval step on each deserialization, comparison is by md5 + * + * @ignore + * @api private + */ +var functionCache = BSON.functionCache = {}; + +/** + * Crc state variables shared by function + * + * @ignore + * @api private + */ +var table = [0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D]; + +/** + * CRC32 hash method, Fast and enough versitility for our usage + * + * @ignore + * @api private + */ +var crc32 = function(string, start, end) { + var crc = 0 + var x = 0; + var y = 0; + crc = crc ^ (-1); + + for(var i = start, iTop = end; i < iTop;i++) { + y = (crc ^ string[i]) & 0xFF; + x = table[y]; + crc = (crc >>> 8) ^ x; + } + + return crc ^ (-1); +} + +/** + * Deserialize stream data as BSON documents. + * + * Options + * - **evalFunctions** {Boolean, default:false}, evaluate functions in the BSON document scoped to the object deserialized. + * - **cacheFunctions** {Boolean, default:false}, cache evaluated functions for reuse. + * - **cacheFunctionsCrc32** {Boolean, default:false}, use a crc32 code for caching, otherwise use the string of the function. + * - **promoteLongs** {Boolean, default:true}, when deserializing a Long will fit it into a Number if it's smaller than 53 bits + * + * @param {Buffer} data the buffer containing the serialized set of BSON documents. + * @param {Number} startIndex the start index in the data Buffer where the deserialization is to start. + * @param {Number} numberOfDocuments number of documents to deserialize. + * @param {Array} documents an array where to store the deserialized documents. + * @param {Number} docStartIndex the index in the documents array from where to start inserting documents. + * @param {Object} [options] additional options used for the deserialization. + * @return {Number} returns the next index in the buffer after deserialization **x** numbers of documents. + * @api public + */ +BSON.deserializeStream = function(data, startIndex, numberOfDocuments, documents, docStartIndex, options) { + // if(numberOfDocuments !== documents.length) throw new Error("Number of expected results back is less than the number of documents"); + options = options != null ? options : {}; + var index = startIndex; + // Loop over all documents + for(var i = 0; i < numberOfDocuments; i++) { + // Find size of the document + var size = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; + // Update options with index + options['index'] = index; + // Parse the document at this point + documents[docStartIndex + i] = BSON.deserialize(data, options); + // Adjust index by the document size + index = index + size; + } + + // Return object containing end index of parsing and list of documents + return index; +} + +/** + * Ensure eval is isolated. + * + * @ignore + * @api private + */ +var isolateEvalWithHash = function(functionCache, hash, functionString, object) { + // Contains the value we are going to set + var value = null; + + // Check for cache hit, eval if missing and return cached function + if(functionCache[hash] == null) { + eval("value = " + functionString); + functionCache[hash] = value; + } + // Set the object + return functionCache[hash].bind(object); +} + +/** + * Ensure eval is isolated. + * + * @ignore + * @api private + */ +var isolateEval = function(functionString) { + // Contains the value we are going to set + var value = null; + // Eval the function + eval("value = " + functionString); + return value; +} + +/** + * Convert Uint8Array to String + * + * @ignore + * @api private + */ +var convertUint8ArrayToUtf8String = function(byteArray, startIndex, endIndex) { + return BinaryParser.decode_utf8(convertArraytoUtf8BinaryString(byteArray, startIndex, endIndex)); +} + +var convertArraytoUtf8BinaryString = function(byteArray, startIndex, endIndex) { + var result = ""; + for(var i = startIndex; i < endIndex; i++) { + result = result + String.fromCharCode(byteArray[i]); + } + + return result; +}; + +/** + * Deserialize data as BSON. + * + * Options + * - **evalFunctions** {Boolean, default:false}, evaluate functions in the BSON document scoped to the object deserialized. + * - **cacheFunctions** {Boolean, default:false}, cache evaluated functions for reuse. + * - **cacheFunctionsCrc32** {Boolean, default:false}, use a crc32 code for caching, otherwise use the string of the function. + * - **promoteLongs** {Boolean, default:true}, when deserializing a Long will fit it into a Number if it's smaller than 53 bits + * + * @param {Buffer} buffer the buffer containing the serialized set of BSON documents. + * @param {Object} [options] additional options used for the deserialization. + * @param {Boolean} [isArray] ignore used for recursive parsing. + * @return {Object} returns the deserialized Javascript Object. + * @api public + */ +BSON.deserialize = function(buffer, options, isArray) { + // Options + options = options == null ? {} : options; + var evalFunctions = options['evalFunctions'] == null ? false : options['evalFunctions']; + var cacheFunctions = options['cacheFunctions'] == null ? false : options['cacheFunctions']; + var cacheFunctionsCrc32 = options['cacheFunctionsCrc32'] == null ? false : options['cacheFunctionsCrc32']; + var promoteLongs = options['promoteLongs'] || true; + + // Validate that we have at least 4 bytes of buffer + if(buffer.length < 5) throw new Error("corrupt bson message < 5 bytes long"); + + // Set up index + var index = typeof options['index'] == 'number' ? options['index'] : 0; + // Reads in a C style string + var readCStyleString = function() { + // Get the start search index + var i = index; + // Locate the end of the c string + while(buffer[i] !== 0x00) { i++ } + // Grab utf8 encoded string + var string = supportsBuffer && Buffer.isBuffer(buffer) ? buffer.toString('utf8', index, i) : convertUint8ArrayToUtf8String(buffer, index, i); + // Update index position + index = i + 1; + // Return string + return string; + } + + // Create holding object + var object = isArray ? [] : {}; + + // Read the document size + var size = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + + // Ensure buffer is valid size + if(size < 5 || size > buffer.length) throw new Error("corrupt bson message"); + + // While we have more left data left keep parsing + while(true) { + // Read the type + var elementType = buffer[index++]; + // If we get a zero it's the last byte, exit + if(elementType == 0) break; + // Read the name of the field + var name = readCStyleString(); + // Switch on the type + switch(elementType) { + case BSON.BSON_DATA_OID: + var string = supportsBuffer && Buffer.isBuffer(buffer) ? buffer.toString('binary', index, index + 12) : convertArraytoUtf8BinaryString(buffer, index, index + 12); + // Decode the oid + object[name] = new ObjectID(string); + // Update index + index = index + 12; + break; + case BSON.BSON_DATA_STRING: + // Read the content of the field + var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Add string to object + object[name] = supportsBuffer && Buffer.isBuffer(buffer) ? buffer.toString('utf8', index, index + stringSize - 1) : convertUint8ArrayToUtf8String(buffer, index, index + stringSize - 1); + // Update parse index position + index = index + stringSize; + break; + case BSON.BSON_DATA_INT: + // Decode the 32bit value + object[name] = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + break; + case BSON.BSON_DATA_NUMBER: + // Decode the double value + object[name] = readIEEE754(buffer, index, 'little', 52, 8); + // Update the index + index = index + 8; + break; + case BSON.BSON_DATA_DATE: + // Unpack the low and high bits + var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Set date object + object[name] = new Date(new Long(lowBits, highBits).toNumber()); + break; + case BSON.BSON_DATA_BOOLEAN: + // Parse the boolean value + object[name] = buffer[index++] == 1; + break; + case BSON.BSON_DATA_NULL: + // Parse the boolean value + object[name] = null; + break; + case BSON.BSON_DATA_BINARY: + // Decode the size of the binary blob + var binarySize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Decode the subtype + var subType = buffer[index++]; + // Decode as raw Buffer object if options specifies it + if(buffer['slice'] != null) { + // If we have subtype 2 skip the 4 bytes for the size + if(subType == Binary.SUBTYPE_BYTE_ARRAY) { + binarySize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + } + // Slice the data + object[name] = new Binary(buffer.slice(index, index + binarySize), subType); + } else { + var _buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(binarySize)) : new Array(binarySize); + // If we have subtype 2 skip the 4 bytes for the size + if(subType == Binary.SUBTYPE_BYTE_ARRAY) { + binarySize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + } + // Copy the data + for(var i = 0; i < binarySize; i++) { + _buffer[i] = buffer[index + i]; + } + // Create the binary object + object[name] = new Binary(_buffer, subType); + } + // Update the index + index = index + binarySize; + break; + case BSON.BSON_DATA_ARRAY: + options['index'] = index; + // Decode the size of the array document + var objectSize = buffer[index] | buffer[index + 1] << 8 | buffer[index + 2] << 16 | buffer[index + 3] << 24; + // Set the array to the object + object[name] = BSON.deserialize(buffer, options, true); + // Adjust the index + index = index + objectSize; + break; + case BSON.BSON_DATA_OBJECT: + options['index'] = index; + // Decode the size of the object document + var objectSize = buffer[index] | buffer[index + 1] << 8 | buffer[index + 2] << 16 | buffer[index + 3] << 24; + // Set the array to the object + object[name] = BSON.deserialize(buffer, options, false); + // Adjust the index + index = index + objectSize; + break; + case BSON.BSON_DATA_REGEXP: + // Create the regexp + var source = readCStyleString(); + var regExpOptions = readCStyleString(); + // For each option add the corresponding one for javascript + var optionsArray = new Array(regExpOptions.length); + + // Parse options + for(var i = 0; i < regExpOptions.length; i++) { + switch(regExpOptions[i]) { + case 'm': + optionsArray[i] = 'm'; + break; + case 's': + optionsArray[i] = 'g'; + break; + case 'i': + optionsArray[i] = 'i'; + break; + } + } + + object[name] = new RegExp(source, optionsArray.join('')); + break; + case BSON.BSON_DATA_LONG: + // Unpack the low and high bits + var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Create long object + var long = new Long(lowBits, highBits); + // Promote the long if possible + if(promoteLongs) { + object[name] = long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG) ? long.toNumber() : long; + } else { + object[name] = long; + } + break; + case BSON.BSON_DATA_SYMBOL: + // Read the content of the field + var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Add string to object + object[name] = new Symbol(buffer.toString('utf8', index, index + stringSize - 1)); + // Update parse index position + index = index + stringSize; + break; + case BSON.BSON_DATA_TIMESTAMP: + // Unpack the low and high bits + var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Set the object + object[name] = new Timestamp(lowBits, highBits); + break; + case BSON.BSON_DATA_MIN_KEY: + // Parse the object + object[name] = new MinKey(); + break; + case BSON.BSON_DATA_MAX_KEY: + // Parse the object + object[name] = new MaxKey(); + break; + case BSON.BSON_DATA_CODE: + // Read the content of the field + var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Function string + var functionString = supportsBuffer && Buffer.isBuffer(buffer) ? buffer.toString('utf8', index, index + stringSize - 1) : convertUint8ArrayToUtf8String(buffer, index, index + stringSize - 1); + + // If we are evaluating the functions + if(evalFunctions) { + // Contains the value we are going to set + var value = null; + // If we have cache enabled let's look for the md5 of the function in the cache + if(cacheFunctions) { + var hash = cacheFunctionsCrc32 ? crc32(functionString) : functionString; + // Got to do this to avoid V8 deoptimizing the call due to finding eval + object[name] = isolateEvalWithHash(functionCache, hash, functionString, object); + } else { + // Set directly + object[name] = isolateEval(functionString); + } + } else { + object[name] = new Code(functionString, {}); + } + + // Update parse index position + index = index + stringSize; + break; + case BSON.BSON_DATA_CODE_W_SCOPE: + // Read the content of the field + var totalSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Javascript function + var functionString = supportsBuffer && Buffer.isBuffer(buffer) ? buffer.toString('utf8', index, index + stringSize - 1) : convertUint8ArrayToUtf8String(buffer, index, index + stringSize - 1); + // Update parse index position + index = index + stringSize; + // Parse the element + options['index'] = index; + // Decode the size of the object document + var objectSize = buffer[index] | buffer[index + 1] << 8 | buffer[index + 2] << 16 | buffer[index + 3] << 24; + // Decode the scope object + var scopeObject = BSON.deserialize(buffer, options, false); + // Adjust the index + index = index + objectSize; + + // If we are evaluating the functions + if(evalFunctions) { + // Contains the value we are going to set + var value = null; + // If we have cache enabled let's look for the md5 of the function in the cache + if(cacheFunctions) { + var hash = cacheFunctionsCrc32 ? crc32(functionString) : functionString; + // Got to do this to avoid V8 deoptimizing the call due to finding eval + object[name] = isolateEvalWithHash(functionCache, hash, functionString, object); + } else { + // Set directly + object[name] = isolateEval(functionString); + } + + // Set the scope on the object + object[name].scope = scopeObject; + } else { + object[name] = new Code(functionString, scopeObject); + } + + // Add string to object + break; + } + } + + // Check if we have a db ref object + if(object['$id'] != null) object = new DBRef(object['$ref'], object['$id'], object['$db']); + + // Return the final objects + return object; +} + +/** + * Check if key name is valid. + * + * @ignore + * @api private + */ +BSON.checkKey = function checkKey (key, dollarsAndDotsOk) { + if (!key.length) return; + // Check if we have a legal key for the object + if (!!~key.indexOf("\x00")) { + // The BSON spec doesn't allow keys with null bytes because keys are + // null-terminated. + throw Error("key " + key + " must not contain null bytes"); + } + if (!dollarsAndDotsOk) { + if('$' == key[0]) { + throw Error("key " + key + " must not start with '$'"); + } else if (!!~key.indexOf('.')) { + throw Error("key " + key + " must not contain '.'"); + } + } +}; + +/** + * Deserialize data as BSON. + * + * Options + * - **evalFunctions** {Boolean, default:false}, evaluate functions in the BSON document scoped to the object deserialized. + * - **cacheFunctions** {Boolean, default:false}, cache evaluated functions for reuse. + * - **cacheFunctionsCrc32** {Boolean, default:false}, use a crc32 code for caching, otherwise use the string of the function. + * + * @param {Buffer} buffer the buffer containing the serialized set of BSON documents. + * @param {Object} [options] additional options used for the deserialization. + * @param {Boolean} [isArray] ignore used for recursive parsing. + * @return {Object} returns the deserialized Javascript Object. + * @api public + */ +BSON.prototype.deserialize = function(data, options) { + return BSON.deserialize(data, options); +} + +/** + * Deserialize stream data as BSON documents. + * + * Options + * - **evalFunctions** {Boolean, default:false}, evaluate functions in the BSON document scoped to the object deserialized. + * - **cacheFunctions** {Boolean, default:false}, cache evaluated functions for reuse. + * - **cacheFunctionsCrc32** {Boolean, default:false}, use a crc32 code for caching, otherwise use the string of the function. + * + * @param {Buffer} data the buffer containing the serialized set of BSON documents. + * @param {Number} startIndex the start index in the data Buffer where the deserialization is to start. + * @param {Number} numberOfDocuments number of documents to deserialize. + * @param {Array} documents an array where to store the deserialized documents. + * @param {Number} docStartIndex the index in the documents array from where to start inserting documents. + * @param {Object} [options] additional options used for the deserialization. + * @return {Number} returns the next index in the buffer after deserialization **x** numbers of documents. + * @api public + */ +BSON.prototype.deserializeStream = function(data, startIndex, numberOfDocuments, documents, docStartIndex, options) { + return BSON.deserializeStream(data, startIndex, numberOfDocuments, documents, docStartIndex, options); +} + +/** + * Serialize a Javascript object. + * + * @param {Object} object the Javascript object to serialize. + * @param {Boolean} checkKeys the serializer will check if keys are valid. + * @param {Boolean} asBuffer return the serialized object as a Buffer object **(ignore)**. + * @param {Boolean} serializeFunctions serialize the javascript functions **(default:false)**. + * @return {Buffer} returns the Buffer object containing the serialized object. + * @api public + */ +BSON.prototype.serialize = function(object, checkKeys, asBuffer, serializeFunctions) { + return BSON.serialize(object, checkKeys, asBuffer, serializeFunctions); +} + +/** + * Calculate the bson size for a passed in Javascript object. + * + * @param {Object} object the Javascript object to calculate the BSON byte size for. + * @param {Boolean} [serializeFunctions] serialize all functions in the object **(default:false)**. + * @return {Number} returns the number of bytes the BSON object will take up. + * @api public + */ +BSON.prototype.calculateObjectSize = function(object, serializeFunctions) { + return BSON.calculateObjectSize(object, serializeFunctions); +} + +/** + * Serialize a Javascript object using a predefined Buffer and index into the buffer, useful when pre-allocating the space for serialization. + * + * @param {Object} object the Javascript object to serialize. + * @param {Boolean} checkKeys the serializer will check if keys are valid. + * @param {Buffer} buffer the Buffer you pre-allocated to store the serialized BSON object. + * @param {Number} index the index in the buffer where we wish to start serializing into. + * @param {Boolean} serializeFunctions serialize the javascript functions **(default:false)**. + * @return {Number} returns the new write index in the Buffer. + * @api public + */ +BSON.prototype.serializeWithBufferAndIndex = function(object, checkKeys, buffer, startIndex, serializeFunctions) { + return BSON.serializeWithBufferAndIndex(object, checkKeys, buffer, startIndex, serializeFunctions); +} + +/** + * @ignore + * @api private + */ +exports.Code = Code; +exports.Symbol = Symbol; +exports.BSON = BSON; +exports.DBRef = DBRef; +exports.Binary = Binary; +exports.ObjectID = ObjectID; +exports.Long = Long; +exports.Timestamp = Timestamp; +exports.Double = Double; +exports.MinKey = MinKey; +exports.MaxKey = MaxKey; + +}, + + + +'code': function(module, exports, global, require, undefined){ + /** + * A class representation of the BSON Code type. + * + * @class Represents the BSON Code type. + * @param {String|Function} code a string or function. + * @param {Object} [scope] an optional scope for the function. + * @return {Code} + */ +function Code(code, scope) { + if(!(this instanceof Code)) return new Code(code, scope); + + this._bsontype = 'Code'; + this.code = code; + this.scope = scope == null ? {} : scope; +}; + +/** + * @ignore + * @api private + */ +Code.prototype.toJSON = function() { + return {scope:this.scope, code:this.code}; +} + +exports.Code = Code; +}, + + + +'db_ref': function(module, exports, global, require, undefined){ + /** + * A class representation of the BSON DBRef type. + * + * @class Represents the BSON DBRef type. + * @param {String} namespace the collection name. + * @param {ObjectID} oid the reference ObjectID. + * @param {String} [db] optional db name, if omitted the reference is local to the current db. + * @return {DBRef} + */ +function DBRef(namespace, oid, db) { + if(!(this instanceof DBRef)) return new DBRef(namespace, oid, db); + + this._bsontype = 'DBRef'; + this.namespace = namespace; + this.oid = oid; + this.db = db; +}; + +/** + * @ignore + * @api private + */ +DBRef.prototype.toJSON = function() { + return { + '$ref':this.namespace, + '$id':this.oid, + '$db':this.db == null ? '' : this.db + }; +} + +exports.DBRef = DBRef; +}, + + + +'double': function(module, exports, global, require, undefined){ + /** + * A class representation of the BSON Double type. + * + * @class Represents the BSON Double type. + * @param {Number} value the number we want to represent as a double. + * @return {Double} + */ +function Double(value) { + if(!(this instanceof Double)) return new Double(value); + + this._bsontype = 'Double'; + this.value = value; +} + +/** + * Access the number value. + * + * @return {Number} returns the wrapped double number. + * @api public + */ +Double.prototype.valueOf = function() { + return this.value; +}; + +/** + * @ignore + * @api private + */ +Double.prototype.toJSON = function() { + return this.value; +} + +exports.Double = Double; +}, + + + +'float_parser': function(module, exports, global, require, undefined){ + // Copyright (c) 2008, Fair Oaks Labs, Inc. +// 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 Fair Oaks Labs, Inc. 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 OWNER 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. +// +// +// Modifications to writeIEEE754 to support negative zeroes made by Brian White + +var readIEEE754 = function(buffer, offset, endian, mLen, nBytes) { + var e, m, + bBE = (endian === 'big'), + eLen = nBytes * 8 - mLen - 1, + eMax = (1 << eLen) - 1, + eBias = eMax >> 1, + nBits = -7, + i = bBE ? 0 : (nBytes - 1), + d = bBE ? 1 : -1, + s = buffer[offset + i]; + + i += d; + + e = s & ((1 << (-nBits)) - 1); + s >>= (-nBits); + nBits += eLen; + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8); + + m = e & ((1 << (-nBits)) - 1); + e >>= (-nBits); + nBits += mLen; + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8); + + if (e === 0) { + e = 1 - eBias; + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity); + } else { + m = m + Math.pow(2, mLen); + e = e - eBias; + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen); +}; + +var writeIEEE754 = function(buffer, value, offset, endian, mLen, nBytes) { + var e, m, c, + bBE = (endian === 'big'), + eLen = nBytes * 8 - mLen - 1, + eMax = (1 << eLen) - 1, + eBias = eMax >> 1, + rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0), + i = bBE ? (nBytes-1) : 0, + d = bBE ? -1 : 1, + s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; + + value = Math.abs(value); + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0; + e = eMax; + } else { + e = Math.floor(Math.log(value) / Math.LN2); + if (value * (c = Math.pow(2, -e)) < 1) { + e--; + c *= 2; + } + if (e+eBias >= 1) { + value += rt / c; + } else { + value += rt * Math.pow(2, 1 - eBias); + } + if (value * c >= 2) { + e++; + c /= 2; + } + + if (e + eBias >= eMax) { + m = 0; + e = eMax; + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen); + e = e + eBias; + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); + e = 0; + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8); + + e = (e << mLen) | m; + eLen += mLen; + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8); + + buffer[offset + i - d] |= s * 128; +}; + +exports.readIEEE754 = readIEEE754; +exports.writeIEEE754 = writeIEEE754; +}, + + + +'index': function(module, exports, global, require, undefined){ + try { + exports.BSONPure = require('./bson'); + exports.BSONNative = require('../../ext'); +} catch(err) { + // do nothing +} + +[ './binary_parser' + , './binary' + , './code' + , './db_ref' + , './double' + , './max_key' + , './min_key' + , './objectid' + , './symbol' + , './timestamp' + , './long'].forEach(function (path) { + var module = require('./' + path); + for (var i in module) { + exports[i] = module[i]; + } +}); + +// Exports all the classes for the NATIVE JS BSON Parser +exports.native = function() { + var classes = {}; + // Map all the classes + [ './binary_parser' + , './binary' + , './code' + , './db_ref' + , './double' + , './max_key' + , './min_key' + , './objectid' + , './symbol' + , './timestamp' + , './long' + , '../../ext' +].forEach(function (path) { + var module = require('./' + path); + for (var i in module) { + classes[i] = module[i]; + } + }); + // Return classes list + return classes; +} + +// Exports all the classes for the PURE JS BSON Parser +exports.pure = function() { + var classes = {}; + // Map all the classes + [ './binary_parser' + , './binary' + , './code' + , './db_ref' + , './double' + , './max_key' + , './min_key' + , './objectid' + , './symbol' + , './timestamp' + , './long' + , '././bson'].forEach(function (path) { + var module = require('./' + path); + for (var i in module) { + classes[i] = module[i]; + } + }); + // Return classes list + return classes; +} + +}, + + + +'long': function(module, exports, global, require, undefined){ + // Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Copyright 2009 Google Inc. All Rights Reserved + +/** + * Defines a Long class for representing a 64-bit two's-complement + * integer value, which faithfully simulates the behavior of a Java "Long". This + * implementation is derived from LongLib in GWT. + * + * Constructs a 64-bit two's-complement integer, given its low and high 32-bit + * values as *signed* integers. See the from* functions below for more + * convenient ways of constructing Longs. + * + * The internal representation of a Long is the two given signed, 32-bit values. + * We use 32-bit pieces because these are the size of integers on which + * Javascript performs bit-operations. For operations like addition and + * multiplication, we split each number into 16-bit pieces, which can easily be + * multiplied within Javascript's floating-point representation without overflow + * or change in sign. + * + * In the algorithms below, we frequently reduce the negative case to the + * positive case by negating the input(s) and then post-processing the result. + * Note that we must ALWAYS check specially whether those values are MIN_VALUE + * (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as + * a positive number, it overflows back into a negative). Not handling this + * case would often result in infinite recursion. + * + * @class Represents the BSON Long type. + * @param {Number} low the low (signed) 32 bits of the Long. + * @param {Number} high the high (signed) 32 bits of the Long. + */ +function Long(low, high) { + if(!(this instanceof Long)) return new Long(low, high); + + this._bsontype = 'Long'; + /** + * @type {number} + * @api private + */ + this.low_ = low | 0; // force into 32 signed bits. + + /** + * @type {number} + * @api private + */ + this.high_ = high | 0; // force into 32 signed bits. +}; + +/** + * Return the int value. + * + * @return {Number} the value, assuming it is a 32-bit integer. + * @api public + */ +Long.prototype.toInt = function() { + return this.low_; +}; + +/** + * Return the Number value. + * + * @return {Number} the closest floating-point representation to this value. + * @api public + */ +Long.prototype.toNumber = function() { + return this.high_ * Long.TWO_PWR_32_DBL_ + + this.getLowBitsUnsigned(); +}; + +/** + * Return the JSON value. + * + * @return {String} the JSON representation. + * @api public + */ +Long.prototype.toJSON = function() { + return this.toString(); +} + +/** + * Return the String value. + * + * @param {Number} [opt_radix] the radix in which the text should be written. + * @return {String} the textual representation of this value. + * @api public + */ +Long.prototype.toString = function(opt_radix) { + var radix = opt_radix || 10; + if (radix < 2 || 36 < radix) { + throw Error('radix out of range: ' + radix); + } + + if (this.isZero()) { + return '0'; + } + + if (this.isNegative()) { + if (this.equals(Long.MIN_VALUE)) { + // We need to change the Long value before it can be negated, so we remove + // the bottom-most digit in this base and then recurse to do the rest. + var radixLong = Long.fromNumber(radix); + var div = this.div(radixLong); + var rem = div.multiply(radixLong).subtract(this); + return div.toString(radix) + rem.toInt().toString(radix); + } else { + return '-' + this.negate().toString(radix); + } + } + + // Do several (6) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = Long.fromNumber(Math.pow(radix, 6)); + + var rem = this; + var result = ''; + while (true) { + var remDiv = rem.div(radixToPower); + var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt(); + var digits = intval.toString(radix); + + rem = remDiv; + if (rem.isZero()) { + return digits + result; + } else { + while (digits.length < 6) { + digits = '0' + digits; + } + result = '' + digits + result; + } + } +}; + +/** + * Return the high 32-bits value. + * + * @return {Number} the high 32-bits as a signed value. + * @api public + */ +Long.prototype.getHighBits = function() { + return this.high_; +}; + +/** + * Return the low 32-bits value. + * + * @return {Number} the low 32-bits as a signed value. + * @api public + */ +Long.prototype.getLowBits = function() { + return this.low_; +}; + +/** + * Return the low unsigned 32-bits value. + * + * @return {Number} the low 32-bits as an unsigned value. + * @api public + */ +Long.prototype.getLowBitsUnsigned = function() { + return (this.low_ >= 0) ? + this.low_ : Long.TWO_PWR_32_DBL_ + this.low_; +}; + +/** + * Returns the number of bits needed to represent the absolute value of this Long. + * + * @return {Number} Returns the number of bits needed to represent the absolute value of this Long. + * @api public + */ +Long.prototype.getNumBitsAbs = function() { + if (this.isNegative()) { + if (this.equals(Long.MIN_VALUE)) { + return 64; + } else { + return this.negate().getNumBitsAbs(); + } + } else { + var val = this.high_ != 0 ? this.high_ : this.low_; + for (var bit = 31; bit > 0; bit--) { + if ((val & (1 << bit)) != 0) { + break; + } + } + return this.high_ != 0 ? bit + 33 : bit + 1; + } +}; + +/** + * Return whether this value is zero. + * + * @return {Boolean} whether this value is zero. + * @api public + */ +Long.prototype.isZero = function() { + return this.high_ == 0 && this.low_ == 0; +}; + +/** + * Return whether this value is negative. + * + * @return {Boolean} whether this value is negative. + * @api public + */ +Long.prototype.isNegative = function() { + return this.high_ < 0; +}; + +/** + * Return whether this value is odd. + * + * @return {Boolean} whether this value is odd. + * @api public + */ +Long.prototype.isOdd = function() { + return (this.low_ & 1) == 1; +}; + +/** + * Return whether this Long equals the other + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long equals the other + * @api public + */ +Long.prototype.equals = function(other) { + return (this.high_ == other.high_) && (this.low_ == other.low_); +}; + +/** + * Return whether this Long does not equal the other. + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long does not equal the other. + * @api public + */ +Long.prototype.notEquals = function(other) { + return (this.high_ != other.high_) || (this.low_ != other.low_); +}; + +/** + * Return whether this Long is less than the other. + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long is less than the other. + * @api public + */ +Long.prototype.lessThan = function(other) { + return this.compare(other) < 0; +}; + +/** + * Return whether this Long is less than or equal to the other. + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long is less than or equal to the other. + * @api public + */ +Long.prototype.lessThanOrEqual = function(other) { + return this.compare(other) <= 0; +}; + +/** + * Return whether this Long is greater than the other. + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long is greater than the other. + * @api public + */ +Long.prototype.greaterThan = function(other) { + return this.compare(other) > 0; +}; + +/** + * Return whether this Long is greater than or equal to the other. + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long is greater than or equal to the other. + * @api public + */ +Long.prototype.greaterThanOrEqual = function(other) { + return this.compare(other) >= 0; +}; + +/** + * Compares this Long with the given one. + * + * @param {Long} other Long to compare against. + * @return {Boolean} 0 if they are the same, 1 if the this is greater, and -1 if the given one is greater. + * @api public + */ +Long.prototype.compare = function(other) { + if (this.equals(other)) { + return 0; + } + + var thisNeg = this.isNegative(); + var otherNeg = other.isNegative(); + if (thisNeg && !otherNeg) { + return -1; + } + if (!thisNeg && otherNeg) { + return 1; + } + + // at this point, the signs are the same, so subtraction will not overflow + if (this.subtract(other).isNegative()) { + return -1; + } else { + return 1; + } +}; + +/** + * The negation of this value. + * + * @return {Long} the negation of this value. + * @api public + */ +Long.prototype.negate = function() { + if (this.equals(Long.MIN_VALUE)) { + return Long.MIN_VALUE; + } else { + return this.not().add(Long.ONE); + } +}; + +/** + * Returns the sum of this and the given Long. + * + * @param {Long} other Long to add to this one. + * @return {Long} the sum of this and the given Long. + * @api public + */ +Long.prototype.add = function(other) { + // Divide each number into 4 chunks of 16 bits, and then sum the chunks. + + var a48 = this.high_ >>> 16; + var a32 = this.high_ & 0xFFFF; + var a16 = this.low_ >>> 16; + var a00 = this.low_ & 0xFFFF; + + var b48 = other.high_ >>> 16; + var b32 = other.high_ & 0xFFFF; + var b16 = other.low_ >>> 16; + var b00 = other.low_ & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 + b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 + b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 + b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 + b48; + c48 &= 0xFFFF; + return Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32); +}; + +/** + * Returns the difference of this and the given Long. + * + * @param {Long} other Long to subtract from this. + * @return {Long} the difference of this and the given Long. + * @api public + */ +Long.prototype.subtract = function(other) { + return this.add(other.negate()); +}; + +/** + * Returns the product of this and the given Long. + * + * @param {Long} other Long to multiply with this. + * @return {Long} the product of this and the other. + * @api public + */ +Long.prototype.multiply = function(other) { + if (this.isZero()) { + return Long.ZERO; + } else if (other.isZero()) { + return Long.ZERO; + } + + if (this.equals(Long.MIN_VALUE)) { + return other.isOdd() ? Long.MIN_VALUE : Long.ZERO; + } else if (other.equals(Long.MIN_VALUE)) { + return this.isOdd() ? Long.MIN_VALUE : Long.ZERO; + } + + if (this.isNegative()) { + if (other.isNegative()) { + return this.negate().multiply(other.negate()); + } else { + return this.negate().multiply(other).negate(); + } + } else if (other.isNegative()) { + return this.multiply(other.negate()).negate(); + } + + // If both Longs are small, use float multiplication + if (this.lessThan(Long.TWO_PWR_24_) && + other.lessThan(Long.TWO_PWR_24_)) { + return Long.fromNumber(this.toNumber() * other.toNumber()); + } + + // Divide each Long into 4 chunks of 16 bits, and then add up 4x4 products. + // We can skip products that would overflow. + + var a48 = this.high_ >>> 16; + var a32 = this.high_ & 0xFFFF; + var a16 = this.low_ >>> 16; + var a00 = this.low_ & 0xFFFF; + + var b48 = other.high_ >>> 16; + var b32 = other.high_ & 0xFFFF; + var b16 = other.low_ >>> 16; + var b00 = other.low_ & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 * b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 * b00; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c16 += a00 * b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 * b00; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a16 * b16; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a00 * b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; + c48 &= 0xFFFF; + return Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32); +}; + +/** + * Returns this Long divided by the given one. + * + * @param {Long} other Long by which to divide. + * @return {Long} this Long divided by the given one. + * @api public + */ +Long.prototype.div = function(other) { + if (other.isZero()) { + throw Error('division by zero'); + } else if (this.isZero()) { + return Long.ZERO; + } + + if (this.equals(Long.MIN_VALUE)) { + if (other.equals(Long.ONE) || + other.equals(Long.NEG_ONE)) { + return Long.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE + } else if (other.equals(Long.MIN_VALUE)) { + return Long.ONE; + } else { + // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. + var halfThis = this.shiftRight(1); + var approx = halfThis.div(other).shiftLeft(1); + if (approx.equals(Long.ZERO)) { + return other.isNegative() ? Long.ONE : Long.NEG_ONE; + } else { + var rem = this.subtract(other.multiply(approx)); + var result = approx.add(rem.div(other)); + return result; + } + } + } else if (other.equals(Long.MIN_VALUE)) { + return Long.ZERO; + } + + if (this.isNegative()) { + if (other.isNegative()) { + return this.negate().div(other.negate()); + } else { + return this.negate().div(other).negate(); + } + } else if (other.isNegative()) { + return this.div(other.negate()).negate(); + } + + // Repeat the following until the remainder is less than other: find a + // floating-point that approximates remainder / other *from below*, add this + // into the result, and subtract it from the remainder. It is critical that + // the approximate value is less than or equal to the real value so that the + // remainder never becomes negative. + var res = Long.ZERO; + var rem = this; + while (rem.greaterThanOrEqual(other)) { + // Approximate the result of division. This may be a little greater or + // smaller than the actual value. + var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())); + + // We will tweak the approximate result by changing it in the 48-th digit or + // the smallest non-fractional digit, whichever is larger. + var log2 = Math.ceil(Math.log(approx) / Math.LN2); + var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48); + + // Decrease the approximation until it is smaller than the remainder. Note + // that if it is too large, the product overflows and is negative. + var approxRes = Long.fromNumber(approx); + var approxRem = approxRes.multiply(other); + while (approxRem.isNegative() || approxRem.greaterThan(rem)) { + approx -= delta; + approxRes = Long.fromNumber(approx); + approxRem = approxRes.multiply(other); + } + + // We know the answer can't be zero... and actually, zero would cause + // infinite recursion since we would make no progress. + if (approxRes.isZero()) { + approxRes = Long.ONE; + } + + res = res.add(approxRes); + rem = rem.subtract(approxRem); + } + return res; +}; + +/** + * Returns this Long modulo the given one. + * + * @param {Long} other Long by which to mod. + * @return {Long} this Long modulo the given one. + * @api public + */ +Long.prototype.modulo = function(other) { + return this.subtract(this.div(other).multiply(other)); +}; + +/** + * The bitwise-NOT of this value. + * + * @return {Long} the bitwise-NOT of this value. + * @api public + */ +Long.prototype.not = function() { + return Long.fromBits(~this.low_, ~this.high_); +}; + +/** + * Returns the bitwise-AND of this Long and the given one. + * + * @param {Long} other the Long with which to AND. + * @return {Long} the bitwise-AND of this and the other. + * @api public + */ +Long.prototype.and = function(other) { + return Long.fromBits(this.low_ & other.low_, this.high_ & other.high_); +}; + +/** + * Returns the bitwise-OR of this Long and the given one. + * + * @param {Long} other the Long with which to OR. + * @return {Long} the bitwise-OR of this and the other. + * @api public + */ +Long.prototype.or = function(other) { + return Long.fromBits(this.low_ | other.low_, this.high_ | other.high_); +}; + +/** + * Returns the bitwise-XOR of this Long and the given one. + * + * @param {Long} other the Long with which to XOR. + * @return {Long} the bitwise-XOR of this and the other. + * @api public + */ +Long.prototype.xor = function(other) { + return Long.fromBits(this.low_ ^ other.low_, this.high_ ^ other.high_); +}; + +/** + * Returns this Long with bits shifted to the left by the given amount. + * + * @param {Number} numBits the number of bits by which to shift. + * @return {Long} this shifted to the left by the given amount. + * @api public + */ +Long.prototype.shiftLeft = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var low = this.low_; + if (numBits < 32) { + var high = this.high_; + return Long.fromBits( + low << numBits, + (high << numBits) | (low >>> (32 - numBits))); + } else { + return Long.fromBits(0, low << (numBits - 32)); + } + } +}; + +/** + * Returns this Long with bits shifted to the right by the given amount. + * + * @param {Number} numBits the number of bits by which to shift. + * @return {Long} this shifted to the right by the given amount. + * @api public + */ +Long.prototype.shiftRight = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var high = this.high_; + if (numBits < 32) { + var low = this.low_; + return Long.fromBits( + (low >>> numBits) | (high << (32 - numBits)), + high >> numBits); + } else { + return Long.fromBits( + high >> (numBits - 32), + high >= 0 ? 0 : -1); + } + } +}; + +/** + * Returns this Long with bits shifted to the right by the given amount, with the new top bits matching the current sign bit. + * + * @param {Number} numBits the number of bits by which to shift. + * @return {Long} this shifted to the right by the given amount, with zeros placed into the new leading bits. + * @api public + */ +Long.prototype.shiftRightUnsigned = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var high = this.high_; + if (numBits < 32) { + var low = this.low_; + return Long.fromBits( + (low >>> numBits) | (high << (32 - numBits)), + high >>> numBits); + } else if (numBits == 32) { + return Long.fromBits(high, 0); + } else { + return Long.fromBits(high >>> (numBits - 32), 0); + } + } +}; + +/** + * Returns a Long representing the given (32-bit) integer value. + * + * @param {Number} value the 32-bit integer in question. + * @return {Long} the corresponding Long value. + * @api public + */ +Long.fromInt = function(value) { + if (-128 <= value && value < 128) { + var cachedObj = Long.INT_CACHE_[value]; + if (cachedObj) { + return cachedObj; + } + } + + var obj = new Long(value | 0, value < 0 ? -1 : 0); + if (-128 <= value && value < 128) { + Long.INT_CACHE_[value] = obj; + } + return obj; +}; + +/** + * Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned. + * + * @param {Number} value the number in question. + * @return {Long} the corresponding Long value. + * @api public + */ +Long.fromNumber = function(value) { + if (isNaN(value) || !isFinite(value)) { + return Long.ZERO; + } else if (value <= -Long.TWO_PWR_63_DBL_) { + return Long.MIN_VALUE; + } else if (value + 1 >= Long.TWO_PWR_63_DBL_) { + return Long.MAX_VALUE; + } else if (value < 0) { + return Long.fromNumber(-value).negate(); + } else { + return new Long( + (value % Long.TWO_PWR_32_DBL_) | 0, + (value / Long.TWO_PWR_32_DBL_) | 0); + } +}; + +/** + * Returns a Long representing the 64-bit integer that comes by concatenating the given high and low bits. Each is assumed to use 32 bits. + * + * @param {Number} lowBits the low 32-bits. + * @param {Number} highBits the high 32-bits. + * @return {Long} the corresponding Long value. + * @api public + */ +Long.fromBits = function(lowBits, highBits) { + return new Long(lowBits, highBits); +}; + +/** + * Returns a Long representation of the given string, written using the given radix. + * + * @param {String} str the textual representation of the Long. + * @param {Number} opt_radix the radix in which the text is written. + * @return {Long} the corresponding Long value. + * @api public + */ +Long.fromString = function(str, opt_radix) { + if (str.length == 0) { + throw Error('number format error: empty string'); + } + + var radix = opt_radix || 10; + if (radix < 2 || 36 < radix) { + throw Error('radix out of range: ' + radix); + } + + if (str.charAt(0) == '-') { + return Long.fromString(str.substring(1), radix).negate(); + } else if (str.indexOf('-') >= 0) { + throw Error('number format error: interior "-" character: ' + str); + } + + // Do several (8) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = Long.fromNumber(Math.pow(radix, 8)); + + var result = Long.ZERO; + for (var i = 0; i < str.length; i += 8) { + var size = Math.min(8, str.length - i); + var value = parseInt(str.substring(i, i + size), radix); + if (size < 8) { + var power = Long.fromNumber(Math.pow(radix, size)); + result = result.multiply(power).add(Long.fromNumber(value)); + } else { + result = result.multiply(radixToPower); + result = result.add(Long.fromNumber(value)); + } + } + return result; +}; + +// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the +// from* methods on which they depend. + + +/** + * A cache of the Long representations of small integer values. + * @type {Object} + * @api private + */ +Long.INT_CACHE_ = {}; + +// NOTE: the compiler should inline these constant values below and then remove +// these variables, so there should be no runtime penalty for these. + +/** + * Number used repeated below in calculations. This must appear before the + * first call to any from* function below. + * @type {number} + * @api private + */ +Long.TWO_PWR_16_DBL_ = 1 << 16; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_24_DBL_ = 1 << 24; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_32_DBL_ = Long.TWO_PWR_16_DBL_ * Long.TWO_PWR_16_DBL_; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_31_DBL_ = Long.TWO_PWR_32_DBL_ / 2; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_48_DBL_ = Long.TWO_PWR_32_DBL_ * Long.TWO_PWR_16_DBL_; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_64_DBL_ = Long.TWO_PWR_32_DBL_ * Long.TWO_PWR_32_DBL_; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_63_DBL_ = Long.TWO_PWR_64_DBL_ / 2; + +/** @type {Long} */ +Long.ZERO = Long.fromInt(0); + +/** @type {Long} */ +Long.ONE = Long.fromInt(1); + +/** @type {Long} */ +Long.NEG_ONE = Long.fromInt(-1); + +/** @type {Long} */ +Long.MAX_VALUE = + Long.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); + +/** @type {Long} */ +Long.MIN_VALUE = Long.fromBits(0, 0x80000000 | 0); + +/** + * @type {Long} + * @api private + */ +Long.TWO_PWR_24_ = Long.fromInt(1 << 24); + +/** + * Expose. + */ +exports.Long = Long; +}, + + + +'max_key': function(module, exports, global, require, undefined){ + /** + * A class representation of the BSON MaxKey type. + * + * @class Represents the BSON MaxKey type. + * @return {MaxKey} + */ +function MaxKey() { + if(!(this instanceof MaxKey)) return new MaxKey(); + + this._bsontype = 'MaxKey'; +} + +exports.MaxKey = MaxKey; +}, + + + +'min_key': function(module, exports, global, require, undefined){ + /** + * A class representation of the BSON MinKey type. + * + * @class Represents the BSON MinKey type. + * @return {MinKey} + */ +function MinKey() { + if(!(this instanceof MinKey)) return new MinKey(); + + this._bsontype = 'MinKey'; +} + +exports.MinKey = MinKey; +}, + + + +'objectid': function(module, exports, global, require, undefined){ + /** + * Module dependencies. + */ +var BinaryParser = require('./binary_parser').BinaryParser; + +/** + * Machine id. + * + * Create a random 3-byte value (i.e. unique for this + * process). Other drivers use a md5 of the machine id here, but + * that would mean an asyc call to gethostname, so we don't bother. + */ +var MACHINE_ID = parseInt(Math.random() * 0xFFFFFF, 10); + +// Regular expression that checks for hex value +var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$"); + +/** +* Create a new ObjectID instance +* +* @class Represents the BSON ObjectID type +* @param {String|Number} id Can be a 24 byte hex string, 12 byte binary string or a Number. +* @return {Object} instance of ObjectID. +*/ +var ObjectID = function ObjectID(id, _hex) { + if(!(this instanceof ObjectID)) return new ObjectID(id, _hex); + + this._bsontype = 'ObjectID'; + var __id = null; + + // Throw an error if it's not a valid setup + if(id != null && 'number' != typeof id && (id.length != 12 && id.length != 24)) + throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters"); + + // Generate id based on the input + if(id == null || typeof id == 'number') { + // convert to 12 byte binary string + this.id = this.generate(id); + } else if(id != null && id.length === 12) { + // assume 12 byte string + this.id = id; + } else if(checkForHexRegExp.test(id)) { + return ObjectID.createFromHexString(id); + } else { + throw new Error("Value passed in is not a valid 24 character hex string"); + } + + if(ObjectID.cacheHexString) this.__id = this.toHexString(); +}; + +// Allow usage of ObjectId aswell as ObjectID +var ObjectId = ObjectID; + +/** +* Return the ObjectID id as a 24 byte hex string representation +* +* @return {String} return the 24 byte hex string representation. +* @api public +*/ +ObjectID.prototype.toHexString = function() { + if(ObjectID.cacheHexString && this.__id) return this.__id; + + var hexString = '' + , number + , value; + + for (var index = 0, len = this.id.length; index < len; index++) { + value = BinaryParser.toByte(this.id[index]); + number = value <= 15 + ? '0' + value.toString(16) + : value.toString(16); + hexString = hexString + number; + } + + if(ObjectID.cacheHexString) this.__id = hexString; + return hexString; +}; + +/** +* Update the ObjectID index used in generating new ObjectID's on the driver +* +* @return {Number} returns next index value. +* @api private +*/ +ObjectID.prototype.get_inc = function() { + return ObjectID.index = (ObjectID.index + 1) % 0xFFFFFF; +}; + +/** +* Update the ObjectID index used in generating new ObjectID's on the driver +* +* @return {Number} returns next index value. +* @api private +*/ +ObjectID.prototype.getInc = function() { + return this.get_inc(); +}; + +/** +* Generate a 12 byte id string used in ObjectID's +* +* @param {Number} [time] optional parameter allowing to pass in a second based timestamp. +* @return {String} return the 12 byte id binary string. +* @api private +*/ +ObjectID.prototype.generate = function(time) { + if ('number' == typeof time) { + var time4Bytes = BinaryParser.encodeInt(time, 32, true, true); + /* for time-based ObjectID the bytes following the time will be zeroed */ + var machine3Bytes = BinaryParser.encodeInt(MACHINE_ID, 24, false); + var pid2Bytes = BinaryParser.fromShort(typeof process === 'undefined' ? Math.floor(Math.random() * 100000) : process.pid); + var index3Bytes = BinaryParser.encodeInt(this.get_inc(), 24, false, true); + } else { + var unixTime = parseInt(Date.now()/1000,10); + var time4Bytes = BinaryParser.encodeInt(unixTime, 32, true, true); + var machine3Bytes = BinaryParser.encodeInt(MACHINE_ID, 24, false); + var pid2Bytes = BinaryParser.fromShort(typeof process === 'undefined' ? Math.floor(Math.random() * 100000) : process.pid); + var index3Bytes = BinaryParser.encodeInt(this.get_inc(), 24, false, true); + } + + return time4Bytes + machine3Bytes + pid2Bytes + index3Bytes; +}; + +/** +* Converts the id into a 24 byte hex string for printing +* +* @return {String} return the 24 byte hex string representation. +* @api private +*/ +ObjectID.prototype.toString = function() { + return this.toHexString(); +}; + +/** +* Converts to a string representation of this Id. +* +* @return {String} return the 24 byte hex string representation. +* @api private +*/ +ObjectID.prototype.inspect = ObjectID.prototype.toString; + +/** +* Converts to its JSON representation. +* +* @return {String} return the 24 byte hex string representation. +* @api private +*/ +ObjectID.prototype.toJSON = function() { + return this.toHexString(); +}; + +/** +* Compares the equality of this ObjectID with `otherID`. +* +* @param {Object} otherID ObjectID instance to compare against. +* @return {Bool} the result of comparing two ObjectID's +* @api public +*/ +ObjectID.prototype.equals = function equals (otherID) { + var id = (otherID instanceof ObjectID || otherID.toHexString) + ? otherID.id + : ObjectID.createFromHexString(otherID).id; + + return this.id === id; +} + +/** +* Returns the generation date (accurate up to the second) that this ID was generated. +* +* @return {Date} the generation date +* @api public +*/ +ObjectID.prototype.getTimestamp = function() { + var timestamp = new Date(); + timestamp.setTime(Math.floor(BinaryParser.decodeInt(this.id.substring(0,4), 32, true, true)) * 1000); + return timestamp; +} + +/** +* @ignore +* @api private +*/ +ObjectID.index = 0; + +ObjectID.createPk = function createPk () { + return new ObjectID(); +}; + +/** +* Creates an ObjectID from a second based number, with the rest of the ObjectID zeroed out. Used for comparisons or sorting the ObjectID. +* +* @param {Number} time an integer number representing a number of seconds. +* @return {ObjectID} return the created ObjectID +* @api public +*/ +ObjectID.createFromTime = function createFromTime (time) { + var id = BinaryParser.encodeInt(time, 32, true, true) + + BinaryParser.encodeInt(0, 64, true, true); + return new ObjectID(id); +}; + +/** +* Creates an ObjectID from a hex string representation of an ObjectID. +* +* @param {String} hexString create a ObjectID from a passed in 24 byte hexstring. +* @return {ObjectID} return the created ObjectID +* @api public +*/ +ObjectID.createFromHexString = function createFromHexString (hexString) { + // Throw an error if it's not a valid setup + if(typeof hexString === 'undefined' || hexString != null && hexString.length != 24) + throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters"); + + var len = hexString.length; + + if(len > 12*2) { + throw new Error('Id cannot be longer than 12 bytes'); + } + + var result = '' + , string + , number; + + for (var index = 0; index < len; index += 2) { + string = hexString.substr(index, 2); + number = parseInt(string, 16); + result += BinaryParser.fromByte(number); + } + + return new ObjectID(result, hexString); +}; + +/** +* @ignore +*/ +Object.defineProperty(ObjectID.prototype, "generationTime", { + enumerable: true + , get: function () { + return Math.floor(BinaryParser.decodeInt(this.id.substring(0,4), 32, true, true)); + } + , set: function (value) { + var value = BinaryParser.encodeInt(value, 32, true, true); + this.id = value + this.id.substr(4); + // delete this.__id; + this.toHexString(); + } +}); + +/** + * Expose. + */ +exports.ObjectID = ObjectID; +exports.ObjectId = ObjectID; + +}, + + + +'symbol': function(module, exports, global, require, undefined){ + /** + * A class representation of the BSON Symbol type. + * + * @class Represents the BSON Symbol type. + * @param {String} value the string representing the symbol. + * @return {Symbol} + */ +function Symbol(value) { + if(!(this instanceof Symbol)) return new Symbol(value); + this._bsontype = 'Symbol'; + this.value = value; +} + +/** + * Access the wrapped string value. + * + * @return {String} returns the wrapped string. + * @api public + */ +Symbol.prototype.valueOf = function() { + return this.value; +}; + +/** + * @ignore + * @api private + */ +Symbol.prototype.toString = function() { + return this.value; +} + +/** + * @ignore + * @api private + */ +Symbol.prototype.inspect = function() { + return this.value; +} + +/** + * @ignore + * @api private + */ +Symbol.prototype.toJSON = function() { + return this.value; +} + +exports.Symbol = Symbol; +}, + + + +'timestamp': function(module, exports, global, require, undefined){ + // Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Copyright 2009 Google Inc. All Rights Reserved + +/** + * Defines a Timestamp class for representing a 64-bit two's-complement + * integer value, which faithfully simulates the behavior of a Java "Timestamp". This + * implementation is derived from TimestampLib in GWT. + * + * Constructs a 64-bit two's-complement integer, given its low and high 32-bit + * values as *signed* integers. See the from* functions below for more + * convenient ways of constructing Timestamps. + * + * The internal representation of a Timestamp is the two given signed, 32-bit values. + * We use 32-bit pieces because these are the size of integers on which + * Javascript performs bit-operations. For operations like addition and + * multiplication, we split each number into 16-bit pieces, which can easily be + * multiplied within Javascript's floating-point representation without overflow + * or change in sign. + * + * In the algorithms below, we frequently reduce the negative case to the + * positive case by negating the input(s) and then post-processing the result. + * Note that we must ALWAYS check specially whether those values are MIN_VALUE + * (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as + * a positive number, it overflows back into a negative). Not handling this + * case would often result in infinite recursion. + * + * @class Represents the BSON Timestamp type. + * @param {Number} low the low (signed) 32 bits of the Timestamp. + * @param {Number} high the high (signed) 32 bits of the Timestamp. + */ +function Timestamp(low, high) { + if(!(this instanceof Timestamp)) return new Timestamp(low, high); + this._bsontype = 'Timestamp'; + /** + * @type {number} + * @api private + */ + this.low_ = low | 0; // force into 32 signed bits. + + /** + * @type {number} + * @api private + */ + this.high_ = high | 0; // force into 32 signed bits. +}; + +/** + * Return the int value. + * + * @return {Number} the value, assuming it is a 32-bit integer. + * @api public + */ +Timestamp.prototype.toInt = function() { + return this.low_; +}; + +/** + * Return the Number value. + * + * @return {Number} the closest floating-point representation to this value. + * @api public + */ +Timestamp.prototype.toNumber = function() { + return this.high_ * Timestamp.TWO_PWR_32_DBL_ + + this.getLowBitsUnsigned(); +}; + +/** + * Return the JSON value. + * + * @return {String} the JSON representation. + * @api public + */ +Timestamp.prototype.toJSON = function() { + return this.toString(); +} + +/** + * Return the String value. + * + * @param {Number} [opt_radix] the radix in which the text should be written. + * @return {String} the textual representation of this value. + * @api public + */ +Timestamp.prototype.toString = function(opt_radix) { + var radix = opt_radix || 10; + if (radix < 2 || 36 < radix) { + throw Error('radix out of range: ' + radix); + } + + if (this.isZero()) { + return '0'; + } + + if (this.isNegative()) { + if (this.equals(Timestamp.MIN_VALUE)) { + // We need to change the Timestamp value before it can be negated, so we remove + // the bottom-most digit in this base and then recurse to do the rest. + var radixTimestamp = Timestamp.fromNumber(radix); + var div = this.div(radixTimestamp); + var rem = div.multiply(radixTimestamp).subtract(this); + return div.toString(radix) + rem.toInt().toString(radix); + } else { + return '-' + this.negate().toString(radix); + } + } + + // Do several (6) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = Timestamp.fromNumber(Math.pow(radix, 6)); + + var rem = this; + var result = ''; + while (true) { + var remDiv = rem.div(radixToPower); + var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt(); + var digits = intval.toString(radix); + + rem = remDiv; + if (rem.isZero()) { + return digits + result; + } else { + while (digits.length < 6) { + digits = '0' + digits; + } + result = '' + digits + result; + } + } +}; + +/** + * Return the high 32-bits value. + * + * @return {Number} the high 32-bits as a signed value. + * @api public + */ +Timestamp.prototype.getHighBits = function() { + return this.high_; +}; + +/** + * Return the low 32-bits value. + * + * @return {Number} the low 32-bits as a signed value. + * @api public + */ +Timestamp.prototype.getLowBits = function() { + return this.low_; +}; + +/** + * Return the low unsigned 32-bits value. + * + * @return {Number} the low 32-bits as an unsigned value. + * @api public + */ +Timestamp.prototype.getLowBitsUnsigned = function() { + return (this.low_ >= 0) ? + this.low_ : Timestamp.TWO_PWR_32_DBL_ + this.low_; +}; + +/** + * Returns the number of bits needed to represent the absolute value of this Timestamp. + * + * @return {Number} Returns the number of bits needed to represent the absolute value of this Timestamp. + * @api public + */ +Timestamp.prototype.getNumBitsAbs = function() { + if (this.isNegative()) { + if (this.equals(Timestamp.MIN_VALUE)) { + return 64; + } else { + return this.negate().getNumBitsAbs(); + } + } else { + var val = this.high_ != 0 ? this.high_ : this.low_; + for (var bit = 31; bit > 0; bit--) { + if ((val & (1 << bit)) != 0) { + break; + } + } + return this.high_ != 0 ? bit + 33 : bit + 1; + } +}; + +/** + * Return whether this value is zero. + * + * @return {Boolean} whether this value is zero. + * @api public + */ +Timestamp.prototype.isZero = function() { + return this.high_ == 0 && this.low_ == 0; +}; + +/** + * Return whether this value is negative. + * + * @return {Boolean} whether this value is negative. + * @api public + */ +Timestamp.prototype.isNegative = function() { + return this.high_ < 0; +}; + +/** + * Return whether this value is odd. + * + * @return {Boolean} whether this value is odd. + * @api public + */ +Timestamp.prototype.isOdd = function() { + return (this.low_ & 1) == 1; +}; + +/** + * Return whether this Timestamp equals the other + * + * @param {Timestamp} other Timestamp to compare against. + * @return {Boolean} whether this Timestamp equals the other + * @api public + */ +Timestamp.prototype.equals = function(other) { + return (this.high_ == other.high_) && (this.low_ == other.low_); +}; + +/** + * Return whether this Timestamp does not equal the other. + * + * @param {Timestamp} other Timestamp to compare against. + * @return {Boolean} whether this Timestamp does not equal the other. + * @api public + */ +Timestamp.prototype.notEquals = function(other) { + return (this.high_ != other.high_) || (this.low_ != other.low_); +}; + +/** + * Return whether this Timestamp is less than the other. + * + * @param {Timestamp} other Timestamp to compare against. + * @return {Boolean} whether this Timestamp is less than the other. + * @api public + */ +Timestamp.prototype.lessThan = function(other) { + return this.compare(other) < 0; +}; + +/** + * Return whether this Timestamp is less than or equal to the other. + * + * @param {Timestamp} other Timestamp to compare against. + * @return {Boolean} whether this Timestamp is less than or equal to the other. + * @api public + */ +Timestamp.prototype.lessThanOrEqual = function(other) { + return this.compare(other) <= 0; +}; + +/** + * Return whether this Timestamp is greater than the other. + * + * @param {Timestamp} other Timestamp to compare against. + * @return {Boolean} whether this Timestamp is greater than the other. + * @api public + */ +Timestamp.prototype.greaterThan = function(other) { + return this.compare(other) > 0; +}; + +/** + * Return whether this Timestamp is greater than or equal to the other. + * + * @param {Timestamp} other Timestamp to compare against. + * @return {Boolean} whether this Timestamp is greater than or equal to the other. + * @api public + */ +Timestamp.prototype.greaterThanOrEqual = function(other) { + return this.compare(other) >= 0; +}; + +/** + * Compares this Timestamp with the given one. + * + * @param {Timestamp} other Timestamp to compare against. + * @return {Boolean} 0 if they are the same, 1 if the this is greater, and -1 if the given one is greater. + * @api public + */ +Timestamp.prototype.compare = function(other) { + if (this.equals(other)) { + return 0; + } + + var thisNeg = this.isNegative(); + var otherNeg = other.isNegative(); + if (thisNeg && !otherNeg) { + return -1; + } + if (!thisNeg && otherNeg) { + return 1; + } + + // at this point, the signs are the same, so subtraction will not overflow + if (this.subtract(other).isNegative()) { + return -1; + } else { + return 1; + } +}; + +/** + * The negation of this value. + * + * @return {Timestamp} the negation of this value. + * @api public + */ +Timestamp.prototype.negate = function() { + if (this.equals(Timestamp.MIN_VALUE)) { + return Timestamp.MIN_VALUE; + } else { + return this.not().add(Timestamp.ONE); + } +}; + +/** + * Returns the sum of this and the given Timestamp. + * + * @param {Timestamp} other Timestamp to add to this one. + * @return {Timestamp} the sum of this and the given Timestamp. + * @api public + */ +Timestamp.prototype.add = function(other) { + // Divide each number into 4 chunks of 16 bits, and then sum the chunks. + + var a48 = this.high_ >>> 16; + var a32 = this.high_ & 0xFFFF; + var a16 = this.low_ >>> 16; + var a00 = this.low_ & 0xFFFF; + + var b48 = other.high_ >>> 16; + var b32 = other.high_ & 0xFFFF; + var b16 = other.low_ >>> 16; + var b00 = other.low_ & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 + b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 + b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 + b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 + b48; + c48 &= 0xFFFF; + return Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32); +}; + +/** + * Returns the difference of this and the given Timestamp. + * + * @param {Timestamp} other Timestamp to subtract from this. + * @return {Timestamp} the difference of this and the given Timestamp. + * @api public + */ +Timestamp.prototype.subtract = function(other) { + return this.add(other.negate()); +}; + +/** + * Returns the product of this and the given Timestamp. + * + * @param {Timestamp} other Timestamp to multiply with this. + * @return {Timestamp} the product of this and the other. + * @api public + */ +Timestamp.prototype.multiply = function(other) { + if (this.isZero()) { + return Timestamp.ZERO; + } else if (other.isZero()) { + return Timestamp.ZERO; + } + + if (this.equals(Timestamp.MIN_VALUE)) { + return other.isOdd() ? Timestamp.MIN_VALUE : Timestamp.ZERO; + } else if (other.equals(Timestamp.MIN_VALUE)) { + return this.isOdd() ? Timestamp.MIN_VALUE : Timestamp.ZERO; + } + + if (this.isNegative()) { + if (other.isNegative()) { + return this.negate().multiply(other.negate()); + } else { + return this.negate().multiply(other).negate(); + } + } else if (other.isNegative()) { + return this.multiply(other.negate()).negate(); + } + + // If both Timestamps are small, use float multiplication + if (this.lessThan(Timestamp.TWO_PWR_24_) && + other.lessThan(Timestamp.TWO_PWR_24_)) { + return Timestamp.fromNumber(this.toNumber() * other.toNumber()); + } + + // Divide each Timestamp into 4 chunks of 16 bits, and then add up 4x4 products. + // We can skip products that would overflow. + + var a48 = this.high_ >>> 16; + var a32 = this.high_ & 0xFFFF; + var a16 = this.low_ >>> 16; + var a00 = this.low_ & 0xFFFF; + + var b48 = other.high_ >>> 16; + var b32 = other.high_ & 0xFFFF; + var b16 = other.low_ >>> 16; + var b00 = other.low_ & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 * b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 * b00; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c16 += a00 * b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 * b00; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a16 * b16; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a00 * b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; + c48 &= 0xFFFF; + return Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32); +}; + +/** + * Returns this Timestamp divided by the given one. + * + * @param {Timestamp} other Timestamp by which to divide. + * @return {Timestamp} this Timestamp divided by the given one. + * @api public + */ +Timestamp.prototype.div = function(other) { + if (other.isZero()) { + throw Error('division by zero'); + } else if (this.isZero()) { + return Timestamp.ZERO; + } + + if (this.equals(Timestamp.MIN_VALUE)) { + if (other.equals(Timestamp.ONE) || + other.equals(Timestamp.NEG_ONE)) { + return Timestamp.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE + } else if (other.equals(Timestamp.MIN_VALUE)) { + return Timestamp.ONE; + } else { + // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. + var halfThis = this.shiftRight(1); + var approx = halfThis.div(other).shiftLeft(1); + if (approx.equals(Timestamp.ZERO)) { + return other.isNegative() ? Timestamp.ONE : Timestamp.NEG_ONE; + } else { + var rem = this.subtract(other.multiply(approx)); + var result = approx.add(rem.div(other)); + return result; + } + } + } else if (other.equals(Timestamp.MIN_VALUE)) { + return Timestamp.ZERO; + } + + if (this.isNegative()) { + if (other.isNegative()) { + return this.negate().div(other.negate()); + } else { + return this.negate().div(other).negate(); + } + } else if (other.isNegative()) { + return this.div(other.negate()).negate(); + } + + // Repeat the following until the remainder is less than other: find a + // floating-point that approximates remainder / other *from below*, add this + // into the result, and subtract it from the remainder. It is critical that + // the approximate value is less than or equal to the real value so that the + // remainder never becomes negative. + var res = Timestamp.ZERO; + var rem = this; + while (rem.greaterThanOrEqual(other)) { + // Approximate the result of division. This may be a little greater or + // smaller than the actual value. + var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())); + + // We will tweak the approximate result by changing it in the 48-th digit or + // the smallest non-fractional digit, whichever is larger. + var log2 = Math.ceil(Math.log(approx) / Math.LN2); + var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48); + + // Decrease the approximation until it is smaller than the remainder. Note + // that if it is too large, the product overflows and is negative. + var approxRes = Timestamp.fromNumber(approx); + var approxRem = approxRes.multiply(other); + while (approxRem.isNegative() || approxRem.greaterThan(rem)) { + approx -= delta; + approxRes = Timestamp.fromNumber(approx); + approxRem = approxRes.multiply(other); + } + + // We know the answer can't be zero... and actually, zero would cause + // infinite recursion since we would make no progress. + if (approxRes.isZero()) { + approxRes = Timestamp.ONE; + } + + res = res.add(approxRes); + rem = rem.subtract(approxRem); + } + return res; +}; + +/** + * Returns this Timestamp modulo the given one. + * + * @param {Timestamp} other Timestamp by which to mod. + * @return {Timestamp} this Timestamp modulo the given one. + * @api public + */ +Timestamp.prototype.modulo = function(other) { + return this.subtract(this.div(other).multiply(other)); +}; + +/** + * The bitwise-NOT of this value. + * + * @return {Timestamp} the bitwise-NOT of this value. + * @api public + */ +Timestamp.prototype.not = function() { + return Timestamp.fromBits(~this.low_, ~this.high_); +}; + +/** + * Returns the bitwise-AND of this Timestamp and the given one. + * + * @param {Timestamp} other the Timestamp with which to AND. + * @return {Timestamp} the bitwise-AND of this and the other. + * @api public + */ +Timestamp.prototype.and = function(other) { + return Timestamp.fromBits(this.low_ & other.low_, this.high_ & other.high_); +}; + +/** + * Returns the bitwise-OR of this Timestamp and the given one. + * + * @param {Timestamp} other the Timestamp with which to OR. + * @return {Timestamp} the bitwise-OR of this and the other. + * @api public + */ +Timestamp.prototype.or = function(other) { + return Timestamp.fromBits(this.low_ | other.low_, this.high_ | other.high_); +}; + +/** + * Returns the bitwise-XOR of this Timestamp and the given one. + * + * @param {Timestamp} other the Timestamp with which to XOR. + * @return {Timestamp} the bitwise-XOR of this and the other. + * @api public + */ +Timestamp.prototype.xor = function(other) { + return Timestamp.fromBits(this.low_ ^ other.low_, this.high_ ^ other.high_); +}; + +/** + * Returns this Timestamp with bits shifted to the left by the given amount. + * + * @param {Number} numBits the number of bits by which to shift. + * @return {Timestamp} this shifted to the left by the given amount. + * @api public + */ +Timestamp.prototype.shiftLeft = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var low = this.low_; + if (numBits < 32) { + var high = this.high_; + return Timestamp.fromBits( + low << numBits, + (high << numBits) | (low >>> (32 - numBits))); + } else { + return Timestamp.fromBits(0, low << (numBits - 32)); + } + } +}; + +/** + * Returns this Timestamp with bits shifted to the right by the given amount. + * + * @param {Number} numBits the number of bits by which to shift. + * @return {Timestamp} this shifted to the right by the given amount. + * @api public + */ +Timestamp.prototype.shiftRight = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var high = this.high_; + if (numBits < 32) { + var low = this.low_; + return Timestamp.fromBits( + (low >>> numBits) | (high << (32 - numBits)), + high >> numBits); + } else { + return Timestamp.fromBits( + high >> (numBits - 32), + high >= 0 ? 0 : -1); + } + } +}; + +/** + * Returns this Timestamp with bits shifted to the right by the given amount, with the new top bits matching the current sign bit. + * + * @param {Number} numBits the number of bits by which to shift. + * @return {Timestamp} this shifted to the right by the given amount, with zeros placed into the new leading bits. + * @api public + */ +Timestamp.prototype.shiftRightUnsigned = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var high = this.high_; + if (numBits < 32) { + var low = this.low_; + return Timestamp.fromBits( + (low >>> numBits) | (high << (32 - numBits)), + high >>> numBits); + } else if (numBits == 32) { + return Timestamp.fromBits(high, 0); + } else { + return Timestamp.fromBits(high >>> (numBits - 32), 0); + } + } +}; + +/** + * Returns a Timestamp representing the given (32-bit) integer value. + * + * @param {Number} value the 32-bit integer in question. + * @return {Timestamp} the corresponding Timestamp value. + * @api public + */ +Timestamp.fromInt = function(value) { + if (-128 <= value && value < 128) { + var cachedObj = Timestamp.INT_CACHE_[value]; + if (cachedObj) { + return cachedObj; + } + } + + var obj = new Timestamp(value | 0, value < 0 ? -1 : 0); + if (-128 <= value && value < 128) { + Timestamp.INT_CACHE_[value] = obj; + } + return obj; +}; + +/** + * Returns a Timestamp representing the given value, provided that it is a finite number. Otherwise, zero is returned. + * + * @param {Number} value the number in question. + * @return {Timestamp} the corresponding Timestamp value. + * @api public + */ +Timestamp.fromNumber = function(value) { + if (isNaN(value) || !isFinite(value)) { + return Timestamp.ZERO; + } else if (value <= -Timestamp.TWO_PWR_63_DBL_) { + return Timestamp.MIN_VALUE; + } else if (value + 1 >= Timestamp.TWO_PWR_63_DBL_) { + return Timestamp.MAX_VALUE; + } else if (value < 0) { + return Timestamp.fromNumber(-value).negate(); + } else { + return new Timestamp( + (value % Timestamp.TWO_PWR_32_DBL_) | 0, + (value / Timestamp.TWO_PWR_32_DBL_) | 0); + } +}; + +/** + * Returns a Timestamp representing the 64-bit integer that comes by concatenating the given high and low bits. Each is assumed to use 32 bits. + * + * @param {Number} lowBits the low 32-bits. + * @param {Number} highBits the high 32-bits. + * @return {Timestamp} the corresponding Timestamp value. + * @api public + */ +Timestamp.fromBits = function(lowBits, highBits) { + return new Timestamp(lowBits, highBits); +}; + +/** + * Returns a Timestamp representation of the given string, written using the given radix. + * + * @param {String} str the textual representation of the Timestamp. + * @param {Number} opt_radix the radix in which the text is written. + * @return {Timestamp} the corresponding Timestamp value. + * @api public + */ +Timestamp.fromString = function(str, opt_radix) { + if (str.length == 0) { + throw Error('number format error: empty string'); + } + + var radix = opt_radix || 10; + if (radix < 2 || 36 < radix) { + throw Error('radix out of range: ' + radix); + } + + if (str.charAt(0) == '-') { + return Timestamp.fromString(str.substring(1), radix).negate(); + } else if (str.indexOf('-') >= 0) { + throw Error('number format error: interior "-" character: ' + str); + } + + // Do several (8) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = Timestamp.fromNumber(Math.pow(radix, 8)); + + var result = Timestamp.ZERO; + for (var i = 0; i < str.length; i += 8) { + var size = Math.min(8, str.length - i); + var value = parseInt(str.substring(i, i + size), radix); + if (size < 8) { + var power = Timestamp.fromNumber(Math.pow(radix, size)); + result = result.multiply(power).add(Timestamp.fromNumber(value)); + } else { + result = result.multiply(radixToPower); + result = result.add(Timestamp.fromNumber(value)); + } + } + return result; +}; + +// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the +// from* methods on which they depend. + + +/** + * A cache of the Timestamp representations of small integer values. + * @type {Object} + * @api private + */ +Timestamp.INT_CACHE_ = {}; + +// NOTE: the compiler should inline these constant values below and then remove +// these variables, so there should be no runtime penalty for these. + +/** + * Number used repeated below in calculations. This must appear before the + * first call to any from* function below. + * @type {number} + * @api private + */ +Timestamp.TWO_PWR_16_DBL_ = 1 << 16; + +/** + * @type {number} + * @api private + */ +Timestamp.TWO_PWR_24_DBL_ = 1 << 24; + +/** + * @type {number} + * @api private + */ +Timestamp.TWO_PWR_32_DBL_ = Timestamp.TWO_PWR_16_DBL_ * Timestamp.TWO_PWR_16_DBL_; + +/** + * @type {number} + * @api private + */ +Timestamp.TWO_PWR_31_DBL_ = Timestamp.TWO_PWR_32_DBL_ / 2; + +/** + * @type {number} + * @api private + */ +Timestamp.TWO_PWR_48_DBL_ = Timestamp.TWO_PWR_32_DBL_ * Timestamp.TWO_PWR_16_DBL_; + +/** + * @type {number} + * @api private + */ +Timestamp.TWO_PWR_64_DBL_ = Timestamp.TWO_PWR_32_DBL_ * Timestamp.TWO_PWR_32_DBL_; + +/** + * @type {number} + * @api private + */ +Timestamp.TWO_PWR_63_DBL_ = Timestamp.TWO_PWR_64_DBL_ / 2; + +/** @type {Timestamp} */ +Timestamp.ZERO = Timestamp.fromInt(0); + +/** @type {Timestamp} */ +Timestamp.ONE = Timestamp.fromInt(1); + +/** @type {Timestamp} */ +Timestamp.NEG_ONE = Timestamp.fromInt(-1); + +/** @type {Timestamp} */ +Timestamp.MAX_VALUE = + Timestamp.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); + +/** @type {Timestamp} */ +Timestamp.MIN_VALUE = Timestamp.fromBits(0, 0x80000000 | 0); + +/** + * @type {Timestamp} + * @api private + */ +Timestamp.TWO_PWR_24_ = Timestamp.fromInt(1 << 24); + +/** + * Expose. + */ +exports.Timestamp = Timestamp; +}, + + }); + + +if(typeof module != 'undefined' && module.exports ){ + module.exports = bson; + + if( !module.parent ){ + bson(); + } +} + +if(typeof window != 'undefined' && typeof require == 'undefined'){ + window.require = bson.require; +} diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/browser_build/package.json b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/browser_build/package.json new file mode 100644 index 0000000..3ebb587 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/browser_build/package.json @@ -0,0 +1,8 @@ +{ "name" : "bson" +, "description" : "A bson parser for node.js and the browser" +, "main": "../lib/bson/bson" +, "directories" : { "lib" : "../lib/bson" } +, "engines" : { "node" : ">=0.6.0" } +, "licenses" : [ { "type" : "Apache License, Version 2.0" + , "url" : "http://www.apache.org/licenses/LICENSE-2.0" } ] +} diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Makefile b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Makefile new file mode 100644 index 0000000..c53dd58 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Makefile @@ -0,0 +1,354 @@ +# We borrow heavily from the kernel build setup, though we are simpler since +# we don't have Kconfig tweaking settings on us. + +# The implicit make rules have it looking for RCS files, among other things. +# We instead explicitly write all the rules we care about. +# It's even quicker (saves ~200ms) to pass -r on the command line. +MAKEFLAGS=-r + +# The source directory tree. +srcdir := .. +abs_srcdir := $(abspath $(srcdir)) + +# The name of the builddir. +builddir_name ?= . + +# The V=1 flag on command line makes us verbosely print command lines. +ifdef V + quiet= +else + quiet=quiet_ +endif + +# Specify BUILDTYPE=Release on the command line for a release build. +BUILDTYPE ?= Release + +# Directory all our build output goes into. +# Note that this must be two directories beneath src/ for unit tests to pass, +# as they reach into the src/ directory for data with relative paths. +builddir ?= $(builddir_name)/$(BUILDTYPE) +abs_builddir := $(abspath $(builddir)) +depsdir := $(builddir)/.deps + +# Object output directory. +obj := $(builddir)/obj +abs_obj := $(abspath $(obj)) + +# We build up a list of every single one of the targets so we can slurp in the +# generated dependency rule Makefiles in one pass. +all_deps := + + + +# C++ apps need to be linked with g++. +# +# Note: flock is used to seralize linking. Linking is a memory-intensive +# process so running parallel links can often lead to thrashing. To disable +# the serialization, override LINK via an envrionment variable as follows: +# +# export LINK=g++ +# +# This will allow make to invoke N linker processes as specified in -jN. +LINK ?= ./gyp-mac-tool flock $(builddir)/linker.lock $(CXX.target) + +CC.target ?= $(CC) +CFLAGS.target ?= $(CFLAGS) +CXX.target ?= $(CXX) +CXXFLAGS.target ?= $(CXXFLAGS) +LINK.target ?= $(LINK) +LDFLAGS.target ?= $(LDFLAGS) +AR.target ?= $(AR) + +# TODO(evan): move all cross-compilation logic to gyp-time so we don't need +# to replicate this environment fallback in make as well. +CC.host ?= gcc +CFLAGS.host ?= +CXX.host ?= g++ +CXXFLAGS.host ?= +LINK.host ?= g++ +LDFLAGS.host ?= +AR.host ?= ar + +# Define a dir function that can handle spaces. +# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions +# "leading spaces cannot appear in the text of the first argument as written. +# These characters can be put into the argument value by variable substitution." +empty := +space := $(empty) $(empty) + +# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces +replace_spaces = $(subst $(space),?,$1) +unreplace_spaces = $(subst ?,$(space),$1) +dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1))) + +# Flags to make gcc output dependency info. Note that you need to be +# careful here to use the flags that ccache and distcc can understand. +# We write to a dep file on the side first and then rename at the end +# so we can't end up with a broken dep file. +depfile = $(depsdir)/$(call replace_spaces,$@).d +DEPFLAGS = -MMD -MF $(depfile).raw + +# We have to fixup the deps output in a few ways. +# (1) the file output should mention the proper .o file. +# ccache or distcc lose the path to the target, so we convert a rule of +# the form: +# foobar.o: DEP1 DEP2 +# into +# path/to/foobar.o: DEP1 DEP2 +# (2) we want missing files not to cause us to fail to build. +# We want to rewrite +# foobar.o: DEP1 DEP2 \ +# DEP3 +# to +# DEP1: +# DEP2: +# DEP3: +# so if the files are missing, they're just considered phony rules. +# We have to do some pretty insane escaping to get those backslashes +# and dollar signs past make, the shell, and sed at the same time. +# Doesn't work with spaces, but that's fine: .d files have spaces in +# their names replaced with other characters. +define fixup_dep +# The depfile may not exist if the input file didn't have any #includes. +touch $(depfile).raw +# Fixup path as in (1). +sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile) +# Add extra rules as in (2). +# We remove slashes and replace spaces with new lines; +# remove blank lines; +# delete the first line and append a colon to the remaining lines. +sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ + grep -v '^$$' |\ + sed -e 1d -e 's|$$|:|' \ + >> $(depfile) +rm $(depfile).raw +endef + +# Command definitions: +# - cmd_foo is the actual command to run; +# - quiet_cmd_foo is the brief-output summary of the command. + +quiet_cmd_cc = CC($(TOOLSET)) $@ +cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_cxx = CXX($(TOOLSET)) $@ +cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_objc = CXX($(TOOLSET)) $@ +cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< + +quiet_cmd_objcxx = CXX($(TOOLSET)) $@ +cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# Commands for precompiled header files. +quiet_cmd_pch_c = CXX($(TOOLSET)) $@ +cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_cc = CXX($(TOOLSET)) $@ +cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_m = CXX($(TOOLSET)) $@ +cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< +quiet_cmd_pch_mm = CXX($(TOOLSET)) $@ +cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# gyp-mac-tool is written next to the root Makefile by gyp. +# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd +# already. +quiet_cmd_mac_tool = MACTOOL $(4) $< +cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@" + +quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@ +cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4) + +quiet_cmd_infoplist = INFOPLIST $@ +cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@" + +quiet_cmd_touch = TOUCH $@ +cmd_touch = touch $@ + +quiet_cmd_copy = COPY $@ +# send stderr to /dev/null to ignore messages when linking directories. +cmd_copy = rm -rf "$@" && cp -af "$<" "$@" + +quiet_cmd_alink = LIBTOOL-STATIC $@ +cmd_alink = rm -f $@ && ./gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^) + +quiet_cmd_link = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +# TODO(thakis): Find out and document the difference between shared_library and +# loadable_module on mac. +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +# TODO(thakis): The solink_module rule is likely wrong. Xcode seems to pass +# -bundle -single_module here (for osmesa.so). +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) + + +# Define an escape_quotes function to escape single quotes. +# This allows us to handle quotes properly as long as we always use +# use single quotes and escape_quotes. +escape_quotes = $(subst ','\'',$(1)) +# This comment is here just to include a ' to unconfuse syntax highlighting. +# Define an escape_vars function to escape '$' variable syntax. +# This allows us to read/write command lines with shell variables (e.g. +# $LD_LIBRARY_PATH), without triggering make substitution. +escape_vars = $(subst $$,$$$$,$(1)) +# Helper that expands to a shell command to echo a string exactly as it is in +# make. This uses printf instead of echo because printf's behaviour with respect +# to escape sequences is more portable than echo's across different shells +# (e.g., dash, bash). +exact_echo = printf '%s\n' '$(call escape_quotes,$(1))' + +# Helper to compare the command we're about to run against the command +# we logged the last time we ran the command. Produces an empty +# string (false) when the commands match. +# Tricky point: Make has no string-equality test function. +# The kernel uses the following, but it seems like it would have false +# positives, where one string reordered its arguments. +# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ +# $(filter-out $(cmd_$@), $(cmd_$(1)))) +# We instead substitute each for the empty string into the other, and +# say they're equal if both substitutions produce the empty string. +# .d files contain ? instead of spaces, take that into account. +command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\ + $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1)))) + +# Helper that is non-empty when a prerequisite changes. +# Normally make does this implicitly, but we force rules to always run +# so we can check their command lines. +# $? -- new prerequisites +# $| -- order-only dependencies +prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) + +# Helper that executes all postbuilds until one fails. +define do_postbuilds + @E=0;\ + for p in $(POSTBUILDS); do\ + eval $$p;\ + E=$$?;\ + if [ $$E -ne 0 ]; then\ + break;\ + fi;\ + done;\ + if [ $$E -ne 0 ]; then\ + rm -rf "$@";\ + exit $$E;\ + fi +endef + +# do_cmd: run a command via the above cmd_foo names, if necessary. +# Should always run for a given target to handle command-line changes. +# Second argument, if non-zero, makes it do asm/C/C++ dependency munging. +# Third argument, if non-zero, makes it do POSTBUILDS processing. +# Note: We intentionally do NOT call dirx for depfile, since it contains ? for +# spaces already and dirx strips the ? characters. +define do_cmd +$(if $(or $(command_changed),$(prereq_changed)), + @$(call exact_echo, $($(quiet)cmd_$(1))) + @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))" + $(if $(findstring flock,$(word 2,$(cmd_$1))), + @$(cmd_$(1)) + @echo " $(quiet_cmd_$(1)): Finished", + @$(cmd_$(1)) + ) + @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) + @$(if $(2),$(fixup_dep)) + $(if $(and $(3), $(POSTBUILDS)), + $(call do_postbuilds) + ) +) +endef + +# Declare the "all" target first so it is the default, +# even though we don't have the deps yet. +.PHONY: all +all: + +# make looks for ways to re-generate included makefiles, but in our case, we +# don't have a direct way. Explicitly telling make that it has nothing to do +# for them makes it go faster. +%.d: ; + +# Use FORCE_DO_CMD to force a target to run. Should be coupled with +# do_cmd. +.PHONY: FORCE_DO_CMD +FORCE_DO_CMD: + +TOOLSET := target +# Suffix rules, putting all outputs into $(obj). +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + + +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,bson.target.mk)))),) + include bson.target.mk +endif + +quiet_cmd_regen_makefile = ACTION Regenerating $@ +cmd_regen_makefile = /usr/local/Cellar/node/0.10.21/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -I/Users/brandon/OpenSource/mousewheeldatacollector/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/config.gypi -I/usr/local/Cellar/node/0.10.21/lib/node_modules/npm/node_modules/node-gyp/addon.gypi -I/Users/brandon/.node-gyp/0.10.21/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/brandon/.node-gyp/0.10.21" "-Dmodule_root_dir=/Users/brandon/OpenSource/mousewheeldatacollector/node_modules/mongoose/node_modules/mongodb/node_modules/bson" binding.gyp +Makefile: $(srcdir)/../../../../../../../../.node-gyp/0.10.21/common.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp $(srcdir)/../../../../../../../../../../usr/local/Cellar/node/0.10.21/lib/node_modules/npm/node_modules/node-gyp/addon.gypi + $(call do_cmd,regen_makefile) + +# "all" is a concatenation of the "all" targets from all the included +# sub-makefiles. This is just here to clarify. +all: + +# Add in dependency-tracking rules. $(all_deps) is the list of every single +# target in our tree. Only consider the ones with .d (dependency) info: +d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) +ifneq ($(d_files),) + include $(d_files) +endif diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Release/.deps/Release/bson.node.d b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Release/.deps/Release/bson.node.d new file mode 100644 index 0000000..396b6bf --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Release/.deps/Release/bson.node.d @@ -0,0 +1 @@ +cmd_Release/bson.node := ./gyp-mac-tool flock ./Release/linker.lock c++ -shared -Wl,-search_paths_first -mmacosx-version-min=10.5 -arch x86_64 -L./Release -install_name @rpath/bson.node -o Release/bson.node Release/obj.target/bson/ext/bson.o -undefined dynamic_lookup diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Release/.deps/Release/obj.target/bson/ext/bson.o.d b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Release/.deps/Release/obj.target/bson/ext/bson.o.d new file mode 100644 index 0000000..ef1d0e6 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Release/.deps/Release/obj.target/bson/ext/bson.o.d @@ -0,0 +1,24 @@ +cmd_Release/obj.target/bson/ext/bson.o := c++ '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DBUILDING_NODE_EXTENSION' -I/Users/brandon/.node-gyp/0.10.21/src -I/Users/brandon/.node-gyp/0.10.21/deps/uv/include -I/Users/brandon/.node-gyp/0.10.21/deps/v8/include -Os -gdwarf-2 -mmacosx-version-min=10.5 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-rtti -fno-threadsafe-statics -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/bson/ext/bson.o.d.raw -c -o Release/obj.target/bson/ext/bson.o ../ext/bson.cc +Release/obj.target/bson/ext/bson.o: ../ext/bson.cc \ + /Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8.h \ + /Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8stdint.h \ + /Users/brandon/.node-gyp/0.10.21/src/node.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-unix.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/ngx-queue.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-darwin.h \ + /Users/brandon/.node-gyp/0.10.21/src/node_object_wrap.h \ + /Users/brandon/.node-gyp/0.10.21/src/node_version.h \ + /Users/brandon/.node-gyp/0.10.21/src/node_buffer.h ../ext/bson.h +../ext/bson.cc: +/Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8.h: +/Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8stdint.h: +/Users/brandon/.node-gyp/0.10.21/src/node.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-unix.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/ngx-queue.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-darwin.h: +/Users/brandon/.node-gyp/0.10.21/src/node_object_wrap.h: +/Users/brandon/.node-gyp/0.10.21/src/node_version.h: +/Users/brandon/.node-gyp/0.10.21/src/node_buffer.h: +../ext/bson.h: diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Release/bson.node b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Release/bson.node new file mode 100755 index 0000000..48d2257 Binary files /dev/null and b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Release/bson.node differ diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Release/linker.lock b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Release/linker.lock new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Release/obj.target/bson/ext/bson.o b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Release/obj.target/bson/ext/bson.o new file mode 100644 index 0000000..3d48ece Binary files /dev/null and b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/Release/obj.target/bson/ext/bson.o differ diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/binding.Makefile b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/binding.Makefile new file mode 100644 index 0000000..90bf824 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/binding.Makefile @@ -0,0 +1,6 @@ +# This file is generated by gyp; do not edit. + +export builddir_name ?= build/./. +.PHONY: all +all: + $(MAKE) bson diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/bson.target.mk b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/bson.target.mk new file mode 100644 index 0000000..3122966 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/bson.target.mk @@ -0,0 +1,154 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := bson +DEFS_Debug := \ + '-D_DARWIN_USE_64_BIT_INODE=1' \ + '-D_LARGEFILE_SOURCE' \ + '-D_FILE_OFFSET_BITS=64' \ + '-DBUILDING_NODE_EXTENSION' \ + '-DDEBUG' \ + '-D_DEBUG' + +# Flags passed to all source files. +CFLAGS_Debug := \ + -O0 \ + -gdwarf-2 \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -Wall \ + -Wendif-labels \ + -W \ + -Wno-unused-parameter + +# Flags passed to only C files. +CFLAGS_C_Debug := \ + -fno-strict-aliasing + +# Flags passed to only C++ files. +CFLAGS_CC_Debug := \ + -fno-rtti \ + -fno-threadsafe-statics \ + -fno-strict-aliasing + +# Flags passed to only ObjC files. +CFLAGS_OBJC_Debug := + +# Flags passed to only ObjC++ files. +CFLAGS_OBJCC_Debug := + +INCS_Debug := \ + -I/Users/brandon/.node-gyp/0.10.21/src \ + -I/Users/brandon/.node-gyp/0.10.21/deps/uv/include \ + -I/Users/brandon/.node-gyp/0.10.21/deps/v8/include + +DEFS_Release := \ + '-D_DARWIN_USE_64_BIT_INODE=1' \ + '-D_LARGEFILE_SOURCE' \ + '-D_FILE_OFFSET_BITS=64' \ + '-DBUILDING_NODE_EXTENSION' + +# Flags passed to all source files. +CFLAGS_Release := \ + -Os \ + -gdwarf-2 \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -Wall \ + -Wendif-labels \ + -W \ + -Wno-unused-parameter + +# Flags passed to only C files. +CFLAGS_C_Release := \ + -fno-strict-aliasing + +# Flags passed to only C++ files. +CFLAGS_CC_Release := \ + -fno-rtti \ + -fno-threadsafe-statics \ + -fno-strict-aliasing + +# Flags passed to only ObjC files. +CFLAGS_OBJC_Release := + +# Flags passed to only ObjC++ files. +CFLAGS_OBJCC_Release := + +INCS_Release := \ + -I/Users/brandon/.node-gyp/0.10.21/src \ + -I/Users/brandon/.node-gyp/0.10.21/deps/uv/include \ + -I/Users/brandon/.node-gyp/0.10.21/deps/v8/include + +OBJS := \ + $(obj).target/$(TARGET)/ext/bson.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) +$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE)) +$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_Debug := \ + -Wl,-search_paths_first \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -L$(builddir) \ + -install_name @rpath/bson.node + +LIBTOOLFLAGS_Debug := \ + -Wl,-search_paths_first + +LDFLAGS_Release := \ + -Wl,-search_paths_first \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -L$(builddir) \ + -install_name @rpath/bson.node + +LIBTOOLFLAGS_Release := \ + -Wl,-search_paths_first + +LIBS := \ + -undefined dynamic_lookup + +$(builddir)/bson.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(builddir)/bson.node: LIBS := $(LIBS) +$(builddir)/bson.node: GYP_LIBTOOLFLAGS := $(LIBTOOLFLAGS_$(BUILDTYPE)) +$(builddir)/bson.node: TOOLSET := $(TOOLSET) +$(builddir)/bson.node: $(OBJS) FORCE_DO_CMD + $(call do_cmd,solink_module) + +all_deps += $(builddir)/bson.node +# Add target alias +.PHONY: bson +bson: $(builddir)/bson.node + +# Short alias for building this executable. +.PHONY: bson.node +bson.node: $(builddir)/bson.node + +# Add executable to "all" target. +.PHONY: all +all: $(builddir)/bson.node + diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/config.gypi b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/config.gypi new file mode 100644 index 0000000..b433275 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/config.gypi @@ -0,0 +1,112 @@ +# Do not edit. File was generated by node-gyp's "configure" step +{ + "target_defaults": { + "cflags": [], + "default_configuration": "Release", + "defines": [], + "include_dirs": [], + "libraries": [] + }, + "variables": { + "clang": 1, + "host_arch": "x64", + "node_install_npm": "true", + "node_prefix": "/usr/local/Cellar/node/0.10.21", + "node_shared_cares": "false", + "node_shared_http_parser": "false", + "node_shared_libuv": "false", + "node_shared_openssl": "false", + "node_shared_v8": "false", + "node_shared_zlib": "false", + "node_tag": "", + "node_unsafe_optimizations": 0, + "node_use_dtrace": "true", + "node_use_etw": "false", + "node_use_openssl": "true", + "node_use_perfctr": "false", + "python": "/usr/bin/python", + "target_arch": "x64", + "v8_enable_gdbjit": 0, + "v8_no_strict_aliasing": 1, + "v8_use_snapshot": "true", + "nodedir": "/Users/brandon/.node-gyp/0.10.21", + "copy_dev_lib": "true", + "standalone_static_library": 1, + "save_dev": "", + "browser": "", + "viewer": "man", + "rollback": "true", + "usage": "", + "globalignorefile": "/usr/local/etc/npmignore", + "init_author_url": "", + "shell": "/bin/zsh", + "parseable": "", + "shrinkwrap": "true", + "userignorefile": "/Users/brandon/.npmignore", + "cache_max": "null", + "init_author_email": "", + "sign_git_tag": "", + "ignore": "", + "long": "", + "registry": "https://registry.npmjs.org/", + "fetch_retries": "2", + "npat": "", + "message": "%s", + "versions": "", + "globalconfig": "/usr/local/etc/npmrc", + "always_auth": "", + "cache_lock_retries": "10", + "fetch_retry_mintimeout": "10000", + "proprietary_attribs": "true", + "coverage": "", + "json": "", + "pre": "", + "description": "true", + "engine_strict": "", + "https_proxy": "", + "init_module": "/Users/brandon/.npm-init.js", + "userconfig": "/Users/brandon/.npmrc", + "npaturl": "http://npat.npmjs.org/", + "node_version": "v0.10.21", + "user": "", + "editor": "vim", + "save": "", + "tag": "latest", + "global": "", + "optional": "true", + "username": "", + "bin_links": "true", + "force": "", + "searchopts": "", + "depth": "null", + "rebuild_bundle": "true", + "searchsort": "name", + "unicode": "true", + "yes": "", + "fetch_retry_maxtimeout": "60000", + "strict_ssl": "true", + "dev": "", + "fetch_retry_factor": "10", + "group": "20", + "cache_lock_stale": "60000", + "version": "", + "cache_min": "10", + "cache": "/Users/brandon/.npm", + "searchexclude": "", + "color": "true", + "save_optional": "", + "user_agent": "node/v0.10.21 darwin x64", + "cache_lock_wait": "10000", + "production": "", + "save_bundle": "", + "init_version": "0.0.0", + "umask": "18", + "git": "git", + "init_author_name": "", + "onload_script": "", + "tmp": "/var/folders/xf/40fvmk952nz5thhtbgln8vfc0000gn/T/", + "unsafe_perm": "true", + "prefix": "/usr/local", + "link": "" + } +} diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/gyp-mac-tool b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/gyp-mac-tool new file mode 100755 index 0000000..2f5e141 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build/gyp-mac-tool @@ -0,0 +1,224 @@ +#!/usr/bin/env python +# Generated by gyp. Do not edit. +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Utility functions to perform Xcode-style build steps. + +These functions are executed via gyp-mac-tool when using the Makefile generator. +""" + +import fcntl +import os +import plistlib +import re +import shutil +import string +import subprocess +import sys + + +def main(args): + executor = MacTool() + exit_code = executor.Dispatch(args) + if exit_code is not None: + sys.exit(exit_code) + + +class MacTool(object): + """This class performs all the Mac tooling steps. The methods can either be + executed directly, or dispatched from an argument list.""" + + def Dispatch(self, args): + """Dispatches a string command to a method.""" + if len(args) < 1: + raise Exception("Not enough arguments") + + method = "Exec%s" % self._CommandifyName(args[0]) + return getattr(self, method)(*args[1:]) + + def _CommandifyName(self, name_string): + """Transforms a tool name like copy-info-plist to CopyInfoPlist""" + return name_string.title().replace('-', '') + + def ExecCopyBundleResource(self, source, dest): + """Copies a resource file to the bundle/Resources directory, performing any + necessary compilation on each resource.""" + extension = os.path.splitext(source)[1].lower() + if os.path.isdir(source): + # Copy tree. + if os.path.exists(dest): + shutil.rmtree(dest) + shutil.copytree(source, dest) + elif extension == '.xib': + return self._CopyXIBFile(source, dest) + elif extension == '.strings': + self._CopyStringsFile(source, dest) + else: + shutil.copyfile(source, dest) + + def _CopyXIBFile(self, source, dest): + """Compiles a XIB file with ibtool into a binary plist in the bundle.""" + tools_dir = os.environ.get('DEVELOPER_BIN_DIR', '/usr/bin') + args = [os.path.join(tools_dir, 'ibtool'), '--errors', '--warnings', + '--notices', '--output-format', 'human-readable-text', '--compile', + dest, source] + ibtool_section_re = re.compile(r'/\*.*\*/') + ibtool_re = re.compile(r'.*note:.*is clipping its content') + ibtoolout = subprocess.Popen(args, stdout=subprocess.PIPE) + current_section_header = None + for line in ibtoolout.stdout: + if ibtool_section_re.match(line): + current_section_header = line + elif not ibtool_re.match(line): + if current_section_header: + sys.stdout.write(current_section_header) + current_section_header = None + sys.stdout.write(line) + return ibtoolout.returncode + + def _CopyStringsFile(self, source, dest): + """Copies a .strings file using iconv to reconvert the input into UTF-16.""" + input_code = self._DetectInputEncoding(source) or "UTF-8" + + # Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call + # CFPropertyListCreateFromXMLData() behind the scenes; at least it prints + # CFPropertyListCreateFromXMLData(): Old-style plist parser: missing + # semicolon in dictionary. + # on invalid files. Do the same kind of validation. + import CoreFoundation + s = open(source).read() + d = CoreFoundation.CFDataCreate(None, s, len(s)) + _, error = CoreFoundation.CFPropertyListCreateFromXMLData(None, d, 0, None) + if error: + return + + fp = open(dest, 'w') + args = ['/usr/bin/iconv', '--from-code', input_code, '--to-code', + 'UTF-16', source] + subprocess.call(args, stdout=fp) + fp.close() + + def _DetectInputEncoding(self, file_name): + """Reads the first few bytes from file_name and tries to guess the text + encoding. Returns None as a guess if it can't detect it.""" + fp = open(file_name, 'rb') + try: + header = fp.read(3) + except e: + fp.close() + return None + fp.close() + if header.startswith("\xFE\xFF"): + return "UTF-16BE" + elif header.startswith("\xFF\xFE"): + return "UTF-16LE" + elif header.startswith("\xEF\xBB\xBF"): + return "UTF-8" + else: + return None + + def ExecCopyInfoPlist(self, source, dest): + """Copies the |source| Info.plist to the destination directory |dest|.""" + # Read the source Info.plist into memory. + fd = open(source, 'r') + lines = fd.read() + fd.close() + + # Go through all the environment variables and replace them as variables in + # the file. + for key in os.environ: + if key.startswith('_'): + continue + evar = '${%s}' % key + lines = string.replace(lines, evar, os.environ[key]) + + # Write out the file with variables replaced. + fd = open(dest, 'w') + fd.write(lines) + fd.close() + + # Now write out PkgInfo file now that the Info.plist file has been + # "compiled". + self._WritePkgInfo(dest) + + def _WritePkgInfo(self, info_plist): + """This writes the PkgInfo file from the data stored in Info.plist.""" + plist = plistlib.readPlist(info_plist) + if not plist: + return + + # Only create PkgInfo for executable types. + package_type = plist['CFBundlePackageType'] + if package_type != 'APPL': + return + + # The format of PkgInfo is eight characters, representing the bundle type + # and bundle signature, each four characters. If that is missing, four + # '?' characters are used instead. + signature_code = plist.get('CFBundleSignature', '????') + if len(signature_code) != 4: # Wrong length resets everything, too. + signature_code = '?' * 4 + + dest = os.path.join(os.path.dirname(info_plist), 'PkgInfo') + fp = open(dest, 'w') + fp.write('%s%s' % (package_type, signature_code)) + fp.close() + + def ExecFlock(self, lockfile, *cmd_list): + """Emulates the most basic behavior of Linux's flock(1).""" + # Rely on exception handling to report errors. + fd = os.open(lockfile, os.O_RDONLY|os.O_NOCTTY|os.O_CREAT, 0o666) + fcntl.flock(fd, fcntl.LOCK_EX) + return subprocess.call(cmd_list) + + def ExecFilterLibtool(self, *cmd_list): + """Calls libtool and filters out 'libtool: file: foo.o has no symbols'.""" + libtool_re = re.compile(r'^libtool: file: .* has no symbols$') + libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE) + _, err = libtoolout.communicate() + for line in err.splitlines(): + if not libtool_re.match(line): + print >>sys.stderr, line + return libtoolout.returncode + + def ExecPackageFramework(self, framework, version): + """Takes a path to Something.framework and the Current version of that and + sets up all the symlinks.""" + # Find the name of the binary based on the part before the ".framework". + binary = os.path.basename(framework).split('.')[0] + + CURRENT = 'Current' + RESOURCES = 'Resources' + VERSIONS = 'Versions' + + if not os.path.exists(os.path.join(framework, VERSIONS, version, binary)): + # Binary-less frameworks don't seem to contain symlinks (see e.g. + # chromium's out/Debug/org.chromium.Chromium.manifest/ bundle). + return + + # Move into the framework directory to set the symlinks correctly. + pwd = os.getcwd() + os.chdir(framework) + + # Set up the Current version. + self._Relink(version, os.path.join(VERSIONS, CURRENT)) + + # Set up the root symlinks. + self._Relink(os.path.join(VERSIONS, CURRENT, binary), binary) + self._Relink(os.path.join(VERSIONS, CURRENT, RESOURCES), RESOURCES) + + # Back to where we were before! + os.chdir(pwd) + + def _Relink(self, dest, link): + """Creates a symlink to |dest| named |link|. If |link| already exists, + it is overwritten.""" + if os.path.lexists(link): + os.remove(link) + os.symlink(dest, link) + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build_browser.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build_browser.js new file mode 100644 index 0000000..bb80238 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/build_browser.js @@ -0,0 +1,7 @@ +require('one'); + +one('./package.json') + .tie('bson', BSON) + // .exclude('buffer') + .tie('buffer', {}) + .save('./browser_build/bson.js') \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/builderror.log b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/builderror.log new file mode 100644 index 0000000..6b37b2c --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/builderror.log @@ -0,0 +1,2 @@ +gyp http GET http://nodejs.org/dist/v0.10.21/node-v0.10.21.tar.gz +gyp http 200 http://nodejs.org/dist/v0.10.21/node-v0.10.21.tar.gz diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/Makefile b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/Makefile new file mode 100644 index 0000000..435999e --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/Makefile @@ -0,0 +1,28 @@ +NODE = node +name = all +JOBS = 1 + +all: + rm -rf build .lock-wscript bson.node + node-waf configure build + cp -R ./build/Release/bson.node . || true + +all_debug: + rm -rf build .lock-wscript bson.node + node-waf --debug configure build + cp -R ./build/Release/bson.node . || true + +clang: + rm -rf build .lock-wscript bson.node + CXX=clang node-waf configure build + cp -R ./build/Release/bson.node . || true + +clang_debug: + rm -rf build .lock-wscript bson.node + CXX=clang node-waf --debug configure build + cp -R ./build/Release/bson.node . || true + +clean: + rm -rf build .lock-wscript bson.node + +.PHONY: all \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/bson.cc b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/bson.cc new file mode 100644 index 0000000..35c1709 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/bson.cc @@ -0,0 +1,1045 @@ +//=========================================================================== + +#include +#include +#include +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#endif + +#include + +// this and the above block must be around the v8.h header otherwise +// v8 is not happy +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef __sun + #include +#endif + +#include "bson.h" + +using namespace v8; +using namespace node; + +//=========================================================================== + +void DataStream::WriteObjectId(const Handle& object, const Handle& key) +{ + uint16_t buffer[12]; + object->Get(key)->ToString()->Write(buffer, 0, 12); + for(uint32_t i = 0; i < 12; ++i) + { + *p++ = (char) buffer[i]; + } +} + +void ThrowAllocatedStringException(size_t allocationSize, const char* format, ...) +{ + va_list args; + va_start(args, format); + char* string = (char*) malloc(allocationSize); + vsprintf(string, format, args); + va_end(args); + + throw string; +} + +void DataStream::CheckKey(const Local& keyName) +{ + size_t keyLength = keyName->Utf8Length(); + if(keyLength == 0) return; + + // Allocate space for the key, do not need to zero terminate as WriteUtf8 does it + char* keyStringBuffer = (char*) alloca(keyLength + 1); + // Write the key to the allocated buffer + keyName->WriteUtf8(keyStringBuffer); + // Check for the zero terminator + char* terminator = strchr(keyStringBuffer, 0x00); + + // If the location is not at the end of the string we've got an illegal 0x00 byte somewhere + if(terminator != &keyStringBuffer[keyLength]) { + ThrowAllocatedStringException(64+keyLength, "key %s must not contain null bytes", keyStringBuffer); + } + + if(keyStringBuffer[0] == '$') + { + ThrowAllocatedStringException(64+keyLength, "key %s must not start with '$'", keyStringBuffer); + } + + if(strchr(keyStringBuffer, '.') != NULL) + { + ThrowAllocatedStringException(64+keyLength, "key %s must not contain '.'", keyStringBuffer); + } +} + +template void BSONSerializer::SerializeDocument(const Handle& value) +{ + void* documentSize = this->BeginWriteSize(); + Local object = bson->GetSerializeObject(value); + + // Get the object property names + #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6 + Local propertyNames = object->GetPropertyNames(); + #else + Local propertyNames = object->GetOwnPropertyNames(); + #endif + + // Length of the property + int propertyLength = propertyNames->Length(); + for(int i = 0; i < propertyLength; ++i) + { + const Local& propertyName = propertyNames->Get(i)->ToString(); + if(checkKeys) this->CheckKey(propertyName); + + const Local& propertyValue = object->Get(propertyName); + + if(serializeFunctions || !propertyValue->IsFunction()) + { + void* typeLocation = this->BeginWriteType(); + this->WriteString(propertyName); + SerializeValue(typeLocation, propertyValue); + } + } + + this->WriteByte(0); + this->CommitSize(documentSize); +} + +template void BSONSerializer::SerializeArray(const Handle& value) +{ + void* documentSize = this->BeginWriteSize(); + + Local array = Local::Cast(value->ToObject()); + uint32_t arrayLength = array->Length(); + + for(uint32_t i = 0; i < arrayLength; ++i) + { + void* typeLocation = this->BeginWriteType(); + this->WriteUInt32String(i); + SerializeValue(typeLocation, array->Get(i)); + } + + this->WriteByte(0); + this->CommitSize(documentSize); +} + +// This is templated so that we can use this function to both count the number of bytes, and to serialize those bytes. +// The template approach eliminates almost all of the inspection of values unless they're required (eg. string lengths) +// and ensures that there is always consistency between bytes counted and bytes written by design. +template void BSONSerializer::SerializeValue(void* typeLocation, const Handle& value) +{ + if(value->IsNumber()) + { + double doubleValue = value->NumberValue(); + int intValue = (int) doubleValue; + if(intValue == doubleValue) + { + this->CommitType(typeLocation, BSON_TYPE_INT); + this->WriteInt32(intValue); + } + else + { + this->CommitType(typeLocation, BSON_TYPE_NUMBER); + this->WriteDouble(doubleValue); + } + } + else if(value->IsString()) + { + this->CommitType(typeLocation, BSON_TYPE_STRING); + this->WriteLengthPrefixedString(value->ToString()); + } + else if(value->IsBoolean()) + { + this->CommitType(typeLocation, BSON_TYPE_BOOLEAN); + this->WriteBool(value); + } + else if(value->IsArray()) + { + this->CommitType(typeLocation, BSON_TYPE_ARRAY); + SerializeArray(value); + } + else if(value->IsDate()) + { + this->CommitType(typeLocation, BSON_TYPE_DATE); + this->WriteInt64(value); + } + else if(value->IsRegExp()) + { + this->CommitType(typeLocation, BSON_TYPE_REGEXP); + const Handle& regExp = Handle::Cast(value); + + this->WriteString(regExp->GetSource()); + + int flags = regExp->GetFlags(); + if(flags & RegExp::kGlobal) this->WriteByte('s'); + if(flags & RegExp::kIgnoreCase) this->WriteByte('i'); + if(flags & RegExp::kMultiline) this->WriteByte('m'); + this->WriteByte(0); + } + else if(value->IsFunction()) + { + this->CommitType(typeLocation, BSON_TYPE_CODE); + this->WriteLengthPrefixedString(value->ToString()); + } + else if(value->IsObject()) + { + const Local& object = value->ToObject(); + if(object->Has(bson->_bsontypeString)) + { + const Local& constructorString = object->GetConstructorName(); + if(bson->longString->StrictEquals(constructorString)) + { + this->CommitType(typeLocation, BSON_TYPE_LONG); + this->WriteInt32(object, bson->_longLowString); + this->WriteInt32(object, bson->_longHighString); + } + else if(bson->timestampString->StrictEquals(constructorString)) + { + this->CommitType(typeLocation, BSON_TYPE_TIMESTAMP); + this->WriteInt32(object, bson->_longLowString); + this->WriteInt32(object, bson->_longHighString); + } + else if(bson->objectIDString->StrictEquals(constructorString)) + { + this->CommitType(typeLocation, BSON_TYPE_OID); + this->WriteObjectId(object, bson->_objectIDidString); + } + else if(bson->binaryString->StrictEquals(constructorString)) + { + this->CommitType(typeLocation, BSON_TYPE_BINARY); + + uint32_t length = object->Get(bson->_binaryPositionString)->Uint32Value(); + Local bufferObj = object->Get(bson->_binaryBufferString)->ToObject(); + + this->WriteInt32(length); + this->WriteByte(object, bson->_binarySubTypeString); // write subtype + // If type 0x02 write the array length aswell + if(object->Get(bson->_binarySubTypeString)->Int32Value() == 0x02) { + this->WriteInt32(length); + } + // Write the actual data + this->WriteData(Buffer::Data(bufferObj), length); + } + else if(bson->doubleString->StrictEquals(constructorString)) + { + this->CommitType(typeLocation, BSON_TYPE_NUMBER); + this->WriteDouble(object, bson->_doubleValueString); + } + else if(bson->symbolString->StrictEquals(constructorString)) + { + this->CommitType(typeLocation, BSON_TYPE_SYMBOL); + this->WriteLengthPrefixedString(object->Get(bson->_symbolValueString)->ToString()); + } + else if(bson->codeString->StrictEquals(constructorString)) + { + const Local& function = object->Get(bson->_codeCodeString)->ToString(); + const Local& scope = object->Get(bson->_codeScopeString)->ToObject(); + + // For Node < 0.6.X use the GetPropertyNames + #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6 + uint32_t propertyNameLength = scope->GetPropertyNames()->Length(); + #else + uint32_t propertyNameLength = scope->GetOwnPropertyNames()->Length(); + #endif + + if(propertyNameLength > 0) + { + this->CommitType(typeLocation, BSON_TYPE_CODE_W_SCOPE); + void* codeWidthScopeSize = this->BeginWriteSize(); + this->WriteLengthPrefixedString(function->ToString()); + SerializeDocument(scope); + this->CommitSize(codeWidthScopeSize); + } + else + { + this->CommitType(typeLocation, BSON_TYPE_CODE); + this->WriteLengthPrefixedString(function->ToString()); + } + } + else if(bson->dbrefString->StrictEquals(constructorString)) + { + this->CommitType(typeLocation, BSON_TYPE_OBJECT); + + void* dbRefSize = this->BeginWriteSize(); + + void* refType = this->BeginWriteType(); + this->WriteData("$ref", 5); + SerializeValue(refType, object->Get(bson->_dbRefNamespaceString)); + + void* idType = this->BeginWriteType(); + this->WriteData("$id", 4); + SerializeValue(idType, object->Get(bson->_dbRefOidString)); + + const Local& refDbValue = object->Get(bson->_dbRefDbString); + if(!refDbValue->IsUndefined()) + { + void* dbType = this->BeginWriteType(); + this->WriteData("$db", 4); + SerializeValue(dbType, refDbValue); + } + + this->WriteByte(0); + this->CommitSize(dbRefSize); + } + else if(bson->minKeyString->StrictEquals(constructorString)) + { + this->CommitType(typeLocation, BSON_TYPE_MIN_KEY); + } + else if(bson->maxKeyString->StrictEquals(constructorString)) + { + this->CommitType(typeLocation, BSON_TYPE_MAX_KEY); + } + } + else if(Buffer::HasInstance(value)) + { + this->CommitType(typeLocation, BSON_TYPE_BINARY); + + #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3 + Buffer *buffer = ObjectWrap::Unwrap(value->ToObject()); + uint32_t length = object->length(); + #else + uint32_t length = Buffer::Length(value->ToObject()); + #endif + + this->WriteInt32(length); + this->WriteByte(0); + this->WriteData(Buffer::Data(value->ToObject()), length); + } + else + { + this->CommitType(typeLocation, BSON_TYPE_OBJECT); + SerializeDocument(value); + } + } + else if(value->IsNull() || value->IsUndefined()) + { + this->CommitType(typeLocation, BSON_TYPE_NULL); + } +} + +// Data points to start of element list, length is length of entire document including '\0' but excluding initial size +BSONDeserializer::BSONDeserializer(BSON* aBson, char* data, size_t length) +: bson(aBson), + pStart(data), + p(data), + pEnd(data + length - 1) +{ + if(*pEnd != '\0') ThrowAllocatedStringException(64, "Missing end of document marker '\\0'"); +} + +BSONDeserializer::BSONDeserializer(BSONDeserializer& parentSerializer, size_t length) +: bson(parentSerializer.bson), + pStart(parentSerializer.p), + p(parentSerializer.p), + pEnd(parentSerializer.p + length - 1) +{ + parentSerializer.p += length; + if(pEnd > parentSerializer.pEnd) ThrowAllocatedStringException(64, "Child document exceeds parent's bounds"); + if(*pEnd != '\0') ThrowAllocatedStringException(64, "Missing end of document marker '\\0'"); +} + +Local BSONDeserializer::ReadCString() +{ + char* start = p; + while(*p++) { } + return String::New(start, (int32_t) (p-start-1) ); +} + +int32_t BSONDeserializer::ReadRegexOptions() +{ + int32_t options = 0; + for(;;) + { + switch(*p++) + { + case '\0': return options; + case 's': options |= RegExp::kGlobal; break; + case 'i': options |= RegExp::kIgnoreCase; break; + case 'm': options |= RegExp::kMultiline; break; + } + } +} + +uint32_t BSONDeserializer::ReadIntegerString() +{ + uint32_t value = 0; + while(*p) + { + if(*p < '0' || *p > '9') ThrowAllocatedStringException(64, "Invalid key for array"); + value = value * 10 + *p++ - '0'; + } + ++p; + return value; +} + +Local BSONDeserializer::ReadString() +{ + uint32_t length = ReadUInt32(); + char* start = p; + p += length; + return String::New(start, length-1); +} + +Local BSONDeserializer::ReadObjectId() +{ + uint16_t objectId[12]; + for(size_t i = 0; i < 12; ++i) + { + objectId[i] = *reinterpret_cast(p++); + } + return String::New(objectId, 12); +} + +Handle BSONDeserializer::DeserializeDocument(bool promoteLongs) +{ + uint32_t length = ReadUInt32(); + if(length < 5) ThrowAllocatedStringException(64, "Bad BSON: Document is less than 5 bytes"); + + BSONDeserializer documentDeserializer(*this, length-4); + return documentDeserializer.DeserializeDocumentInternal(promoteLongs); +} + +Handle BSONDeserializer::DeserializeDocumentInternal(bool promoteLongs) +{ + Local returnObject = Object::New(); + + while(HasMoreData()) + { + BsonType type = (BsonType) ReadByte(); + const Local& name = ReadCString(); + const Handle& value = DeserializeValue(type, promoteLongs); + returnObject->ForceSet(name, value); + } + if(p != pEnd) ThrowAllocatedStringException(64, "Bad BSON Document: Serialize consumed unexpected number of bytes"); + + // From JavaScript: + // if(object['$id'] != null) object = new DBRef(object['$ref'], object['$id'], object['$db']); + if(returnObject->Has(bson->_dbRefIdRefString)) + { + Local argv[] = { returnObject->Get(bson->_dbRefRefString), returnObject->Get(bson->_dbRefIdRefString), returnObject->Get(bson->_dbRefDbRefString) }; + return bson->dbrefConstructor->NewInstance(3, argv); + } + else + { + return returnObject; + } +} + +Handle BSONDeserializer::DeserializeArray(bool promoteLongs) +{ + uint32_t length = ReadUInt32(); + if(length < 5) ThrowAllocatedStringException(64, "Bad BSON: Array Document is less than 5 bytes"); + + BSONDeserializer documentDeserializer(*this, length-4); + return documentDeserializer.DeserializeArrayInternal(promoteLongs); +} + +Handle BSONDeserializer::DeserializeArrayInternal(bool promoteLongs) +{ + Local returnArray = Array::New(); + + while(HasMoreData()) + { + BsonType type = (BsonType) ReadByte(); + uint32_t index = ReadIntegerString(); + const Handle& value = DeserializeValue(type, promoteLongs); + returnArray->Set(index, value); + } + if(p != pEnd) ThrowAllocatedStringException(64, "Bad BSON Array: Serialize consumed unexpected number of bytes"); + + return returnArray; +} + +Handle BSONDeserializer::DeserializeValue(BsonType type, bool promoteLongs) +{ + switch(type) + { + case BSON_TYPE_STRING: + return ReadString(); + + case BSON_TYPE_INT: + return Integer::New(ReadInt32()); + + case BSON_TYPE_NUMBER: + return Number::New(ReadDouble()); + + case BSON_TYPE_NULL: + return Null(); + + case BSON_TYPE_UNDEFINED: + return Undefined(); + + case BSON_TYPE_TIMESTAMP: + { + int32_t lowBits = ReadInt32(); + int32_t highBits = ReadInt32(); + Local argv[] = { Int32::New(lowBits), Int32::New(highBits) }; + return bson->timestampConstructor->NewInstance(2, argv); + } + + case BSON_TYPE_BOOLEAN: + return (ReadByte() != 0) ? True() : False(); + + case BSON_TYPE_REGEXP: + { + const Local& regex = ReadCString(); + int32_t options = ReadRegexOptions(); + return RegExp::New(regex, (RegExp::Flags) options); + } + + case BSON_TYPE_CODE: + { + const Local& code = ReadString(); + const Local& scope = Object::New(); + Local argv[] = { code, scope }; + return bson->codeConstructor->NewInstance(2, argv); + } + + case BSON_TYPE_CODE_W_SCOPE: + { + ReadUInt32(); + const Local& code = ReadString(); + const Handle& scope = DeserializeDocument(promoteLongs); + Local argv[] = { code, scope->ToObject() }; + return bson->codeConstructor->NewInstance(2, argv); + } + + case BSON_TYPE_OID: + { + Local argv[] = { ReadObjectId() }; + return bson->objectIDConstructor->NewInstance(1, argv); + } + + case BSON_TYPE_BINARY: + { + uint32_t length = ReadUInt32(); + uint32_t subType = ReadByte(); + if(subType == 0x02) { + length = ReadInt32(); + } + + Buffer* buffer = Buffer::New(p, length); + p += length; + + Handle argv[] = { buffer->handle_, Uint32::New(subType) }; + return bson->binaryConstructor->NewInstance(2, argv); + } + + case BSON_TYPE_LONG: + { + // Read 32 bit integers + int32_t lowBits = (int32_t) ReadInt32(); + int32_t highBits = (int32_t) ReadInt32(); + + // Promote long is enabled + if(promoteLongs) { + // If value is < 2^53 and >-2^53 + if((highBits < 0x200000 || (highBits == 0x200000 && lowBits == 0)) && highBits >= -0x200000) { + // Adjust the pointer and read as 64 bit value + p -= 8; + // Read the 64 bit value + int64_t finalValue = (int64_t) ReadInt64(); + return Number::New(finalValue); + } + } + + // Decode the Long value + Local argv[] = { Int32::New(lowBits), Int32::New(highBits) }; + return bson->longConstructor->NewInstance(2, argv); + } + + case BSON_TYPE_DATE: + return Date::New((double) ReadInt64()); + + case BSON_TYPE_ARRAY: + return DeserializeArray(promoteLongs); + + case BSON_TYPE_OBJECT: + return DeserializeDocument(promoteLongs); + + case BSON_TYPE_SYMBOL: + { + const Local& string = ReadString(); + Local argv[] = { string }; + return bson->symbolConstructor->NewInstance(1, argv); + } + + case BSON_TYPE_MIN_KEY: + return bson->minKeyConstructor->NewInstance(); + + case BSON_TYPE_MAX_KEY: + return bson->maxKeyConstructor->NewInstance(); + + default: + ThrowAllocatedStringException(64, "Unhandled BSON Type: %d", type); + } + + return v8::Null(); +} + + +static Handle VException(const char *msg) +{ + HandleScope scope; + return ThrowException(Exception::Error(String::New(msg))); +} + +Persistent BSON::constructor_template; + +BSON::BSON() : ObjectWrap() +{ + // Setup pre-allocated comparision objects + _bsontypeString = Persistent::New(String::New("_bsontype")); + _longLowString = Persistent::New(String::New("low_")); + _longHighString = Persistent::New(String::New("high_")); + _objectIDidString = Persistent::New(String::New("id")); + _binaryPositionString = Persistent::New(String::New("position")); + _binarySubTypeString = Persistent::New(String::New("sub_type")); + _binaryBufferString = Persistent::New(String::New("buffer")); + _doubleValueString = Persistent::New(String::New("value")); + _symbolValueString = Persistent::New(String::New("value")); + _dbRefRefString = Persistent::New(String::New("$ref")); + _dbRefIdRefString = Persistent::New(String::New("$id")); + _dbRefDbRefString = Persistent::New(String::New("$db")); + _dbRefNamespaceString = Persistent::New(String::New("namespace")); + _dbRefDbString = Persistent::New(String::New("db")); + _dbRefOidString = Persistent::New(String::New("oid")); + _codeCodeString = Persistent::New(String::New("code")); + _codeScopeString = Persistent::New(String::New("scope")); + _toBSONString = Persistent::New(String::New("toBSON")); + + longString = Persistent::New(String::New("Long")); + objectIDString = Persistent::New(String::New("ObjectID")); + binaryString = Persistent::New(String::New("Binary")); + codeString = Persistent::New(String::New("Code")); + dbrefString = Persistent::New(String::New("DBRef")); + symbolString = Persistent::New(String::New("Symbol")); + doubleString = Persistent::New(String::New("Double")); + timestampString = Persistent::New(String::New("Timestamp")); + minKeyString = Persistent::New(String::New("MinKey")); + maxKeyString = Persistent::New(String::New("MaxKey")); +} + +void BSON::Initialize(v8::Handle target) +{ + // Grab the scope of the call from Node + HandleScope scope; + // Define a new function template + Local t = FunctionTemplate::New(New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("BSON")); + + // Instance methods + NODE_SET_PROTOTYPE_METHOD(constructor_template, "calculateObjectSize", CalculateObjectSize); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "serialize", BSONSerialize); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "serializeWithBufferAndIndex", SerializeWithBufferAndIndex); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "deserialize", BSONDeserialize); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "deserializeStream", BSONDeserializeStream); + + target->ForceSet(String::NewSymbol("BSON"), constructor_template->GetFunction()); +} + +// Create a new instance of BSON and passing it the existing context +Handle BSON::New(const Arguments &args) +{ + HandleScope scope; + + // Check that we have an array + if(args.Length() == 1 && args[0]->IsArray()) + { + // Cast the array to a local reference + Local array = Local::Cast(args[0]); + + if(array->Length() > 0) + { + // Create a bson object instance and return it + BSON *bson = new BSON(); + + uint32_t foundClassesMask = 0; + + // Iterate over all entries to save the instantiate funtions + for(uint32_t i = 0; i < array->Length(); i++) { + // Let's get a reference to the function + Local func = Local::Cast(array->Get(i)); + Local functionName = func->GetName()->ToString(); + + // Save the functions making them persistant handles (they don't get collected) + if(functionName->StrictEquals(bson->longString)) { + bson->longConstructor = Persistent::New(func); + foundClassesMask |= 1; + } else if(functionName->StrictEquals(bson->objectIDString)) { + bson->objectIDConstructor = Persistent::New(func); + foundClassesMask |= 2; + } else if(functionName->StrictEquals(bson->binaryString)) { + bson->binaryConstructor = Persistent::New(func); + foundClassesMask |= 4; + } else if(functionName->StrictEquals(bson->codeString)) { + bson->codeConstructor = Persistent::New(func); + foundClassesMask |= 8; + } else if(functionName->StrictEquals(bson->dbrefString)) { + bson->dbrefConstructor = Persistent::New(func); + foundClassesMask |= 0x10; + } else if(functionName->StrictEquals(bson->symbolString)) { + bson->symbolConstructor = Persistent::New(func); + foundClassesMask |= 0x20; + } else if(functionName->StrictEquals(bson->doubleString)) { + bson->doubleConstructor = Persistent::New(func); + foundClassesMask |= 0x40; + } else if(functionName->StrictEquals(bson->timestampString)) { + bson->timestampConstructor = Persistent::New(func); + foundClassesMask |= 0x80; + } else if(functionName->StrictEquals(bson->minKeyString)) { + bson->minKeyConstructor = Persistent::New(func); + foundClassesMask |= 0x100; + } else if(functionName->StrictEquals(bson->maxKeyString)) { + bson->maxKeyConstructor = Persistent::New(func); + foundClassesMask |= 0x200; + } + } + + // Check if we have the right number of constructors otherwise throw an error + if(foundClassesMask != 0x3ff) { + delete bson; + return VException("Missing function constructor for either [Long/ObjectID/Binary/Code/DbRef/Symbol/Double/Timestamp/MinKey/MaxKey]"); + } else { + bson->Wrap(args.This()); + return args.This(); + } + } + else + { + return VException("No types passed in"); + } + } + else + { + return VException("Argument passed in must be an array of types"); + } +} + +//------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------ + +Handle BSON::BSONDeserialize(const Arguments &args) +{ + HandleScope scope; + + // Fail if the first argument is not a string or a buffer + if(args.Length() > 1 && !args[0]->IsString() && !Buffer::HasInstance(args[0])) + return VException("First Argument must be a Buffer or String."); + + // Promote longs + bool promoteLongs = true; + + // If we have an options object + if(args.Length() == 2 && args[1]->IsObject()) { + Local options = args[1]->ToObject(); + + if(options->Has(String::New("promoteLongs"))) { + promoteLongs = options->Get(String::New("promoteLongs"))->ToBoolean()->Value(); + } + } + + // Define pointer to data + Local obj = args[0]->ToObject(); + + // Unpack the BSON parser instance + BSON *bson = ObjectWrap::Unwrap(args.This()); + + // If we passed in a buffer, let's unpack it, otherwise let's unpack the string + if(Buffer::HasInstance(obj)) + { +#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3 + Buffer *buffer = ObjectWrap::Unwrap(obj); + char* data = buffer->data(); + size_t length = buffer->length(); +#else + char* data = Buffer::Data(obj); + size_t length = Buffer::Length(obj); +#endif + + // Validate that we have at least 5 bytes + if(length < 5) return VException("corrupt bson message < 5 bytes long"); + + try + { + BSONDeserializer deserializer(bson, data, length); + // deserializer.promoteLongs = promoteLongs; + return deserializer.DeserializeDocument(promoteLongs); + } + catch(char* exception) + { + Handle error = VException(exception); + free(exception); + return error; + } + + } + else + { + // The length of the data for this encoding + ssize_t len = DecodeBytes(args[0], BINARY); + + // Validate that we have at least 5 bytes + if(len < 5) return VException("corrupt bson message < 5 bytes long"); + + // Let's define the buffer size + char* data = (char *)malloc(len); + DecodeWrite(data, len, args[0], BINARY); + + try + { + BSONDeserializer deserializer(bson, data, len); + // deserializer.promoteLongs = promoteLongs; + Handle result = deserializer.DeserializeDocument(promoteLongs); + free(data); + return result; + + } + catch(char* exception) + { + Handle error = VException(exception); + free(exception); + free(data); + return error; + } + } +} + +Local BSON::GetSerializeObject(const Handle& argValue) +{ + Local object = argValue->ToObject(); + if(object->Has(_toBSONString)) + { + const Local& toBSON = object->Get(_toBSONString); + if(!toBSON->IsFunction()) ThrowAllocatedStringException(64, "toBSON is not a function"); + + Local result = Local::Cast(toBSON)->Call(object, 0, NULL); + if(!result->IsObject()) ThrowAllocatedStringException(64, "toBSON function did not return an object"); + return result->ToObject(); + } + else + { + return object; + } +} + +Handle BSON::BSONSerialize(const Arguments &args) +{ + HandleScope scope; + + if(args.Length() == 1 && !args[0]->IsObject()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]"); + if(args.Length() == 2 && !args[0]->IsObject() && !args[1]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]"); + if(args.Length() == 3 && !args[0]->IsObject() && !args[1]->IsBoolean() && !args[2]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]"); + if(args.Length() == 4 && !args[0]->IsObject() && !args[1]->IsBoolean() && !args[2]->IsBoolean() && !args[3]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean] or [object, boolean, boolean, boolean]"); + if(args.Length() > 4) return VException("One, two, tree or four arguments required - [object] or [object, boolean] or [object, boolean, boolean] or [object, boolean, boolean, boolean]"); + + // Check if we have an array as the object + if(args[0]->IsArray()) return VException("Only javascript objects supported"); + + // Unpack the BSON parser instance + BSON *bson = ObjectWrap::Unwrap(args.This()); + + // Calculate the total size of the document in binary form to ensure we only allocate memory once + // With serialize function + bool serializeFunctions = (args.Length() >= 4) && args[3]->BooleanValue(); + + char *serialized_object = NULL; + size_t object_size; + try + { + Local object = bson->GetSerializeObject(args[0]); + + BSONSerializer counter(bson, false, serializeFunctions); + counter.SerializeDocument(object); + object_size = counter.GetSerializeSize(); + + // Allocate the memory needed for the serialization + serialized_object = (char *)malloc(object_size); + + // Check if we have a boolean value + bool checkKeys = args.Length() >= 3 && args[1]->IsBoolean() && args[1]->BooleanValue(); + BSONSerializer data(bson, checkKeys, serializeFunctions, serialized_object); + data.SerializeDocument(object); + } + catch(char *err_msg) + { + free(serialized_object); + Handle error = VException(err_msg); + free(err_msg); + return error; + } + + // If we have 3 arguments + if(args.Length() == 3 || args.Length() == 4) + { + Buffer *buffer = Buffer::New(serialized_object, object_size); + free(serialized_object); + return scope.Close(buffer->handle_); + } + else + { + Local bin_value = Encode(serialized_object, object_size, BINARY)->ToString(); + free(serialized_object); + return bin_value; + } +} + +Handle BSON::CalculateObjectSize(const Arguments &args) +{ + HandleScope scope; + // Ensure we have a valid object + if(args.Length() == 1 && !args[0]->IsObject()) return VException("One argument required - [object]"); + if(args.Length() == 2 && !args[0]->IsObject() && !args[1]->IsBoolean()) return VException("Two arguments required - [object, boolean]"); + if(args.Length() > 3) return VException("One or two arguments required - [object] or [object, boolean]"); + + // Unpack the BSON parser instance + BSON *bson = ObjectWrap::Unwrap(args.This()); + bool serializeFunctions = (args.Length() >= 2) && args[1]->BooleanValue(); + BSONSerializer countSerializer(bson, false, serializeFunctions); + countSerializer.SerializeDocument(args[0]); + + // Return the object size + return scope.Close(Uint32::New((uint32_t) countSerializer.GetSerializeSize())); +} + +Handle BSON::SerializeWithBufferAndIndex(const Arguments &args) +{ + HandleScope scope; + + //BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object, ->, buffer, index) { + // Ensure we have the correct values + if(args.Length() > 5) return VException("Four or five parameters required [object, boolean, Buffer, int] or [object, boolean, Buffer, int, boolean]"); + if(args.Length() == 4 && !args[0]->IsObject() && !args[1]->IsBoolean() && !Buffer::HasInstance(args[2]) && !args[3]->IsUint32()) return VException("Four parameters required [object, boolean, Buffer, int]"); + if(args.Length() == 5 && !args[0]->IsObject() && !args[1]->IsBoolean() && !Buffer::HasInstance(args[2]) && !args[3]->IsUint32() && !args[4]->IsBoolean()) return VException("Four parameters required [object, boolean, Buffer, int, boolean]"); + + uint32_t index; + size_t object_size; + + try + { + BSON *bson = ObjectWrap::Unwrap(args.This()); + + Local obj = args[2]->ToObject(); + char* data = Buffer::Data(obj); + size_t length = Buffer::Length(obj); + + index = args[3]->Uint32Value(); + bool checkKeys = args.Length() >= 4 && args[1]->IsBoolean() && args[1]->BooleanValue(); + bool serializeFunctions = (args.Length() == 5) && args[4]->BooleanValue(); + + BSONSerializer dataSerializer(bson, checkKeys, serializeFunctions, data+index); + dataSerializer.SerializeDocument(bson->GetSerializeObject(args[0])); + object_size = dataSerializer.GetSerializeSize(); + + if(object_size + index > length) return VException("Serious error - overflowed buffer!!"); + } + catch(char *exception) + { + Handle error = VException(exception); + free(exception); + return error; + } + + return scope.Close(Uint32::New((uint32_t) (index + object_size - 1))); +} + +Handle BSON::BSONDeserializeStream(const Arguments &args) +{ + HandleScope scope; + + // At least 3 arguments required + if(args.Length() < 5) return VException("Arguments required (Buffer(data), Number(index in data), Number(number of documents to deserialize), Array(results), Number(index in the array), Object(optional))"); + + // If the number of argumets equals 3 + if(args.Length() >= 5) + { + if(!Buffer::HasInstance(args[0])) return VException("First argument must be Buffer instance"); + if(!args[1]->IsUint32()) return VException("Second argument must be a positive index number"); + if(!args[2]->IsUint32()) return VException("Third argument must be a positive number of documents to deserialize"); + if(!args[3]->IsArray()) return VException("Fourth argument must be an array the size of documents to deserialize"); + if(!args[4]->IsUint32()) return VException("Sixth argument must be a positive index number"); + } + + // If we have 4 arguments + if(args.Length() == 6 && !args[5]->IsObject()) return VException("Fifth argument must be an object with options"); + + // Define pointer to data + Local obj = args[0]->ToObject(); + uint32_t numberOfDocuments = args[2]->Uint32Value(); + uint32_t index = args[1]->Uint32Value(); + uint32_t resultIndex = args[4]->Uint32Value(); + bool promoteLongs = true; + + // Check for the value promoteLongs in the options object + if(args.Length() == 6) { + Local options = args[5]->ToObject(); + + // Check if we have the promoteLong variable + if(options->Has(String::New("promoteLongs"))) { + promoteLongs = options->Get(String::New("promoteLongs"))->ToBoolean()->Value(); + } + } + + // Unpack the BSON parser instance + BSON *bson = ObjectWrap::Unwrap(args.This()); + + // Unpack the buffer variable +#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3 + Buffer *buffer = ObjectWrap::Unwrap(obj); + char* data = buffer->data(); + size_t length = buffer->length(); +#else + char* data = Buffer::Data(obj); + size_t length = Buffer::Length(obj); +#endif + + // Fetch the documents + Local documents = args[3]->ToObject(); + + BSONDeserializer deserializer(bson, data+index, length-index); + for(uint32_t i = 0; i < numberOfDocuments; i++) + { + try + { + documents->Set(i + resultIndex, deserializer.DeserializeDocument(promoteLongs)); + } + catch (char* exception) + { + Handle error = VException(exception); + free(exception); + return error; + } + } + + // Return new index of parsing + return scope.Close(Uint32::New((uint32_t) (index + deserializer.GetSerializeSize()))); +} + +// Exporting function +extern "C" void init(Handle target) +{ + HandleScope scope; + BSON::Initialize(target); +} + +NODE_MODULE(bson, BSON::Initialize); diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/bson.h b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/bson.h new file mode 100644 index 0000000..3638f82 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/bson.h @@ -0,0 +1,277 @@ +//=========================================================================== + +#ifndef BSON_H_ +#define BSON_H_ + +//=========================================================================== + +#ifdef __arm__ +#define USE_MISALIGNED_MEMORY_ACCESS 0 +#else +#define USE_MISALIGNED_MEMORY_ACCESS 1 +#endif + +#include +#include +#include + +using namespace v8; +using namespace node; + +//=========================================================================== + +enum BsonType +{ + BSON_TYPE_NUMBER = 1, + BSON_TYPE_STRING = 2, + BSON_TYPE_OBJECT = 3, + BSON_TYPE_ARRAY = 4, + BSON_TYPE_BINARY = 5, + BSON_TYPE_UNDEFINED = 6, + BSON_TYPE_OID = 7, + BSON_TYPE_BOOLEAN = 8, + BSON_TYPE_DATE = 9, + BSON_TYPE_NULL = 10, + BSON_TYPE_REGEXP = 11, + BSON_TYPE_CODE = 13, + BSON_TYPE_SYMBOL = 14, + BSON_TYPE_CODE_W_SCOPE = 15, + BSON_TYPE_INT = 16, + BSON_TYPE_TIMESTAMP = 17, + BSON_TYPE_LONG = 18, + BSON_TYPE_MAX_KEY = 0x7f, + BSON_TYPE_MIN_KEY = 0xff +}; + +//=========================================================================== + +template class BSONSerializer; + +class BSON : public ObjectWrap { +public: + BSON(); + ~BSON() {} + + static void Initialize(Handle target); + static Handle BSONDeserializeStream(const Arguments &args); + + // JS based objects + static Handle BSONSerialize(const Arguments &args); + static Handle BSONDeserialize(const Arguments &args); + + // Calculate size of function + static Handle CalculateObjectSize(const Arguments &args); + static Handle SerializeWithBufferAndIndex(const Arguments &args); + + // Constructor used for creating new BSON objects from C++ + static Persistent constructor_template; + +private: + static Handle New(const Arguments &args); + static Handle deserialize(BSON *bson, char *data, uint32_t dataLength, uint32_t startIndex, bool is_array_item); + + // BSON type instantiate functions + Persistent longConstructor; + Persistent objectIDConstructor; + Persistent binaryConstructor; + Persistent codeConstructor; + Persistent dbrefConstructor; + Persistent symbolConstructor; + Persistent doubleConstructor; + Persistent timestampConstructor; + Persistent minKeyConstructor; + Persistent maxKeyConstructor; + + // Equality Objects + Persistent longString; + Persistent objectIDString; + Persistent binaryString; + Persistent codeString; + Persistent dbrefString; + Persistent symbolString; + Persistent doubleString; + Persistent timestampString; + Persistent minKeyString; + Persistent maxKeyString; + + // Equality speed up comparison objects + Persistent _bsontypeString; + Persistent _longLowString; + Persistent _longHighString; + Persistent _objectIDidString; + Persistent _binaryPositionString; + Persistent _binarySubTypeString; + Persistent _binaryBufferString; + Persistent _doubleValueString; + Persistent _symbolValueString; + + Persistent _dbRefRefString; + Persistent _dbRefIdRefString; + Persistent _dbRefDbRefString; + Persistent _dbRefNamespaceString; + Persistent _dbRefDbString; + Persistent _dbRefOidString; + + Persistent _codeCodeString; + Persistent _codeScopeString; + Persistent _toBSONString; + + Local GetSerializeObject(const Handle& object); + + template friend class BSONSerializer; + friend class BSONDeserializer; +}; + +//=========================================================================== + +class CountStream +{ +public: + CountStream() : count(0) { } + + void WriteByte(int value) { ++count; } + void WriteByte(const Handle&, const Handle&) { ++count; } + void WriteBool(const Handle& value) { ++count; } + void WriteInt32(int32_t value) { count += 4; } + void WriteInt32(const Handle& value) { count += 4; } + void WriteInt32(const Handle& object, const Handle& key) { count += 4; } + void WriteInt64(int64_t value) { count += 8; } + void WriteInt64(const Handle& value) { count += 8; } + void WriteDouble(double value) { count += 8; } + void WriteDouble(const Handle& value) { count += 8; } + void WriteDouble(const Handle&, const Handle&) { count += 8; } + void WriteUInt32String(uint32_t name) { char buffer[32]; count += sprintf(buffer, "%u", name) + 1; } + void WriteLengthPrefixedString(const Local& value) { count += value->Utf8Length()+5; } + void WriteObjectId(const Handle& object, const Handle& key) { count += 12; } + void WriteString(const Local& value) { count += value->Utf8Length() + 1; } // This returns the number of bytes exclusive of the NULL terminator + void WriteData(const char* data, size_t length) { count += length; } + + void* BeginWriteType() { ++count; return NULL; } + void CommitType(void*, BsonType) { } + void* BeginWriteSize() { count += 4; return NULL; } + void CommitSize(void*) { } + + size_t GetSerializeSize() const { return count; } + + // Do nothing. CheckKey is implemented for DataStream + void CheckKey(const Local&) { } + +private: + size_t count; +}; + +class DataStream +{ +public: + DataStream(char* aDestinationBuffer) : destinationBuffer(aDestinationBuffer), p(aDestinationBuffer) { } + + void WriteByte(int value) { *p++ = value; } + void WriteByte(const Handle& object, const Handle& key) { *p++ = object->Get(key)->Int32Value(); } +#if USE_MISALIGNED_MEMORY_ACCESS + void WriteInt32(int32_t value) { *reinterpret_cast(p) = value; p += 4; } + void WriteInt64(int64_t value) { *reinterpret_cast(p) = value; p += 8; } + void WriteDouble(double value) { *reinterpret_cast(p) = value; p += 8; } +#else + void WriteInt32(int32_t value) { memcpy(p, &value, 4); p += 4; } + void WriteInt64(int64_t value) { memcpy(p, &value, 8); p += 8; } + void WriteDouble(double value) { memcpy(p, &value, 8); p += 8; } +#endif + void WriteBool(const Handle& value) { WriteByte(value->BooleanValue() ? 1 : 0); } + void WriteInt32(const Handle& value) { WriteInt32(value->Int32Value()); } + void WriteInt32(const Handle& object, const Handle& key) { WriteInt32(object->Get(key)); } + void WriteInt64(const Handle& value) { WriteInt64(value->IntegerValue()); } + void WriteDouble(const Handle& value) { WriteDouble(value->NumberValue()); } + void WriteDouble(const Handle& object, const Handle& key) { WriteDouble(object->Get(key)); } + void WriteUInt32String(uint32_t name) { p += sprintf(p, "%u", name) + 1; } + void WriteLengthPrefixedString(const Local& value) { WriteInt32(value->Utf8Length()+1); WriteString(value); } + void WriteObjectId(const Handle& object, const Handle& key); + void WriteString(const Local& value) { p += value->WriteUtf8(p); } // This returns the number of bytes inclusive of the NULL terminator. + void WriteData(const char* data, size_t length) { memcpy(p, data, length); p += length; } + + void* BeginWriteType() { void* returnValue = p; p++; return returnValue; } + void CommitType(void* beginPoint, BsonType value) { *reinterpret_cast(beginPoint) = value; } + void* BeginWriteSize() { void* returnValue = p; p += 4; return returnValue; } + +#if USE_MISALIGNED_MEMORY_ACCESS + void CommitSize(void* beginPoint) { *reinterpret_cast(beginPoint) = (int32_t) (p - (char*) beginPoint); } +#else + void CommitSize(void* beginPoint) { int32_t value = (int32_t) (p - (char*) beginPoint); memcpy(beginPoint, &value, 4); } +#endif + + size_t GetSerializeSize() const { return p - destinationBuffer; } + + void CheckKey(const Local& keyName); + +protected: + char *const destinationBuffer; // base, never changes + char* p; // cursor into buffer +}; + +template class BSONSerializer : public T +{ +private: + typedef T Inherited; + +public: + BSONSerializer(BSON* aBson, bool aCheckKeys, bool aSerializeFunctions) : Inherited(), checkKeys(aCheckKeys), serializeFunctions(aSerializeFunctions), bson(aBson) { } + BSONSerializer(BSON* aBson, bool aCheckKeys, bool aSerializeFunctions, char* parentParam) : Inherited(parentParam), checkKeys(aCheckKeys), serializeFunctions(aSerializeFunctions), bson(aBson) { } + + void SerializeDocument(const Handle& value); + void SerializeArray(const Handle& value); + void SerializeValue(void* typeLocation, const Handle& value); + +private: + bool checkKeys; + bool serializeFunctions; + BSON* bson; +}; + +//=========================================================================== + +class BSONDeserializer +{ +public: + BSONDeserializer(BSON* aBson, char* data, size_t length); + BSONDeserializer(BSONDeserializer& parentSerializer, size_t length); + + Handle DeserializeDocument(bool promoteLongs); + + bool HasMoreData() const { return p < pEnd; } + Local ReadCString(); + uint32_t ReadIntegerString(); + int32_t ReadRegexOptions(); + Local ReadString(); + Local ReadObjectId(); + + unsigned char ReadByte() { return *reinterpret_cast(p++); } +#if USE_MISALIGNED_MEMORY_ACCESS + int32_t ReadInt32() { int32_t returnValue = *reinterpret_cast(p); p += 4; return returnValue; } + uint32_t ReadUInt32() { uint32_t returnValue = *reinterpret_cast(p); p += 4; return returnValue; } + int64_t ReadInt64() { int64_t returnValue = *reinterpret_cast(p); p += 8; return returnValue; } + double ReadDouble() { double returnValue = *reinterpret_cast(p); p += 8; return returnValue; } +#else + int32_t ReadInt32() { int32_t returnValue; memcpy(&returnValue, p, 4); p += 4; return returnValue; } + uint32_t ReadUInt32() { uint32_t returnValue; memcpy(&returnValue, p, 4); p += 4; return returnValue; } + int64_t ReadInt64() { int64_t returnValue; memcpy(&returnValue, p, 8); p += 8; return returnValue; } + double ReadDouble() { double returnValue; memcpy(&returnValue, p, 8); p += 8; return returnValue; } +#endif + + size_t GetSerializeSize() const { return p - pStart; } + +private: + Handle DeserializeArray(bool promoteLongs); + Handle DeserializeValue(BsonType type, bool promoteLongs); + Handle DeserializeDocumentInternal(bool promoteLongs); + Handle DeserializeArrayInternal(bool promoteLongs); + + BSON* bson; + char* const pStart; + char* p; + char* const pEnd; +}; + +//=========================================================================== + +#endif // BSON_H_ + +//=========================================================================== diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/index.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/index.js new file mode 100644 index 0000000..85e243c --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/index.js @@ -0,0 +1,30 @@ +var bson = null; + +// Load the precompiled win32 binary +if(process.platform == "win32" && process.arch == "x64") { + bson = require('./win32/x64/bson'); +} else if(process.platform == "win32" && process.arch == "ia32") { + bson = require('./win32/ia32/bson'); +} else { + bson = require('../build/Release/bson'); +} + +exports.BSON = bson.BSON; +exports.Long = require('../lib/bson/long').Long; +exports.ObjectID = require('../lib/bson/objectid').ObjectID; +exports.DBRef = require('../lib/bson/db_ref').DBRef; +exports.Code = require('../lib/bson/code').Code; +exports.Timestamp = require('../lib/bson/timestamp').Timestamp; +exports.Binary = require('../lib/bson/binary').Binary; +exports.Double = require('../lib/bson/double').Double; +exports.MaxKey = require('../lib/bson/max_key').MaxKey; +exports.MinKey = require('../lib/bson/min_key').MinKey; +exports.Symbol = require('../lib/bson/symbol').Symbol; + +// Just add constants tot he Native BSON parser +exports.BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0; +exports.BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1; +exports.BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2; +exports.BSON.BSON_BINARY_SUBTYPE_UUID = 3; +exports.BSON.BSON_BINARY_SUBTYPE_MD5 = 4; +exports.BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128; diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/win32/ia32/bson.node b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/win32/ia32/bson.node new file mode 100644 index 0000000..7f54835 Binary files /dev/null and b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/win32/ia32/bson.node differ diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/win32/x64/bson.node b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/win32/x64/bson.node new file mode 100644 index 0000000..f01f8be Binary files /dev/null and b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/win32/x64/bson.node differ diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/wscript b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/wscript new file mode 100644 index 0000000..40f5317 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/ext/wscript @@ -0,0 +1,39 @@ +import Options +from os import unlink, symlink, popen +from os.path import exists + +srcdir = "." +blddir = "build" +VERSION = "0.1.0" + +def set_options(opt): + opt.tool_options("compiler_cxx") + opt.add_option( '--debug' + , action='store_true' + , default=False + , help='Build debug variant [Default: False]' + , dest='debug' + ) + +def configure(conf): + conf.check_tool("compiler_cxx") + conf.check_tool("node_addon") + conf.env.append_value('CXXFLAGS', ['-O3', '-funroll-loops']) + + # conf.env.append_value('CXXFLAGS', ['-DDEBUG', '-g', '-O0', '-Wall', '-Wextra']) + # conf.check(lib='node', libpath=['/usr/lib', '/usr/local/lib'], uselib_store='NODE') + +def build(bld): + obj = bld.new_task_gen("cxx", "shlib", "node_addon") + obj.target = "bson" + obj.source = ["bson.cc"] + # obj.uselib = "NODE" + +def shutdown(): + # HACK to get compress.node out of build directory. + # better way to do this? + if Options.commands['clean']: + if exists('bson.node'): unlink('bson.node') + else: + if exists('build/default/bson.node') and not exists('bson.node'): + symlink('build/default/bson.node', 'bson.node') diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/binary.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/binary.js new file mode 100644 index 0000000..82d4d04 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/binary.js @@ -0,0 +1,339 @@ +/** + * Module dependencies. + */ +if(typeof window === 'undefined') { + var Buffer = require('buffer').Buffer; // TODO just use global Buffer +} + +// Binary default subtype +var BSON_BINARY_SUBTYPE_DEFAULT = 0; + +/** + * @ignore + * @api private + */ +var writeStringToArray = function(data) { + // Create a buffer + var buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(data.length)) : new Array(data.length); + // Write the content to the buffer + for(var i = 0; i < data.length; i++) { + buffer[i] = data.charCodeAt(i); + } + // Write the string to the buffer + return buffer; +} + +/** + * Convert Array ot Uint8Array to Binary String + * + * @ignore + * @api private + */ +var convertArraytoUtf8BinaryString = function(byteArray, startIndex, endIndex) { + var result = ""; + for(var i = startIndex; i < endIndex; i++) { + result = result + String.fromCharCode(byteArray[i]); + } + return result; +}; + +/** + * A class representation of the BSON Binary type. + * + * Sub types + * - **BSON.BSON_BINARY_SUBTYPE_DEFAULT**, default BSON type. + * - **BSON.BSON_BINARY_SUBTYPE_FUNCTION**, BSON function type. + * - **BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY**, BSON byte array type. + * - **BSON.BSON_BINARY_SUBTYPE_UUID**, BSON uuid type. + * - **BSON.BSON_BINARY_SUBTYPE_MD5**, BSON md5 type. + * - **BSON.BSON_BINARY_SUBTYPE_USER_DEFINED**, BSON user defined type. + * + * @class Represents the Binary BSON type. + * @param {Buffer} buffer a buffer object containing the binary data. + * @param {Number} [subType] the option binary type. + * @return {Grid} + */ +function Binary(buffer, subType) { + if(!(this instanceof Binary)) return new Binary(buffer, subType); + + this._bsontype = 'Binary'; + + if(buffer instanceof Number) { + this.sub_type = buffer; + this.position = 0; + } else { + this.sub_type = subType == null ? BSON_BINARY_SUBTYPE_DEFAULT : subType; + this.position = 0; + } + + if(buffer != null && !(buffer instanceof Number)) { + // Only accept Buffer, Uint8Array or Arrays + if(typeof buffer == 'string') { + // Different ways of writing the length of the string for the different types + if(typeof Buffer != 'undefined') { + this.buffer = new Buffer(buffer); + } else if(typeof Uint8Array != 'undefined' || (Object.prototype.toString.call(buffer) == '[object Array]')) { + this.buffer = writeStringToArray(buffer); + } else { + throw new Error("only String, Buffer, Uint8Array or Array accepted"); + } + } else { + this.buffer = buffer; + } + this.position = buffer.length; + } else { + if(typeof Buffer != 'undefined') { + this.buffer = new Buffer(Binary.BUFFER_SIZE); + } else if(typeof Uint8Array != 'undefined'){ + this.buffer = new Uint8Array(new ArrayBuffer(Binary.BUFFER_SIZE)); + } else { + this.buffer = new Array(Binary.BUFFER_SIZE); + } + // Set position to start of buffer + this.position = 0; + } +}; + +/** + * Updates this binary with byte_value. + * + * @param {Character} byte_value a single byte we wish to write. + * @api public + */ +Binary.prototype.put = function put(byte_value) { + // If it's a string and a has more than one character throw an error + if(byte_value['length'] != null && typeof byte_value != 'number' && byte_value.length != 1) throw new Error("only accepts single character String, Uint8Array or Array"); + if(typeof byte_value != 'number' && byte_value < 0 || byte_value > 255) throw new Error("only accepts number in a valid unsigned byte range 0-255"); + + // Decode the byte value once + var decoded_byte = null; + if(typeof byte_value == 'string') { + decoded_byte = byte_value.charCodeAt(0); + } else if(byte_value['length'] != null) { + decoded_byte = byte_value[0]; + } else { + decoded_byte = byte_value; + } + + if(this.buffer.length > this.position) { + this.buffer[this.position++] = decoded_byte; + } else { + if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) { + // Create additional overflow buffer + var buffer = new Buffer(Binary.BUFFER_SIZE + this.buffer.length); + // Combine the two buffers together + this.buffer.copy(buffer, 0, 0, this.buffer.length); + this.buffer = buffer; + this.buffer[this.position++] = decoded_byte; + } else { + var buffer = null; + // Create a new buffer (typed or normal array) + if(Object.prototype.toString.call(this.buffer) == '[object Uint8Array]') { + buffer = new Uint8Array(new ArrayBuffer(Binary.BUFFER_SIZE + this.buffer.length)); + } else { + buffer = new Array(Binary.BUFFER_SIZE + this.buffer.length); + } + + // We need to copy all the content to the new array + for(var i = 0; i < this.buffer.length; i++) { + buffer[i] = this.buffer[i]; + } + + // Reassign the buffer + this.buffer = buffer; + // Write the byte + this.buffer[this.position++] = decoded_byte; + } + } +}; + +/** + * Writes a buffer or string to the binary. + * + * @param {Buffer|String} string a string or buffer to be written to the Binary BSON object. + * @param {Number} offset specify the binary of where to write the content. + * @api public + */ +Binary.prototype.write = function write(string, offset) { + offset = typeof offset == 'number' ? offset : this.position; + + // If the buffer is to small let's extend the buffer + if(this.buffer.length < offset + string.length) { + var buffer = null; + // If we are in node.js + if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) { + buffer = new Buffer(this.buffer.length + string.length); + this.buffer.copy(buffer, 0, 0, this.buffer.length); + } else if(Object.prototype.toString.call(this.buffer) == '[object Uint8Array]') { + // Create a new buffer + buffer = new Uint8Array(new ArrayBuffer(this.buffer.length + string.length)) + // Copy the content + for(var i = 0; i < this.position; i++) { + buffer[i] = this.buffer[i]; + } + } + + // Assign the new buffer + this.buffer = buffer; + } + + if(typeof Buffer != 'undefined' && Buffer.isBuffer(string) && Buffer.isBuffer(this.buffer)) { + string.copy(this.buffer, offset, 0, string.length); + this.position = (offset + string.length) > this.position ? (offset + string.length) : this.position; + // offset = string.length + } else if(typeof Buffer != 'undefined' && typeof string == 'string' && Buffer.isBuffer(this.buffer)) { + this.buffer.write(string, 'binary', offset); + this.position = (offset + string.length) > this.position ? (offset + string.length) : this.position; + // offset = string.length; + } else if(Object.prototype.toString.call(string) == '[object Uint8Array]' + || Object.prototype.toString.call(string) == '[object Array]' && typeof string != 'string') { + for(var i = 0; i < string.length; i++) { + this.buffer[offset++] = string[i]; + } + + this.position = offset > this.position ? offset : this.position; + } else if(typeof string == 'string') { + for(var i = 0; i < string.length; i++) { + this.buffer[offset++] = string.charCodeAt(i); + } + + this.position = offset > this.position ? offset : this.position; + } +}; + +/** + * Reads **length** bytes starting at **position**. + * + * @param {Number} position read from the given position in the Binary. + * @param {Number} length the number of bytes to read. + * @return {Buffer} + * @api public + */ +Binary.prototype.read = function read(position, length) { + length = length && length > 0 + ? length + : this.position; + + // Let's return the data based on the type we have + if(this.buffer['slice']) { + return this.buffer.slice(position, position + length); + } else { + // Create a buffer to keep the result + var buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(length)) : new Array(length); + for(var i = 0; i < length; i++) { + buffer[i] = this.buffer[position++]; + } + } + // Return the buffer + return buffer; +}; + +/** + * Returns the value of this binary as a string. + * + * @return {String} + * @api public + */ +Binary.prototype.value = function value(asRaw) { + asRaw = asRaw == null ? false : asRaw; + + // If it's a node.js buffer object + if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) { + return asRaw ? this.buffer.slice(0, this.position) : this.buffer.toString('binary', 0, this.position); + } else { + if(asRaw) { + // we support the slice command use it + if(this.buffer['slice'] != null) { + return this.buffer.slice(0, this.position); + } else { + // Create a new buffer to copy content to + var newBuffer = Object.prototype.toString.call(this.buffer) == '[object Uint8Array]' ? new Uint8Array(new ArrayBuffer(this.position)) : new Array(this.position); + // Copy content + for(var i = 0; i < this.position; i++) { + newBuffer[i] = this.buffer[i]; + } + // Return the buffer + return newBuffer; + } + } else { + return convertArraytoUtf8BinaryString(this.buffer, 0, this.position); + } + } +}; + +/** + * Length. + * + * @return {Number} the length of the binary. + * @api public + */ +Binary.prototype.length = function length() { + return this.position; +}; + +/** + * @ignore + * @api private + */ +Binary.prototype.toJSON = function() { + return this.buffer != null ? this.buffer.toString('base64') : ''; +} + +/** + * @ignore + * @api private + */ +Binary.prototype.toString = function(format) { + return this.buffer != null ? this.buffer.slice(0, this.position).toString(format) : ''; +} + +Binary.BUFFER_SIZE = 256; + +/** + * Default BSON type + * + * @classconstant SUBTYPE_DEFAULT + **/ +Binary.SUBTYPE_DEFAULT = 0; +/** + * Function BSON type + * + * @classconstant SUBTYPE_DEFAULT + **/ +Binary.SUBTYPE_FUNCTION = 1; +/** + * Byte Array BSON type + * + * @classconstant SUBTYPE_DEFAULT + **/ +Binary.SUBTYPE_BYTE_ARRAY = 2; +/** + * OLD UUID BSON type + * + * @classconstant SUBTYPE_DEFAULT + **/ +Binary.SUBTYPE_UUID_OLD = 3; +/** + * UUID BSON type + * + * @classconstant SUBTYPE_DEFAULT + **/ +Binary.SUBTYPE_UUID = 4; +/** + * MD5 BSON type + * + * @classconstant SUBTYPE_DEFAULT + **/ +Binary.SUBTYPE_MD5 = 5; +/** + * User BSON type + * + * @classconstant SUBTYPE_DEFAULT + **/ +Binary.SUBTYPE_USER_DEFINED = 128; + +/** + * Expose. + */ +exports.Binary = Binary; + diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/binary_parser.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/binary_parser.js new file mode 100644 index 0000000..d2fc811 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/binary_parser.js @@ -0,0 +1,385 @@ +/** + * Binary Parser. + * Jonas Raoni Soares Silva + * http://jsfromhell.com/classes/binary-parser [v1.0] + */ +var chr = String.fromCharCode; + +var maxBits = []; +for (var i = 0; i < 64; i++) { + maxBits[i] = Math.pow(2, i); +} + +function BinaryParser (bigEndian, allowExceptions) { + if(!(this instanceof BinaryParser)) return new BinaryParser(bigEndian, allowExceptions); + + this.bigEndian = bigEndian; + this.allowExceptions = allowExceptions; +}; + +BinaryParser.warn = function warn (msg) { + if (this.allowExceptions) { + throw new Error(msg); + } + + return 1; +}; + +BinaryParser.decodeFloat = function decodeFloat (data, precisionBits, exponentBits) { + var b = new this.Buffer(this.bigEndian, data); + + b.checkBuffer(precisionBits + exponentBits + 1); + + var bias = maxBits[exponentBits - 1] - 1 + , signal = b.readBits(precisionBits + exponentBits, 1) + , exponent = b.readBits(precisionBits, exponentBits) + , significand = 0 + , divisor = 2 + , curByte = b.buffer.length + (-precisionBits >> 3) - 1; + + do { + for (var byteValue = b.buffer[ ++curByte ], startBit = precisionBits % 8 || 8, mask = 1 << startBit; mask >>= 1; ( byteValue & mask ) && ( significand += 1 / divisor ), divisor *= 2 ); + } while (precisionBits -= startBit); + + return exponent == ( bias << 1 ) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity : ( 1 + signal * -2 ) * ( exponent || significand ? !exponent ? Math.pow( 2, -bias + 1 ) * significand : Math.pow( 2, exponent - bias ) * ( 1 + significand ) : 0 ); +}; + +BinaryParser.decodeInt = function decodeInt (data, bits, signed, forceBigEndian) { + var b = new this.Buffer(this.bigEndian || forceBigEndian, data) + , x = b.readBits(0, bits) + , max = maxBits[bits]; //max = Math.pow( 2, bits ); + + return signed && x >= max / 2 + ? x - max + : x; +}; + +BinaryParser.encodeFloat = function encodeFloat (data, precisionBits, exponentBits) { + var bias = maxBits[exponentBits - 1] - 1 + , minExp = -bias + 1 + , maxExp = bias + , minUnnormExp = minExp - precisionBits + , n = parseFloat(data) + , status = isNaN(n) || n == -Infinity || n == +Infinity ? n : 0 + , exp = 0 + , len = 2 * bias + 1 + precisionBits + 3 + , bin = new Array(len) + , signal = (n = status !== 0 ? 0 : n) < 0 + , intPart = Math.floor(n = Math.abs(n)) + , floatPart = n - intPart + , lastBit + , rounded + , result + , i + , j; + + for (i = len; i; bin[--i] = 0); + + for (i = bias + 2; intPart && i; bin[--i] = intPart % 2, intPart = Math.floor(intPart / 2)); + + for (i = bias + 1; floatPart > 0 && i; (bin[++i] = ((floatPart *= 2) >= 1) - 0 ) && --floatPart); + + for (i = -1; ++i < len && !bin[i];); + + if (bin[(lastBit = precisionBits - 1 + (i = (exp = bias + 1 - i) >= minExp && exp <= maxExp ? i + 1 : bias + 1 - (exp = minExp - 1))) + 1]) { + if (!(rounded = bin[lastBit])) { + for (j = lastBit + 2; !rounded && j < len; rounded = bin[j++]); + } + + for (j = lastBit + 1; rounded && --j >= 0; (bin[j] = !bin[j] - 0) && (rounded = 0)); + } + + for (i = i - 2 < 0 ? -1 : i - 3; ++i < len && !bin[i];); + + if ((exp = bias + 1 - i) >= minExp && exp <= maxExp) { + ++i; + } else if (exp < minExp) { + exp != bias + 1 - len && exp < minUnnormExp && this.warn("encodeFloat::float underflow"); + i = bias + 1 - (exp = minExp - 1); + } + + if (intPart || status !== 0) { + this.warn(intPart ? "encodeFloat::float overflow" : "encodeFloat::" + status); + exp = maxExp + 1; + i = bias + 2; + + if (status == -Infinity) { + signal = 1; + } else if (isNaN(status)) { + bin[i] = 1; + } + } + + for (n = Math.abs(exp + bias), j = exponentBits + 1, result = ""; --j; result = (n % 2) + result, n = n >>= 1); + + for (n = 0, j = 0, i = (result = (signal ? "1" : "0") + result + bin.slice(i, i + precisionBits).join("")).length, r = []; i; j = (j + 1) % 8) { + n += (1 << j) * result.charAt(--i); + if (j == 7) { + r[r.length] = String.fromCharCode(n); + n = 0; + } + } + + r[r.length] = n + ? String.fromCharCode(n) + : ""; + + return (this.bigEndian ? r.reverse() : r).join(""); +}; + +BinaryParser.encodeInt = function encodeInt (data, bits, signed, forceBigEndian) { + var max = maxBits[bits]; + + if (data >= max || data < -(max / 2)) { + this.warn("encodeInt::overflow"); + data = 0; + } + + if (data < 0) { + data += max; + } + + for (var r = []; data; r[r.length] = String.fromCharCode(data % 256), data = Math.floor(data / 256)); + + for (bits = -(-bits >> 3) - r.length; bits--; r[r.length] = "\0"); + + return ((this.bigEndian || forceBigEndian) ? r.reverse() : r).join(""); +}; + +BinaryParser.toSmall = function( data ){ return this.decodeInt( data, 8, true ); }; +BinaryParser.fromSmall = function( data ){ return this.encodeInt( data, 8, true ); }; +BinaryParser.toByte = function( data ){ return this.decodeInt( data, 8, false ); }; +BinaryParser.fromByte = function( data ){ return this.encodeInt( data, 8, false ); }; +BinaryParser.toShort = function( data ){ return this.decodeInt( data, 16, true ); }; +BinaryParser.fromShort = function( data ){ return this.encodeInt( data, 16, true ); }; +BinaryParser.toWord = function( data ){ return this.decodeInt( data, 16, false ); }; +BinaryParser.fromWord = function( data ){ return this.encodeInt( data, 16, false ); }; +BinaryParser.toInt = function( data ){ return this.decodeInt( data, 32, true ); }; +BinaryParser.fromInt = function( data ){ return this.encodeInt( data, 32, true ); }; +BinaryParser.toLong = function( data ){ return this.decodeInt( data, 64, true ); }; +BinaryParser.fromLong = function( data ){ return this.encodeInt( data, 64, true ); }; +BinaryParser.toDWord = function( data ){ return this.decodeInt( data, 32, false ); }; +BinaryParser.fromDWord = function( data ){ return this.encodeInt( data, 32, false ); }; +BinaryParser.toQWord = function( data ){ return this.decodeInt( data, 64, true ); }; +BinaryParser.fromQWord = function( data ){ return this.encodeInt( data, 64, true ); }; +BinaryParser.toFloat = function( data ){ return this.decodeFloat( data, 23, 8 ); }; +BinaryParser.fromFloat = function( data ){ return this.encodeFloat( data, 23, 8 ); }; +BinaryParser.toDouble = function( data ){ return this.decodeFloat( data, 52, 11 ); }; +BinaryParser.fromDouble = function( data ){ return this.encodeFloat( data, 52, 11 ); }; + +// Factor out the encode so it can be shared by add_header and push_int32 +BinaryParser.encode_int32 = function encode_int32 (number, asArray) { + var a, b, c, d, unsigned; + unsigned = (number < 0) ? (number + 0x100000000) : number; + a = Math.floor(unsigned / 0xffffff); + unsigned &= 0xffffff; + b = Math.floor(unsigned / 0xffff); + unsigned &= 0xffff; + c = Math.floor(unsigned / 0xff); + unsigned &= 0xff; + d = Math.floor(unsigned); + return asArray ? [chr(a), chr(b), chr(c), chr(d)] : chr(a) + chr(b) + chr(c) + chr(d); +}; + +BinaryParser.encode_int64 = function encode_int64 (number) { + var a, b, c, d, e, f, g, h, unsigned; + unsigned = (number < 0) ? (number + 0x10000000000000000) : number; + a = Math.floor(unsigned / 0xffffffffffffff); + unsigned &= 0xffffffffffffff; + b = Math.floor(unsigned / 0xffffffffffff); + unsigned &= 0xffffffffffff; + c = Math.floor(unsigned / 0xffffffffff); + unsigned &= 0xffffffffff; + d = Math.floor(unsigned / 0xffffffff); + unsigned &= 0xffffffff; + e = Math.floor(unsigned / 0xffffff); + unsigned &= 0xffffff; + f = Math.floor(unsigned / 0xffff); + unsigned &= 0xffff; + g = Math.floor(unsigned / 0xff); + unsigned &= 0xff; + h = Math.floor(unsigned); + return chr(a) + chr(b) + chr(c) + chr(d) + chr(e) + chr(f) + chr(g) + chr(h); +}; + +/** + * UTF8 methods + */ + +// Take a raw binary string and return a utf8 string +BinaryParser.decode_utf8 = function decode_utf8 (binaryStr) { + var len = binaryStr.length + , decoded = '' + , i = 0 + , c = 0 + , c1 = 0 + , c2 = 0 + , c3; + + while (i < len) { + c = binaryStr.charCodeAt(i); + if (c < 128) { + decoded += String.fromCharCode(c); + i++; + } else if ((c > 191) && (c < 224)) { + c2 = binaryStr.charCodeAt(i+1); + decoded += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); + i += 2; + } else { + c2 = binaryStr.charCodeAt(i+1); + c3 = binaryStr.charCodeAt(i+2); + decoded += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + i += 3; + } + } + + return decoded; +}; + +// Encode a cstring +BinaryParser.encode_cstring = function encode_cstring (s) { + return unescape(encodeURIComponent(s)) + BinaryParser.fromByte(0); +}; + +// Take a utf8 string and return a binary string +BinaryParser.encode_utf8 = function encode_utf8 (s) { + var a = "" + , c; + + for (var n = 0, len = s.length; n < len; n++) { + c = s.charCodeAt(n); + + if (c < 128) { + a += String.fromCharCode(c); + } else if ((c > 127) && (c < 2048)) { + a += String.fromCharCode((c>>6) | 192) ; + a += String.fromCharCode((c&63) | 128); + } else { + a += String.fromCharCode((c>>12) | 224); + a += String.fromCharCode(((c>>6) & 63) | 128); + a += String.fromCharCode((c&63) | 128); + } + } + + return a; +}; + +BinaryParser.hprint = function hprint (s) { + var number; + + for (var i = 0, len = s.length; i < len; i++) { + if (s.charCodeAt(i) < 32) { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(16) + : s.charCodeAt(i).toString(16); + process.stdout.write(number + " ") + } else { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(16) + : s.charCodeAt(i).toString(16); + process.stdout.write(number + " ") + } + } + + process.stdout.write("\n\n"); +}; + +BinaryParser.ilprint = function hprint (s) { + var number; + + for (var i = 0, len = s.length; i < len; i++) { + if (s.charCodeAt(i) < 32) { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(10) + : s.charCodeAt(i).toString(10); + + require('util').debug(number+' : '); + } else { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(10) + : s.charCodeAt(i).toString(10); + require('util').debug(number+' : '+ s.charAt(i)); + } + } +}; + +BinaryParser.hlprint = function hprint (s) { + var number; + + for (var i = 0, len = s.length; i < len; i++) { + if (s.charCodeAt(i) < 32) { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(16) + : s.charCodeAt(i).toString(16); + require('util').debug(number+' : '); + } else { + number = s.charCodeAt(i) <= 15 + ? "0" + s.charCodeAt(i).toString(16) + : s.charCodeAt(i).toString(16); + require('util').debug(number+' : '+ s.charAt(i)); + } + } +}; + +/** + * BinaryParser buffer constructor. + */ +function BinaryParserBuffer (bigEndian, buffer) { + this.bigEndian = bigEndian || 0; + this.buffer = []; + this.setBuffer(buffer); +}; + +BinaryParserBuffer.prototype.setBuffer = function setBuffer (data) { + var l, i, b; + + if (data) { + i = l = data.length; + b = this.buffer = new Array(l); + for (; i; b[l - i] = data.charCodeAt(--i)); + this.bigEndian && b.reverse(); + } +}; + +BinaryParserBuffer.prototype.hasNeededBits = function hasNeededBits (neededBits) { + return this.buffer.length >= -(-neededBits >> 3); +}; + +BinaryParserBuffer.prototype.checkBuffer = function checkBuffer (neededBits) { + if (!this.hasNeededBits(neededBits)) { + throw new Error("checkBuffer::missing bytes"); + } +}; + +BinaryParserBuffer.prototype.readBits = function readBits (start, length) { + //shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni) + + function shl (a, b) { + for (; b--; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1); + return a; + } + + if (start < 0 || length <= 0) { + return 0; + } + + this.checkBuffer(start + length); + + var offsetLeft + , offsetRight = start % 8 + , curByte = this.buffer.length - ( start >> 3 ) - 1 + , lastByte = this.buffer.length + ( -( start + length ) >> 3 ) + , diff = curByte - lastByte + , sum = ((this.buffer[ curByte ] >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1)) + (diff && (offsetLeft = (start + length) % 8) ? (this.buffer[lastByte++] & ((1 << offsetLeft) - 1)) << (diff-- << 3) - offsetRight : 0); + + for(; diff; sum += shl(this.buffer[lastByte++], (diff-- << 3) - offsetRight)); + + return sum; +}; + +/** + * Expose. + */ +BinaryParser.Buffer = BinaryParserBuffer; + +exports.BinaryParser = BinaryParser; diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/bson.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/bson.js new file mode 100644 index 0000000..3004d84 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/bson.js @@ -0,0 +1,1539 @@ +var Long = require('./long').Long + , Double = require('./double').Double + , Timestamp = require('./timestamp').Timestamp + , ObjectID = require('./objectid').ObjectID + , Symbol = require('./symbol').Symbol + , Code = require('./code').Code + , MinKey = require('./min_key').MinKey + , MaxKey = require('./max_key').MaxKey + , DBRef = require('./db_ref').DBRef + , Binary = require('./binary').Binary + , BinaryParser = require('./binary_parser').BinaryParser + , writeIEEE754 = require('./float_parser').writeIEEE754 + , readIEEE754 = require('./float_parser').readIEEE754 + +// To ensure that 0.4 of node works correctly +var isDate = function isDate(d) { + return typeof d === 'object' && Object.prototype.toString.call(d) === '[object Date]'; +} + +/** + * Create a new BSON instance + * + * @class Represents the BSON Parser + * @return {BSON} instance of BSON Parser. + */ +function BSON () {}; + +/** + * @ignore + * @api private + */ +// BSON MAX VALUES +BSON.BSON_INT32_MAX = 0x7FFFFFFF; +BSON.BSON_INT32_MIN = -0x80000000; + +BSON.BSON_INT64_MAX = Math.pow(2, 63) - 1; +BSON.BSON_INT64_MIN = -Math.pow(2, 63); + +// JS MAX PRECISE VALUES +BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double. +BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double. + +// Internal long versions +var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000); // Any integer up to 2^53 can be precisely represented by a double. +var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000); // Any integer down to -2^53 can be precisely represented by a double. + +/** + * Number BSON Type + * + * @classconstant BSON_DATA_NUMBER + **/ +BSON.BSON_DATA_NUMBER = 1; +/** + * String BSON Type + * + * @classconstant BSON_DATA_STRING + **/ +BSON.BSON_DATA_STRING = 2; +/** + * Object BSON Type + * + * @classconstant BSON_DATA_OBJECT + **/ +BSON.BSON_DATA_OBJECT = 3; +/** + * Array BSON Type + * + * @classconstant BSON_DATA_ARRAY + **/ +BSON.BSON_DATA_ARRAY = 4; +/** + * Binary BSON Type + * + * @classconstant BSON_DATA_BINARY + **/ +BSON.BSON_DATA_BINARY = 5; +/** + * ObjectID BSON Type + * + * @classconstant BSON_DATA_OID + **/ +BSON.BSON_DATA_OID = 7; +/** + * Boolean BSON Type + * + * @classconstant BSON_DATA_BOOLEAN + **/ +BSON.BSON_DATA_BOOLEAN = 8; +/** + * Date BSON Type + * + * @classconstant BSON_DATA_DATE + **/ +BSON.BSON_DATA_DATE = 9; +/** + * null BSON Type + * + * @classconstant BSON_DATA_NULL + **/ +BSON.BSON_DATA_NULL = 10; +/** + * RegExp BSON Type + * + * @classconstant BSON_DATA_REGEXP + **/ +BSON.BSON_DATA_REGEXP = 11; +/** + * Code BSON Type + * + * @classconstant BSON_DATA_CODE + **/ +BSON.BSON_DATA_CODE = 13; +/** + * Symbol BSON Type + * + * @classconstant BSON_DATA_SYMBOL + **/ +BSON.BSON_DATA_SYMBOL = 14; +/** + * Code with Scope BSON Type + * + * @classconstant BSON_DATA_CODE_W_SCOPE + **/ +BSON.BSON_DATA_CODE_W_SCOPE = 15; +/** + * 32 bit Integer BSON Type + * + * @classconstant BSON_DATA_INT + **/ +BSON.BSON_DATA_INT = 16; +/** + * Timestamp BSON Type + * + * @classconstant BSON_DATA_TIMESTAMP + **/ +BSON.BSON_DATA_TIMESTAMP = 17; +/** + * Long BSON Type + * + * @classconstant BSON_DATA_LONG + **/ +BSON.BSON_DATA_LONG = 18; +/** + * MinKey BSON Type + * + * @classconstant BSON_DATA_MIN_KEY + **/ +BSON.BSON_DATA_MIN_KEY = 0xff; +/** + * MaxKey BSON Type + * + * @classconstant BSON_DATA_MAX_KEY + **/ +BSON.BSON_DATA_MAX_KEY = 0x7f; + +/** + * Binary Default Type + * + * @classconstant BSON_BINARY_SUBTYPE_DEFAULT + **/ +BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0; +/** + * Binary Function Type + * + * @classconstant BSON_BINARY_SUBTYPE_FUNCTION + **/ +BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1; +/** + * Binary Byte Array Type + * + * @classconstant BSON_BINARY_SUBTYPE_BYTE_ARRAY + **/ +BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2; +/** + * Binary UUID Type + * + * @classconstant BSON_BINARY_SUBTYPE_UUID + **/ +BSON.BSON_BINARY_SUBTYPE_UUID = 3; +/** + * Binary MD5 Type + * + * @classconstant BSON_BINARY_SUBTYPE_MD5 + **/ +BSON.BSON_BINARY_SUBTYPE_MD5 = 4; +/** + * Binary User Defined Type + * + * @classconstant BSON_BINARY_SUBTYPE_USER_DEFINED + **/ +BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128; + +/** + * Calculate the bson size for a passed in Javascript object. + * + * @param {Object} object the Javascript object to calculate the BSON byte size for. + * @param {Boolean} [serializeFunctions] serialize all functions in the object **(default:false)**. + * @return {Number} returns the number of bytes the BSON object will take up. + * @api public + */ +BSON.calculateObjectSize = function calculateObjectSize(object, serializeFunctions) { + var totalLength = (4 + 1); + + if(Array.isArray(object)) { + for(var i = 0; i < object.length; i++) { + totalLength += calculateElement(i.toString(), object[i], serializeFunctions) + } + } else { + // If we have toBSON defined, override the current object + if(object.toBSON) { + object = object.toBSON(); + } + + // Calculate size + for(var key in object) { + totalLength += calculateElement(key, object[key], serializeFunctions) + } + } + + return totalLength; +} + +/** + * @ignore + * @api private + */ +function calculateElement(name, value, serializeFunctions) { + var isBuffer = typeof Buffer !== 'undefined'; + + switch(typeof value) { + case 'string': + return 1 + (!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1 + 4 + (!isBuffer ? numberOfBytes(value) : Buffer.byteLength(value, 'utf8')) + 1; + case 'number': + if(Math.floor(value) === value && value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { + if(value >= BSON.BSON_INT32_MIN && value <= BSON.BSON_INT32_MAX) { // 32 bit + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (4 + 1); + } else { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (8 + 1); + } + } else { // 64 bit + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (8 + 1); + } + case 'undefined': + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (1); + case 'boolean': + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (1 + 1); + case 'object': + if(value == null || value instanceof MinKey || value instanceof MaxKey || value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (1); + } else if(value instanceof ObjectID || value['_bsontype'] == 'ObjectID') { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (12 + 1); + } else if(value instanceof Date || isDate(value)) { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (8 + 1); + } else if(typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (1 + 4 + 1) + value.length; + } else if(value instanceof Long || value instanceof Double || value instanceof Timestamp + || value['_bsontype'] == 'Long' || value['_bsontype'] == 'Double' || value['_bsontype'] == 'Timestamp') { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (8 + 1); + } else if(value instanceof Code || value['_bsontype'] == 'Code') { + // Calculate size depending on the availability of a scope + if(value.scope != null && Object.keys(value.scope).length > 0) { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + 4 + 4 + (!isBuffer ? numberOfBytes(value.code.toString()) : Buffer.byteLength(value.code.toString(), 'utf8')) + 1 + BSON.calculateObjectSize(value.scope, serializeFunctions); + } else { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + 4 + (!isBuffer ? numberOfBytes(value.code.toString()) : Buffer.byteLength(value.code.toString(), 'utf8')) + 1; + } + } else if(value instanceof Binary || value['_bsontype'] == 'Binary') { + // Check what kind of subtype we have + if(value.sub_type == Binary.SUBTYPE_BYTE_ARRAY) { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (value.position + 1 + 4 + 1 + 4); + } else { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (value.position + 1 + 4 + 1); + } + } else if(value instanceof Symbol || value['_bsontype'] == 'Symbol') { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + ((!isBuffer ? numberOfBytes(value.value) : Buffer.byteLength(value.value, 'utf8')) + 4 + 1 + 1); + } else if(value instanceof DBRef || value['_bsontype'] == 'DBRef') { + // Set up correct object for serialization + var ordered_values = { + '$ref': value.namespace + , '$id' : value.oid + }; + + // Add db reference if it exists + if(null != value.db) { + ordered_values['$db'] = value.db; + } + + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + BSON.calculateObjectSize(ordered_values, serializeFunctions); + } else if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]') { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + (!isBuffer ? numberOfBytes(value.source) : Buffer.byteLength(value.source, 'utf8')) + 1 + + (value.global ? 1 : 0) + (value.ignoreCase ? 1 : 0) + (value.multiline ? 1 : 0) + 1 + } else { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + BSON.calculateObjectSize(value, serializeFunctions) + 1; + } + case 'function': + // WTF for 0.4.X where typeof /someregexp/ === 'function' + if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]' || String.call(value) == '[object RegExp]') { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + (!isBuffer ? numberOfBytes(value.source) : Buffer.byteLength(value.source, 'utf8')) + 1 + + (value.global ? 1 : 0) + (value.ignoreCase ? 1 : 0) + (value.multiline ? 1 : 0) + 1 + } else { + if(serializeFunctions && value.scope != null && Object.keys(value.scope).length > 0) { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + 4 + 4 + (!isBuffer ? numberOfBytes(value.toString()) : Buffer.byteLength(value.toString(), 'utf8')) + 1 + BSON.calculateObjectSize(value.scope, serializeFunctions); + } else if(serializeFunctions) { + return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + 4 + (!isBuffer ? numberOfBytes(value.toString()) : Buffer.byteLength(value.toString(), 'utf8')) + 1; + } + } + } + + return 0; +} + +/** + * Serialize a Javascript object using a predefined Buffer and index into the buffer, useful when pre-allocating the space for serialization. + * + * @param {Object} object the Javascript object to serialize. + * @param {Boolean} checkKeys the serializer will check if keys are valid. + * @param {Buffer} buffer the Buffer you pre-allocated to store the serialized BSON object. + * @param {Number} index the index in the buffer where we wish to start serializing into. + * @param {Boolean} serializeFunctions serialize the javascript functions **(default:false)**. + * @return {Number} returns the new write index in the Buffer. + * @api public + */ +BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object, checkKeys, buffer, index, serializeFunctions) { + // Default setting false + serializeFunctions = serializeFunctions == null ? false : serializeFunctions; + // Write end information (length of the object) + var size = buffer.length; + // Write the size of the object + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + return serializeObject(object, checkKeys, buffer, index, serializeFunctions) - 1; +} + +/** + * @ignore + * @api private + */ +var serializeObject = function(object, checkKeys, buffer, index, serializeFunctions) { + // Process the object + if(Array.isArray(object)) { + for(var i = 0; i < object.length; i++) { + index = packElement(i.toString(), object[i], checkKeys, buffer, index, serializeFunctions); + } + } else { + // If we have toBSON defined, override the current object + if(object.toBSON) { + object = object.toBSON(); + } + + // Serialize the object + for(var key in object) { + // Check the key and throw error if it's illegal + if (key != '$db' && key != '$ref' && key != '$id') { + // dollars and dots ok + BSON.checkKey(key, !checkKeys); + } + + // Pack the element + index = packElement(key, object[key], checkKeys, buffer, index, serializeFunctions); + } + } + + // Write zero + buffer[index++] = 0; + return index; +} + +var stringToBytes = function(str) { + var ch, st, re = []; + for (var i = 0; i < str.length; i++ ) { + ch = str.charCodeAt(i); // get char + st = []; // set up "stack" + do { + st.push( ch & 0xFF ); // push byte to stack + ch = ch >> 8; // shift value down by 1 byte + } + while ( ch ); + // add stack contents to result + // done because chars have "wrong" endianness + re = re.concat( st.reverse() ); + } + // return an array of bytes + return re; +} + +var numberOfBytes = function(str) { + var ch, st, re = 0; + for (var i = 0; i < str.length; i++ ) { + ch = str.charCodeAt(i); // get char + st = []; // set up "stack" + do { + st.push( ch & 0xFF ); // push byte to stack + ch = ch >> 8; // shift value down by 1 byte + } + while ( ch ); + // add stack contents to result + // done because chars have "wrong" endianness + re = re + st.length; + } + // return an array of bytes + return re; +} + +/** + * @ignore + * @api private + */ +var writeToTypedArray = function(buffer, string, index) { + var bytes = stringToBytes(string); + for(var i = 0; i < bytes.length; i++) { + buffer[index + i] = bytes[i]; + } + return bytes.length; +} + +/** + * @ignore + * @api private + */ +var supportsBuffer = typeof Buffer != 'undefined'; + +/** + * @ignore + * @api private + */ +var packElement = function(name, value, checkKeys, buffer, index, serializeFunctions) { + var startIndex = index; + + switch(typeof value) { + case 'string': + // Encode String type + buffer[index++] = BSON.BSON_DATA_STRING; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + + // Calculate size + var size = supportsBuffer ? Buffer.byteLength(value) + 1 : numberOfBytes(value) + 1; + // Write the size of the string to buffer + buffer[index + 3] = (size >> 24) & 0xff; + buffer[index + 2] = (size >> 16) & 0xff; + buffer[index + 1] = (size >> 8) & 0xff; + buffer[index] = size & 0xff; + // Ajust the index + index = index + 4; + // Write the string + supportsBuffer ? buffer.write(value, index, 'utf8') : writeToTypedArray(buffer, value, index); + // Update index + index = index + size - 1; + // Write zero + buffer[index++] = 0; + // Return index + return index; + case 'number': + // We have an integer value + if(Math.floor(value) === value && value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { + // If the value fits in 32 bits encode as int, if it fits in a double + // encode it as a double, otherwise long + if(value >= BSON.BSON_INT32_MIN && value <= BSON.BSON_INT32_MAX) { + // Set int type 32 bits or less + buffer[index++] = BSON.BSON_DATA_INT; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Write the int value + buffer[index++] = value & 0xff; + buffer[index++] = (value >> 8) & 0xff; + buffer[index++] = (value >> 16) & 0xff; + buffer[index++] = (value >> 24) & 0xff; + } else if(value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) { + // Encode as double + buffer[index++] = BSON.BSON_DATA_NUMBER; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Write float + writeIEEE754(buffer, value, index, 'little', 52, 8); + // Ajust index + index = index + 8; + } else { + // Set long type + buffer[index++] = BSON.BSON_DATA_LONG; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + var longVal = Long.fromNumber(value); + var lowBits = longVal.getLowBits(); + var highBits = longVal.getHighBits(); + // Encode low bits + buffer[index++] = lowBits & 0xff; + buffer[index++] = (lowBits >> 8) & 0xff; + buffer[index++] = (lowBits >> 16) & 0xff; + buffer[index++] = (lowBits >> 24) & 0xff; + // Encode high bits + buffer[index++] = highBits & 0xff; + buffer[index++] = (highBits >> 8) & 0xff; + buffer[index++] = (highBits >> 16) & 0xff; + buffer[index++] = (highBits >> 24) & 0xff; + } + } else { + // Encode as double + buffer[index++] = BSON.BSON_DATA_NUMBER; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Write float + writeIEEE754(buffer, value, index, 'little', 52, 8); + // Ajust index + index = index + 8; + } + + return index; + case 'undefined': + // Set long type + buffer[index++] = BSON.BSON_DATA_NULL; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + return index; + case 'boolean': + // Write the type + buffer[index++] = BSON.BSON_DATA_BOOLEAN; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Encode the boolean value + buffer[index++] = value ? 1 : 0; + return index; + case 'object': + if(value === null || value instanceof MinKey || value instanceof MaxKey + || value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') { + // Write the type of either min or max key + if(value === null) { + buffer[index++] = BSON.BSON_DATA_NULL; + } else if(value instanceof MinKey) { + buffer[index++] = BSON.BSON_DATA_MIN_KEY; + } else { + buffer[index++] = BSON.BSON_DATA_MAX_KEY; + } + + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + return index; + } else if(value instanceof ObjectID || value['_bsontype'] == 'ObjectID') { + // Write the type + buffer[index++] = BSON.BSON_DATA_OID; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + + // Write objectid + supportsBuffer ? buffer.write(value.id, index, 'binary') : writeToTypedArray(buffer, value.id, index); + // Ajust index + index = index + 12; + return index; + } else if(value instanceof Date || isDate(value)) { + // Write the type + buffer[index++] = BSON.BSON_DATA_DATE; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + + // Write the date + var dateInMilis = Long.fromNumber(value.getTime()); + var lowBits = dateInMilis.getLowBits(); + var highBits = dateInMilis.getHighBits(); + // Encode low bits + buffer[index++] = lowBits & 0xff; + buffer[index++] = (lowBits >> 8) & 0xff; + buffer[index++] = (lowBits >> 16) & 0xff; + buffer[index++] = (lowBits >> 24) & 0xff; + // Encode high bits + buffer[index++] = highBits & 0xff; + buffer[index++] = (highBits >> 8) & 0xff; + buffer[index++] = (highBits >> 16) & 0xff; + buffer[index++] = (highBits >> 24) & 0xff; + return index; + } else if(typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) { + // Write the type + buffer[index++] = BSON.BSON_DATA_BINARY; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Get size of the buffer (current write point) + var size = value.length; + // Write the size of the string to buffer + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + // Write the default subtype + buffer[index++] = BSON.BSON_BINARY_SUBTYPE_DEFAULT; + // Copy the content form the binary field to the buffer + value.copy(buffer, index, 0, size); + // Adjust the index + index = index + size; + return index; + } else if(value instanceof Long || value instanceof Timestamp || value['_bsontype'] == 'Long' || value['_bsontype'] == 'Timestamp') { + // Write the type + buffer[index++] = value instanceof Long ? BSON.BSON_DATA_LONG : BSON.BSON_DATA_TIMESTAMP; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Write the date + var lowBits = value.getLowBits(); + var highBits = value.getHighBits(); + // Encode low bits + buffer[index++] = lowBits & 0xff; + buffer[index++] = (lowBits >> 8) & 0xff; + buffer[index++] = (lowBits >> 16) & 0xff; + buffer[index++] = (lowBits >> 24) & 0xff; + // Encode high bits + buffer[index++] = highBits & 0xff; + buffer[index++] = (highBits >> 8) & 0xff; + buffer[index++] = (highBits >> 16) & 0xff; + buffer[index++] = (highBits >> 24) & 0xff; + return index; + } else if(value instanceof Double || value['_bsontype'] == 'Double') { + // Encode as double + buffer[index++] = BSON.BSON_DATA_NUMBER; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Write float + writeIEEE754(buffer, value, index, 'little', 52, 8); + // Ajust index + index = index + 8; + return index; + } else if(value instanceof Code || value['_bsontype'] == 'Code') { + if(value.scope != null && Object.keys(value.scope).length > 0) { + // Write the type + buffer[index++] = BSON.BSON_DATA_CODE_W_SCOPE; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Calculate the scope size + var scopeSize = BSON.calculateObjectSize(value.scope, serializeFunctions); + // Function string + var functionString = value.code.toString(); + // Function Size + var codeSize = supportsBuffer ? Buffer.byteLength(functionString) + 1 : numberOfBytes(functionString) + 1; + + // Calculate full size of the object + var totalSize = 4 + codeSize + scopeSize + 4; + + // Write the total size of the object + buffer[index++] = totalSize & 0xff; + buffer[index++] = (totalSize >> 8) & 0xff; + buffer[index++] = (totalSize >> 16) & 0xff; + buffer[index++] = (totalSize >> 24) & 0xff; + + // Write the size of the string to buffer + buffer[index++] = codeSize & 0xff; + buffer[index++] = (codeSize >> 8) & 0xff; + buffer[index++] = (codeSize >> 16) & 0xff; + buffer[index++] = (codeSize >> 24) & 0xff; + + // Write the string + supportsBuffer ? buffer.write(functionString, index, 'utf8') : writeToTypedArray(buffer, functionString, index); + // Update index + index = index + codeSize - 1; + // Write zero + buffer[index++] = 0; + // Serialize the scope object + var scopeObjectBuffer = supportsBuffer ? new Buffer(scopeSize) : new Uint8Array(new ArrayBuffer(scopeSize)); + // Execute the serialization into a seperate buffer + serializeObject(value.scope, checkKeys, scopeObjectBuffer, 0, serializeFunctions); + + // Adjusted scope Size (removing the header) + var scopeDocSize = scopeSize; + // Write scope object size + buffer[index++] = scopeDocSize & 0xff; + buffer[index++] = (scopeDocSize >> 8) & 0xff; + buffer[index++] = (scopeDocSize >> 16) & 0xff; + buffer[index++] = (scopeDocSize >> 24) & 0xff; + + // Write the scopeObject into the buffer + supportsBuffer ? scopeObjectBuffer.copy(buffer, index, 0, scopeSize) : buffer.set(scopeObjectBuffer, index); + // Adjust index, removing the empty size of the doc (5 bytes 0000000005) + index = index + scopeDocSize - 5; + // Write trailing zero + buffer[index++] = 0; + return index + } else { + buffer[index++] = BSON.BSON_DATA_CODE; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Function string + var functionString = value.code.toString(); + // Function Size + var size = supportsBuffer ? Buffer.byteLength(functionString) + 1 : numberOfBytes(functionString) + 1; + // Write the size of the string to buffer + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + // Write the string + supportsBuffer ? buffer.write(functionString, index, 'utf8') : writeToTypedArray(buffer, functionString, index); + // Update index + index = index + size - 1; + // Write zero + buffer[index++] = 0; + return index; + } + } else if(value instanceof Binary || value['_bsontype'] == 'Binary') { + // Write the type + buffer[index++] = BSON.BSON_DATA_BINARY; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Extract the buffer + var data = value.value(true); + // Calculate size + var size = value.position; + // Write the size of the string to buffer + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + // Write the subtype to the buffer + buffer[index++] = value.sub_type; + + // If we have binary type 2 the 4 first bytes are the size + if(value.sub_type == Binary.SUBTYPE_BYTE_ARRAY) { + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + } + + // Write the data to the object + supportsBuffer ? data.copy(buffer, index, 0, value.position) : buffer.set(data, index); + // Ajust index + index = index + value.position; + return index; + } else if(value instanceof Symbol || value['_bsontype'] == 'Symbol') { + // Write the type + buffer[index++] = BSON.BSON_DATA_SYMBOL; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Calculate size + var size = supportsBuffer ? Buffer.byteLength(value.value) + 1 : numberOfBytes(value.value) + 1; + // Write the size of the string to buffer + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + // Write the string + buffer.write(value.value, index, 'utf8'); + // Update index + index = index + size - 1; + // Write zero + buffer[index++] = 0x00; + return index; + } else if(value instanceof DBRef || value['_bsontype'] == 'DBRef') { + // Write the type + buffer[index++] = BSON.BSON_DATA_OBJECT; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Set up correct object for serialization + var ordered_values = { + '$ref': value.namespace + , '$id' : value.oid + }; + + // Add db reference if it exists + if(null != value.db) { + ordered_values['$db'] = value.db; + } + + // Message size + var size = BSON.calculateObjectSize(ordered_values, serializeFunctions); + // Serialize the object + var endIndex = BSON.serializeWithBufferAndIndex(ordered_values, checkKeys, buffer, index, serializeFunctions); + // Write the size of the string to buffer + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + // Write zero for object + buffer[endIndex++] = 0x00; + // Return the end index + return endIndex; + } else if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]') { + // Write the type + buffer[index++] = BSON.BSON_DATA_REGEXP; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + + // Write the regular expression string + supportsBuffer ? buffer.write(value.source, index, 'utf8') : writeToTypedArray(buffer, value.source, index); + // Adjust the index + index = index + (supportsBuffer ? Buffer.byteLength(value.source) : numberOfBytes(value.source)); + // Write zero + buffer[index++] = 0x00; + // Write the parameters + if(value.global) buffer[index++] = 0x73; // s + if(value.ignoreCase) buffer[index++] = 0x69; // i + if(value.multiline) buffer[index++] = 0x6d; // m + // Add ending zero + buffer[index++] = 0x00; + return index; + } else { + // Write the type + buffer[index++] = Array.isArray(value) ? BSON.BSON_DATA_ARRAY : BSON.BSON_DATA_OBJECT; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Adjust the index + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + var endIndex = serializeObject(value, checkKeys, buffer, index + 4, serializeFunctions); + // Write size + var size = endIndex - index; + // Write the size of the string to buffer + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + return endIndex; + } + case 'function': + // WTF for 0.4.X where typeof /someregexp/ === 'function' + if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]' || String.call(value) == '[object RegExp]') { + // Write the type + buffer[index++] = BSON.BSON_DATA_REGEXP; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + + // Write the regular expression string + buffer.write(value.source, index, 'utf8'); + // Adjust the index + index = index + (supportsBuffer ? Buffer.byteLength(value.source) : numberOfBytes(value.source)); + // Write zero + buffer[index++] = 0x00; + // Write the parameters + if(value.global) buffer[index++] = 0x73; // s + if(value.ignoreCase) buffer[index++] = 0x69; // i + if(value.multiline) buffer[index++] = 0x6d; // m + // Add ending zero + buffer[index++] = 0x00; + return index; + } else { + if(serializeFunctions && value.scope != null && Object.keys(value.scope).length > 0) { + // Write the type + buffer[index++] = BSON.BSON_DATA_CODE_W_SCOPE; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Calculate the scope size + var scopeSize = BSON.calculateObjectSize(value.scope, serializeFunctions); + // Function string + var functionString = value.toString(); + // Function Size + var codeSize = supportsBuffer ? Buffer.byteLength(functionString) + 1 : numberOfBytes(functionString) + 1; + + // Calculate full size of the object + var totalSize = 4 + codeSize + scopeSize; + + // Write the total size of the object + buffer[index++] = totalSize & 0xff; + buffer[index++] = (totalSize >> 8) & 0xff; + buffer[index++] = (totalSize >> 16) & 0xff; + buffer[index++] = (totalSize >> 24) & 0xff; + + // Write the size of the string to buffer + buffer[index++] = codeSize & 0xff; + buffer[index++] = (codeSize >> 8) & 0xff; + buffer[index++] = (codeSize >> 16) & 0xff; + buffer[index++] = (codeSize >> 24) & 0xff; + + // Write the string + supportsBuffer ? buffer.write(functionString, index, 'utf8') : writeToTypedArray(buffer, functionString, index); + // Update index + index = index + codeSize - 1; + // Write zero + buffer[index++] = 0; + // Serialize the scope object + var scopeObjectBuffer = new Buffer(scopeSize); + // Execute the serialization into a seperate buffer + serializeObject(value.scope, checkKeys, scopeObjectBuffer, 0, serializeFunctions); + + // Adjusted scope Size (removing the header) + var scopeDocSize = scopeSize - 4; + // Write scope object size + buffer[index++] = scopeDocSize & 0xff; + buffer[index++] = (scopeDocSize >> 8) & 0xff; + buffer[index++] = (scopeDocSize >> 16) & 0xff; + buffer[index++] = (scopeDocSize >> 24) & 0xff; + + // Write the scopeObject into the buffer + scopeObjectBuffer.copy(buffer, index, 0, scopeSize); + + // Adjust index, removing the empty size of the doc (5 bytes 0000000005) + index = index + scopeDocSize - 5; + // Write trailing zero + buffer[index++] = 0; + return index + } else if(serializeFunctions) { + buffer[index++] = BSON.BSON_DATA_CODE; + // Number of written bytes + var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index); + // Encode the name + index = index + numberOfWrittenBytes + 1; + buffer[index - 1] = 0; + // Function string + var functionString = value.toString(); + // Function Size + var size = supportsBuffer ? Buffer.byteLength(functionString) + 1 : numberOfBytes(functionString) + 1; + // Write the size of the string to buffer + buffer[index++] = size & 0xff; + buffer[index++] = (size >> 8) & 0xff; + buffer[index++] = (size >> 16) & 0xff; + buffer[index++] = (size >> 24) & 0xff; + // Write the string + supportsBuffer ? buffer.write(functionString, index, 'utf8') : writeToTypedArray(buffer, functionString, index); + // Update index + index = index + size - 1; + // Write zero + buffer[index++] = 0; + return index; + } + } + } + + // If no value to serialize + return index; +} + +/** + * Serialize a Javascript object. + * + * @param {Object} object the Javascript object to serialize. + * @param {Boolean} checkKeys the serializer will check if keys are valid. + * @param {Boolean} asBuffer return the serialized object as a Buffer object **(ignore)**. + * @param {Boolean} serializeFunctions serialize the javascript functions **(default:false)**. + * @return {Buffer} returns the Buffer object containing the serialized object. + * @api public + */ +BSON.serialize = function(object, checkKeys, asBuffer, serializeFunctions) { + // Throw error if we are trying serialize an illegal type + if(object == null || typeof object != 'object' || Array.isArray(object)) + throw new Error("Only javascript objects supported"); + + // Emoty target buffer + var buffer = null; + // Calculate the size of the object + var size = BSON.calculateObjectSize(object, serializeFunctions); + // Fetch the best available type for storing the binary data + if(buffer = typeof Buffer != 'undefined') { + buffer = new Buffer(size); + asBuffer = true; + } else if(typeof Uint8Array != 'undefined') { + buffer = new Uint8Array(new ArrayBuffer(size)); + } else { + buffer = new Array(size); + } + + // If asBuffer is false use typed arrays + BSON.serializeWithBufferAndIndex(object, checkKeys, buffer, 0, serializeFunctions); + return buffer; +} + +/** + * Contains the function cache if we have that enable to allow for avoiding the eval step on each deserialization, comparison is by md5 + * + * @ignore + * @api private + */ +var functionCache = BSON.functionCache = {}; + +/** + * Crc state variables shared by function + * + * @ignore + * @api private + */ +var table = [0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D]; + +/** + * CRC32 hash method, Fast and enough versitility for our usage + * + * @ignore + * @api private + */ +var crc32 = function(string, start, end) { + var crc = 0 + var x = 0; + var y = 0; + crc = crc ^ (-1); + + for(var i = start, iTop = end; i < iTop;i++) { + y = (crc ^ string[i]) & 0xFF; + x = table[y]; + crc = (crc >>> 8) ^ x; + } + + return crc ^ (-1); +} + +/** + * Deserialize stream data as BSON documents. + * + * Options + * - **evalFunctions** {Boolean, default:false}, evaluate functions in the BSON document scoped to the object deserialized. + * - **cacheFunctions** {Boolean, default:false}, cache evaluated functions for reuse. + * - **cacheFunctionsCrc32** {Boolean, default:false}, use a crc32 code for caching, otherwise use the string of the function. + * - **promoteLongs** {Boolean, default:true}, when deserializing a Long will fit it into a Number if it's smaller than 53 bits + * + * @param {Buffer} data the buffer containing the serialized set of BSON documents. + * @param {Number} startIndex the start index in the data Buffer where the deserialization is to start. + * @param {Number} numberOfDocuments number of documents to deserialize. + * @param {Array} documents an array where to store the deserialized documents. + * @param {Number} docStartIndex the index in the documents array from where to start inserting documents. + * @param {Object} [options] additional options used for the deserialization. + * @return {Number} returns the next index in the buffer after deserialization **x** numbers of documents. + * @api public + */ +BSON.deserializeStream = function(data, startIndex, numberOfDocuments, documents, docStartIndex, options) { + // if(numberOfDocuments !== documents.length) throw new Error("Number of expected results back is less than the number of documents"); + options = options != null ? options : {}; + var index = startIndex; + // Loop over all documents + for(var i = 0; i < numberOfDocuments; i++) { + // Find size of the document + var size = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24; + // Update options with index + options['index'] = index; + // Parse the document at this point + documents[docStartIndex + i] = BSON.deserialize(data, options); + // Adjust index by the document size + index = index + size; + } + + // Return object containing end index of parsing and list of documents + return index; +} + +/** + * Ensure eval is isolated. + * + * @ignore + * @api private + */ +var isolateEvalWithHash = function(functionCache, hash, functionString, object) { + // Contains the value we are going to set + var value = null; + + // Check for cache hit, eval if missing and return cached function + if(functionCache[hash] == null) { + eval("value = " + functionString); + functionCache[hash] = value; + } + // Set the object + return functionCache[hash].bind(object); +} + +/** + * Ensure eval is isolated. + * + * @ignore + * @api private + */ +var isolateEval = function(functionString) { + // Contains the value we are going to set + var value = null; + // Eval the function + eval("value = " + functionString); + return value; +} + +/** + * Convert Uint8Array to String + * + * @ignore + * @api private + */ +var convertUint8ArrayToUtf8String = function(byteArray, startIndex, endIndex) { + return BinaryParser.decode_utf8(convertArraytoUtf8BinaryString(byteArray, startIndex, endIndex)); +} + +var convertArraytoUtf8BinaryString = function(byteArray, startIndex, endIndex) { + var result = ""; + for(var i = startIndex; i < endIndex; i++) { + result = result + String.fromCharCode(byteArray[i]); + } + + return result; +}; + +/** + * Deserialize data as BSON. + * + * Options + * - **evalFunctions** {Boolean, default:false}, evaluate functions in the BSON document scoped to the object deserialized. + * - **cacheFunctions** {Boolean, default:false}, cache evaluated functions for reuse. + * - **cacheFunctionsCrc32** {Boolean, default:false}, use a crc32 code for caching, otherwise use the string of the function. + * - **promoteLongs** {Boolean, default:true}, when deserializing a Long will fit it into a Number if it's smaller than 53 bits + * + * @param {Buffer} buffer the buffer containing the serialized set of BSON documents. + * @param {Object} [options] additional options used for the deserialization. + * @param {Boolean} [isArray] ignore used for recursive parsing. + * @return {Object} returns the deserialized Javascript Object. + * @api public + */ +BSON.deserialize = function(buffer, options, isArray) { + // Options + options = options == null ? {} : options; + var evalFunctions = options['evalFunctions'] == null ? false : options['evalFunctions']; + var cacheFunctions = options['cacheFunctions'] == null ? false : options['cacheFunctions']; + var cacheFunctionsCrc32 = options['cacheFunctionsCrc32'] == null ? false : options['cacheFunctionsCrc32']; + var promoteLongs = options['promoteLongs'] == null ? true : options['promoteLongs']; + + // Validate that we have at least 4 bytes of buffer + if(buffer.length < 5) throw new Error("corrupt bson message < 5 bytes long"); + + // Set up index + var index = typeof options['index'] == 'number' ? options['index'] : 0; + // Reads in a C style string + var readCStyleString = function() { + // Get the start search index + var i = index; + // Locate the end of the c string + while(buffer[i] !== 0x00) { i++ } + // Grab utf8 encoded string + var string = supportsBuffer && Buffer.isBuffer(buffer) ? buffer.toString('utf8', index, i) : convertUint8ArrayToUtf8String(buffer, index, i); + // Update index position + index = i + 1; + // Return string + return string; + } + + // Create holding object + var object = isArray ? [] : {}; + + // Read the document size + var size = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + + // Ensure buffer is valid size + if(size < 5 || size > buffer.length) throw new Error("corrupt bson message"); + + // While we have more left data left keep parsing + while(true) { + // Read the type + var elementType = buffer[index++]; + // If we get a zero it's the last byte, exit + if(elementType == 0) break; + // Read the name of the field + var name = readCStyleString(); + // Switch on the type + switch(elementType) { + case BSON.BSON_DATA_OID: + var string = supportsBuffer && Buffer.isBuffer(buffer) ? buffer.toString('binary', index, index + 12) : convertArraytoUtf8BinaryString(buffer, index, index + 12); + // Decode the oid + object[name] = new ObjectID(string); + // Update index + index = index + 12; + break; + case BSON.BSON_DATA_STRING: + // Read the content of the field + var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Add string to object + object[name] = supportsBuffer && Buffer.isBuffer(buffer) ? buffer.toString('utf8', index, index + stringSize - 1) : convertUint8ArrayToUtf8String(buffer, index, index + stringSize - 1); + // Update parse index position + index = index + stringSize; + break; + case BSON.BSON_DATA_INT: + // Decode the 32bit value + object[name] = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + break; + case BSON.BSON_DATA_NUMBER: + // Decode the double value + object[name] = readIEEE754(buffer, index, 'little', 52, 8); + // Update the index + index = index + 8; + break; + case BSON.BSON_DATA_DATE: + // Unpack the low and high bits + var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Set date object + object[name] = new Date(new Long(lowBits, highBits).toNumber()); + break; + case BSON.BSON_DATA_BOOLEAN: + // Parse the boolean value + object[name] = buffer[index++] == 1; + break; + case BSON.BSON_DATA_NULL: + // Parse the boolean value + object[name] = null; + break; + case BSON.BSON_DATA_BINARY: + // Decode the size of the binary blob + var binarySize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Decode the subtype + var subType = buffer[index++]; + // Decode as raw Buffer object if options specifies it + if(buffer['slice'] != null) { + // If we have subtype 2 skip the 4 bytes for the size + if(subType == Binary.SUBTYPE_BYTE_ARRAY) { + binarySize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + } + // Slice the data + object[name] = new Binary(buffer.slice(index, index + binarySize), subType); + } else { + var _buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(binarySize)) : new Array(binarySize); + // If we have subtype 2 skip the 4 bytes for the size + if(subType == Binary.SUBTYPE_BYTE_ARRAY) { + binarySize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + } + // Copy the data + for(var i = 0; i < binarySize; i++) { + _buffer[i] = buffer[index + i]; + } + // Create the binary object + object[name] = new Binary(_buffer, subType); + } + // Update the index + index = index + binarySize; + break; + case BSON.BSON_DATA_ARRAY: + options['index'] = index; + // Decode the size of the array document + var objectSize = buffer[index] | buffer[index + 1] << 8 | buffer[index + 2] << 16 | buffer[index + 3] << 24; + // Set the array to the object + object[name] = BSON.deserialize(buffer, options, true); + // Adjust the index + index = index + objectSize; + break; + case BSON.BSON_DATA_OBJECT: + options['index'] = index; + // Decode the size of the object document + var objectSize = buffer[index] | buffer[index + 1] << 8 | buffer[index + 2] << 16 | buffer[index + 3] << 24; + // Set the array to the object + object[name] = BSON.deserialize(buffer, options, false); + // Adjust the index + index = index + objectSize; + break; + case BSON.BSON_DATA_REGEXP: + // Create the regexp + var source = readCStyleString(); + var regExpOptions = readCStyleString(); + // For each option add the corresponding one for javascript + var optionsArray = new Array(regExpOptions.length); + + // Parse options + for(var i = 0; i < regExpOptions.length; i++) { + switch(regExpOptions[i]) { + case 'm': + optionsArray[i] = 'm'; + break; + case 's': + optionsArray[i] = 'g'; + break; + case 'i': + optionsArray[i] = 'i'; + break; + } + } + + object[name] = new RegExp(source, optionsArray.join('')); + break; + case BSON.BSON_DATA_LONG: + // Unpack the low and high bits + var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Create long object + var long = new Long(lowBits, highBits); + // Promote the long if possible + if(promoteLongs) { + object[name] = long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG) ? long.toNumber() : long; + } else { + object[name] = long; + } + break; + case BSON.BSON_DATA_SYMBOL: + // Read the content of the field + var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Add string to object + object[name] = new Symbol(buffer.toString('utf8', index, index + stringSize - 1)); + // Update parse index position + index = index + stringSize; + break; + case BSON.BSON_DATA_TIMESTAMP: + // Unpack the low and high bits + var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Set the object + object[name] = new Timestamp(lowBits, highBits); + break; + case BSON.BSON_DATA_MIN_KEY: + // Parse the object + object[name] = new MinKey(); + break; + case BSON.BSON_DATA_MAX_KEY: + // Parse the object + object[name] = new MaxKey(); + break; + case BSON.BSON_DATA_CODE: + // Read the content of the field + var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Function string + var functionString = supportsBuffer && Buffer.isBuffer(buffer) ? buffer.toString('utf8', index, index + stringSize - 1) : convertUint8ArrayToUtf8String(buffer, index, index + stringSize - 1); + + // If we are evaluating the functions + if(evalFunctions) { + // Contains the value we are going to set + var value = null; + // If we have cache enabled let's look for the md5 of the function in the cache + if(cacheFunctions) { + var hash = cacheFunctionsCrc32 ? crc32(functionString) : functionString; + // Got to do this to avoid V8 deoptimizing the call due to finding eval + object[name] = isolateEvalWithHash(functionCache, hash, functionString, object); + } else { + // Set directly + object[name] = isolateEval(functionString); + } + } else { + object[name] = new Code(functionString, {}); + } + + // Update parse index position + index = index + stringSize; + break; + case BSON.BSON_DATA_CODE_W_SCOPE: + // Read the content of the field + var totalSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24; + // Javascript function + var functionString = supportsBuffer && Buffer.isBuffer(buffer) ? buffer.toString('utf8', index, index + stringSize - 1) : convertUint8ArrayToUtf8String(buffer, index, index + stringSize - 1); + // Update parse index position + index = index + stringSize; + // Parse the element + options['index'] = index; + // Decode the size of the object document + var objectSize = buffer[index] | buffer[index + 1] << 8 | buffer[index + 2] << 16 | buffer[index + 3] << 24; + // Decode the scope object + var scopeObject = BSON.deserialize(buffer, options, false); + // Adjust the index + index = index + objectSize; + + // If we are evaluating the functions + if(evalFunctions) { + // Contains the value we are going to set + var value = null; + // If we have cache enabled let's look for the md5 of the function in the cache + if(cacheFunctions) { + var hash = cacheFunctionsCrc32 ? crc32(functionString) : functionString; + // Got to do this to avoid V8 deoptimizing the call due to finding eval + object[name] = isolateEvalWithHash(functionCache, hash, functionString, object); + } else { + // Set directly + object[name] = isolateEval(functionString); + } + + // Set the scope on the object + object[name].scope = scopeObject; + } else { + object[name] = new Code(functionString, scopeObject); + } + + // Add string to object + break; + } + } + + // Check if we have a db ref object + if(object['$id'] != null) object = new DBRef(object['$ref'], object['$id'], object['$db']); + + // Return the final objects + return object; +} + +/** + * Check if key name is valid. + * + * @ignore + * @api private + */ +BSON.checkKey = function checkKey (key, dollarsAndDotsOk) { + if (!key.length) return; + // Check if we have a legal key for the object + if (!!~key.indexOf("\x00")) { + // The BSON spec doesn't allow keys with null bytes because keys are + // null-terminated. + throw Error("key " + key + " must not contain null bytes"); + } + if (!dollarsAndDotsOk) { + if('$' == key[0]) { + throw Error("key " + key + " must not start with '$'"); + } else if (!!~key.indexOf('.')) { + throw Error("key " + key + " must not contain '.'"); + } + } +}; + +/** + * Deserialize data as BSON. + * + * Options + * - **evalFunctions** {Boolean, default:false}, evaluate functions in the BSON document scoped to the object deserialized. + * - **cacheFunctions** {Boolean, default:false}, cache evaluated functions for reuse. + * - **cacheFunctionsCrc32** {Boolean, default:false}, use a crc32 code for caching, otherwise use the string of the function. + * + * @param {Buffer} buffer the buffer containing the serialized set of BSON documents. + * @param {Object} [options] additional options used for the deserialization. + * @param {Boolean} [isArray] ignore used for recursive parsing. + * @return {Object} returns the deserialized Javascript Object. + * @api public + */ +BSON.prototype.deserialize = function(data, options) { + return BSON.deserialize(data, options); +} + +/** + * Deserialize stream data as BSON documents. + * + * Options + * - **evalFunctions** {Boolean, default:false}, evaluate functions in the BSON document scoped to the object deserialized. + * - **cacheFunctions** {Boolean, default:false}, cache evaluated functions for reuse. + * - **cacheFunctionsCrc32** {Boolean, default:false}, use a crc32 code for caching, otherwise use the string of the function. + * + * @param {Buffer} data the buffer containing the serialized set of BSON documents. + * @param {Number} startIndex the start index in the data Buffer where the deserialization is to start. + * @param {Number} numberOfDocuments number of documents to deserialize. + * @param {Array} documents an array where to store the deserialized documents. + * @param {Number} docStartIndex the index in the documents array from where to start inserting documents. + * @param {Object} [options] additional options used for the deserialization. + * @return {Number} returns the next index in the buffer after deserialization **x** numbers of documents. + * @api public + */ +BSON.prototype.deserializeStream = function(data, startIndex, numberOfDocuments, documents, docStartIndex, options) { + return BSON.deserializeStream(data, startIndex, numberOfDocuments, documents, docStartIndex, options); +} + +/** + * Serialize a Javascript object. + * + * @param {Object} object the Javascript object to serialize. + * @param {Boolean} checkKeys the serializer will check if keys are valid. + * @param {Boolean} asBuffer return the serialized object as a Buffer object **(ignore)**. + * @param {Boolean} serializeFunctions serialize the javascript functions **(default:false)**. + * @return {Buffer} returns the Buffer object containing the serialized object. + * @api public + */ +BSON.prototype.serialize = function(object, checkKeys, asBuffer, serializeFunctions) { + return BSON.serialize(object, checkKeys, asBuffer, serializeFunctions); +} + +/** + * Calculate the bson size for a passed in Javascript object. + * + * @param {Object} object the Javascript object to calculate the BSON byte size for. + * @param {Boolean} [serializeFunctions] serialize all functions in the object **(default:false)**. + * @return {Number} returns the number of bytes the BSON object will take up. + * @api public + */ +BSON.prototype.calculateObjectSize = function(object, serializeFunctions) { + return BSON.calculateObjectSize(object, serializeFunctions); +} + +/** + * Serialize a Javascript object using a predefined Buffer and index into the buffer, useful when pre-allocating the space for serialization. + * + * @param {Object} object the Javascript object to serialize. + * @param {Boolean} checkKeys the serializer will check if keys are valid. + * @param {Buffer} buffer the Buffer you pre-allocated to store the serialized BSON object. + * @param {Number} index the index in the buffer where we wish to start serializing into. + * @param {Boolean} serializeFunctions serialize the javascript functions **(default:false)**. + * @return {Number} returns the new write index in the Buffer. + * @api public + */ +BSON.prototype.serializeWithBufferAndIndex = function(object, checkKeys, buffer, startIndex, serializeFunctions) { + return BSON.serializeWithBufferAndIndex(object, checkKeys, buffer, startIndex, serializeFunctions); +} + +/** + * @ignore + * @api private + */ +exports.Code = Code; +exports.Symbol = Symbol; +exports.BSON = BSON; +exports.DBRef = DBRef; +exports.Binary = Binary; +exports.ObjectID = ObjectID; +exports.Long = Long; +exports.Timestamp = Timestamp; +exports.Double = Double; +exports.MinKey = MinKey; +exports.MaxKey = MaxKey; diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/code.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/code.js new file mode 100644 index 0000000..69b56a3 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/code.js @@ -0,0 +1,25 @@ +/** + * A class representation of the BSON Code type. + * + * @class Represents the BSON Code type. + * @param {String|Function} code a string or function. + * @param {Object} [scope] an optional scope for the function. + * @return {Code} + */ +function Code(code, scope) { + if(!(this instanceof Code)) return new Code(code, scope); + + this._bsontype = 'Code'; + this.code = code; + this.scope = scope == null ? {} : scope; +}; + +/** + * @ignore + * @api private + */ +Code.prototype.toJSON = function() { + return {scope:this.scope, code:this.code}; +} + +exports.Code = Code; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/db_ref.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/db_ref.js new file mode 100644 index 0000000..56b6510 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/db_ref.js @@ -0,0 +1,31 @@ +/** + * A class representation of the BSON DBRef type. + * + * @class Represents the BSON DBRef type. + * @param {String} namespace the collection name. + * @param {ObjectID} oid the reference ObjectID. + * @param {String} [db] optional db name, if omitted the reference is local to the current db. + * @return {DBRef} + */ +function DBRef(namespace, oid, db) { + if(!(this instanceof DBRef)) return new DBRef(namespace, oid, db); + + this._bsontype = 'DBRef'; + this.namespace = namespace; + this.oid = oid; + this.db = db; +}; + +/** + * @ignore + * @api private + */ +DBRef.prototype.toJSON = function() { + return { + '$ref':this.namespace, + '$id':this.oid, + '$db':this.db == null ? '' : this.db + }; +} + +exports.DBRef = DBRef; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/double.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/double.js new file mode 100644 index 0000000..ae51463 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/double.js @@ -0,0 +1,33 @@ +/** + * A class representation of the BSON Double type. + * + * @class Represents the BSON Double type. + * @param {Number} value the number we want to represent as a double. + * @return {Double} + */ +function Double(value) { + if(!(this instanceof Double)) return new Double(value); + + this._bsontype = 'Double'; + this.value = value; +} + +/** + * Access the number value. + * + * @return {Number} returns the wrapped double number. + * @api public + */ +Double.prototype.valueOf = function() { + return this.value; +}; + +/** + * @ignore + * @api private + */ +Double.prototype.toJSON = function() { + return this.value; +} + +exports.Double = Double; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/float_parser.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/float_parser.js new file mode 100644 index 0000000..6fca392 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/float_parser.js @@ -0,0 +1,121 @@ +// Copyright (c) 2008, Fair Oaks Labs, Inc. +// 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 Fair Oaks Labs, Inc. 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 OWNER 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. +// +// +// Modifications to writeIEEE754 to support negative zeroes made by Brian White + +var readIEEE754 = function(buffer, offset, endian, mLen, nBytes) { + var e, m, + bBE = (endian === 'big'), + eLen = nBytes * 8 - mLen - 1, + eMax = (1 << eLen) - 1, + eBias = eMax >> 1, + nBits = -7, + i = bBE ? 0 : (nBytes - 1), + d = bBE ? 1 : -1, + s = buffer[offset + i]; + + i += d; + + e = s & ((1 << (-nBits)) - 1); + s >>= (-nBits); + nBits += eLen; + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8); + + m = e & ((1 << (-nBits)) - 1); + e >>= (-nBits); + nBits += mLen; + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8); + + if (e === 0) { + e = 1 - eBias; + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity); + } else { + m = m + Math.pow(2, mLen); + e = e - eBias; + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen); +}; + +var writeIEEE754 = function(buffer, value, offset, endian, mLen, nBytes) { + var e, m, c, + bBE = (endian === 'big'), + eLen = nBytes * 8 - mLen - 1, + eMax = (1 << eLen) - 1, + eBias = eMax >> 1, + rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0), + i = bBE ? (nBytes-1) : 0, + d = bBE ? -1 : 1, + s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; + + value = Math.abs(value); + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0; + e = eMax; + } else { + e = Math.floor(Math.log(value) / Math.LN2); + if (value * (c = Math.pow(2, -e)) < 1) { + e--; + c *= 2; + } + if (e+eBias >= 1) { + value += rt / c; + } else { + value += rt * Math.pow(2, 1 - eBias); + } + if (value * c >= 2) { + e++; + c /= 2; + } + + if (e + eBias >= eMax) { + m = 0; + e = eMax; + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen); + e = e + eBias; + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); + e = 0; + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8); + + e = (e << mLen) | m; + eLen += mLen; + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8); + + buffer[offset + i - d] |= s * 128; +}; + +exports.readIEEE754 = readIEEE754; +exports.writeIEEE754 = writeIEEE754; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/index.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/index.js new file mode 100644 index 0000000..950fcad --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/index.js @@ -0,0 +1,74 @@ +try { + exports.BSONPure = require('./bson'); + exports.BSONNative = require('../../ext'); +} catch(err) { + // do nothing +} + +[ './binary_parser' + , './binary' + , './code' + , './db_ref' + , './double' + , './max_key' + , './min_key' + , './objectid' + , './symbol' + , './timestamp' + , './long'].forEach(function (path) { + var module = require('./' + path); + for (var i in module) { + exports[i] = module[i]; + } +}); + +// Exports all the classes for the NATIVE JS BSON Parser +exports.native = function() { + var classes = {}; + // Map all the classes + [ './binary_parser' + , './binary' + , './code' + , './db_ref' + , './double' + , './max_key' + , './min_key' + , './objectid' + , './symbol' + , './timestamp' + , './long' + , '../../ext' +].forEach(function (path) { + var module = require('./' + path); + for (var i in module) { + classes[i] = module[i]; + } + }); + // Return classes list + return classes; +} + +// Exports all the classes for the PURE JS BSON Parser +exports.pure = function() { + var classes = {}; + // Map all the classes + [ './binary_parser' + , './binary' + , './code' + , './db_ref' + , './double' + , './max_key' + , './min_key' + , './objectid' + , './symbol' + , './timestamp' + , './long' + , '././bson'].forEach(function (path) { + var module = require('./' + path); + for (var i in module) { + classes[i] = module[i]; + } + }); + // Return classes list + return classes; +} diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/long.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/long.js new file mode 100644 index 0000000..f8f37a6 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/long.js @@ -0,0 +1,854 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Copyright 2009 Google Inc. All Rights Reserved + +/** + * Defines a Long class for representing a 64-bit two's-complement + * integer value, which faithfully simulates the behavior of a Java "Long". This + * implementation is derived from LongLib in GWT. + * + * Constructs a 64-bit two's-complement integer, given its low and high 32-bit + * values as *signed* integers. See the from* functions below for more + * convenient ways of constructing Longs. + * + * The internal representation of a Long is the two given signed, 32-bit values. + * We use 32-bit pieces because these are the size of integers on which + * Javascript performs bit-operations. For operations like addition and + * multiplication, we split each number into 16-bit pieces, which can easily be + * multiplied within Javascript's floating-point representation without overflow + * or change in sign. + * + * In the algorithms below, we frequently reduce the negative case to the + * positive case by negating the input(s) and then post-processing the result. + * Note that we must ALWAYS check specially whether those values are MIN_VALUE + * (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as + * a positive number, it overflows back into a negative). Not handling this + * case would often result in infinite recursion. + * + * @class Represents the BSON Long type. + * @param {Number} low the low (signed) 32 bits of the Long. + * @param {Number} high the high (signed) 32 bits of the Long. + */ +function Long(low, high) { + if(!(this instanceof Long)) return new Long(low, high); + + this._bsontype = 'Long'; + /** + * @type {number} + * @api private + */ + this.low_ = low | 0; // force into 32 signed bits. + + /** + * @type {number} + * @api private + */ + this.high_ = high | 0; // force into 32 signed bits. +}; + +/** + * Return the int value. + * + * @return {Number} the value, assuming it is a 32-bit integer. + * @api public + */ +Long.prototype.toInt = function() { + return this.low_; +}; + +/** + * Return the Number value. + * + * @return {Number} the closest floating-point representation to this value. + * @api public + */ +Long.prototype.toNumber = function() { + return this.high_ * Long.TWO_PWR_32_DBL_ + + this.getLowBitsUnsigned(); +}; + +/** + * Return the JSON value. + * + * @return {String} the JSON representation. + * @api public + */ +Long.prototype.toJSON = function() { + return this.toString(); +} + +/** + * Return the String value. + * + * @param {Number} [opt_radix] the radix in which the text should be written. + * @return {String} the textual representation of this value. + * @api public + */ +Long.prototype.toString = function(opt_radix) { + var radix = opt_radix || 10; + if (radix < 2 || 36 < radix) { + throw Error('radix out of range: ' + radix); + } + + if (this.isZero()) { + return '0'; + } + + if (this.isNegative()) { + if (this.equals(Long.MIN_VALUE)) { + // We need to change the Long value before it can be negated, so we remove + // the bottom-most digit in this base and then recurse to do the rest. + var radixLong = Long.fromNumber(radix); + var div = this.div(radixLong); + var rem = div.multiply(radixLong).subtract(this); + return div.toString(radix) + rem.toInt().toString(radix); + } else { + return '-' + this.negate().toString(radix); + } + } + + // Do several (6) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = Long.fromNumber(Math.pow(radix, 6)); + + var rem = this; + var result = ''; + while (true) { + var remDiv = rem.div(radixToPower); + var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt(); + var digits = intval.toString(radix); + + rem = remDiv; + if (rem.isZero()) { + return digits + result; + } else { + while (digits.length < 6) { + digits = '0' + digits; + } + result = '' + digits + result; + } + } +}; + +/** + * Return the high 32-bits value. + * + * @return {Number} the high 32-bits as a signed value. + * @api public + */ +Long.prototype.getHighBits = function() { + return this.high_; +}; + +/** + * Return the low 32-bits value. + * + * @return {Number} the low 32-bits as a signed value. + * @api public + */ +Long.prototype.getLowBits = function() { + return this.low_; +}; + +/** + * Return the low unsigned 32-bits value. + * + * @return {Number} the low 32-bits as an unsigned value. + * @api public + */ +Long.prototype.getLowBitsUnsigned = function() { + return (this.low_ >= 0) ? + this.low_ : Long.TWO_PWR_32_DBL_ + this.low_; +}; + +/** + * Returns the number of bits needed to represent the absolute value of this Long. + * + * @return {Number} Returns the number of bits needed to represent the absolute value of this Long. + * @api public + */ +Long.prototype.getNumBitsAbs = function() { + if (this.isNegative()) { + if (this.equals(Long.MIN_VALUE)) { + return 64; + } else { + return this.negate().getNumBitsAbs(); + } + } else { + var val = this.high_ != 0 ? this.high_ : this.low_; + for (var bit = 31; bit > 0; bit--) { + if ((val & (1 << bit)) != 0) { + break; + } + } + return this.high_ != 0 ? bit + 33 : bit + 1; + } +}; + +/** + * Return whether this value is zero. + * + * @return {Boolean} whether this value is zero. + * @api public + */ +Long.prototype.isZero = function() { + return this.high_ == 0 && this.low_ == 0; +}; + +/** + * Return whether this value is negative. + * + * @return {Boolean} whether this value is negative. + * @api public + */ +Long.prototype.isNegative = function() { + return this.high_ < 0; +}; + +/** + * Return whether this value is odd. + * + * @return {Boolean} whether this value is odd. + * @api public + */ +Long.prototype.isOdd = function() { + return (this.low_ & 1) == 1; +}; + +/** + * Return whether this Long equals the other + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long equals the other + * @api public + */ +Long.prototype.equals = function(other) { + return (this.high_ == other.high_) && (this.low_ == other.low_); +}; + +/** + * Return whether this Long does not equal the other. + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long does not equal the other. + * @api public + */ +Long.prototype.notEquals = function(other) { + return (this.high_ != other.high_) || (this.low_ != other.low_); +}; + +/** + * Return whether this Long is less than the other. + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long is less than the other. + * @api public + */ +Long.prototype.lessThan = function(other) { + return this.compare(other) < 0; +}; + +/** + * Return whether this Long is less than or equal to the other. + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long is less than or equal to the other. + * @api public + */ +Long.prototype.lessThanOrEqual = function(other) { + return this.compare(other) <= 0; +}; + +/** + * Return whether this Long is greater than the other. + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long is greater than the other. + * @api public + */ +Long.prototype.greaterThan = function(other) { + return this.compare(other) > 0; +}; + +/** + * Return whether this Long is greater than or equal to the other. + * + * @param {Long} other Long to compare against. + * @return {Boolean} whether this Long is greater than or equal to the other. + * @api public + */ +Long.prototype.greaterThanOrEqual = function(other) { + return this.compare(other) >= 0; +}; + +/** + * Compares this Long with the given one. + * + * @param {Long} other Long to compare against. + * @return {Boolean} 0 if they are the same, 1 if the this is greater, and -1 if the given one is greater. + * @api public + */ +Long.prototype.compare = function(other) { + if (this.equals(other)) { + return 0; + } + + var thisNeg = this.isNegative(); + var otherNeg = other.isNegative(); + if (thisNeg && !otherNeg) { + return -1; + } + if (!thisNeg && otherNeg) { + return 1; + } + + // at this point, the signs are the same, so subtraction will not overflow + if (this.subtract(other).isNegative()) { + return -1; + } else { + return 1; + } +}; + +/** + * The negation of this value. + * + * @return {Long} the negation of this value. + * @api public + */ +Long.prototype.negate = function() { + if (this.equals(Long.MIN_VALUE)) { + return Long.MIN_VALUE; + } else { + return this.not().add(Long.ONE); + } +}; + +/** + * Returns the sum of this and the given Long. + * + * @param {Long} other Long to add to this one. + * @return {Long} the sum of this and the given Long. + * @api public + */ +Long.prototype.add = function(other) { + // Divide each number into 4 chunks of 16 bits, and then sum the chunks. + + var a48 = this.high_ >>> 16; + var a32 = this.high_ & 0xFFFF; + var a16 = this.low_ >>> 16; + var a00 = this.low_ & 0xFFFF; + + var b48 = other.high_ >>> 16; + var b32 = other.high_ & 0xFFFF; + var b16 = other.low_ >>> 16; + var b00 = other.low_ & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 + b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 + b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 + b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 + b48; + c48 &= 0xFFFF; + return Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32); +}; + +/** + * Returns the difference of this and the given Long. + * + * @param {Long} other Long to subtract from this. + * @return {Long} the difference of this and the given Long. + * @api public + */ +Long.prototype.subtract = function(other) { + return this.add(other.negate()); +}; + +/** + * Returns the product of this and the given Long. + * + * @param {Long} other Long to multiply with this. + * @return {Long} the product of this and the other. + * @api public + */ +Long.prototype.multiply = function(other) { + if (this.isZero()) { + return Long.ZERO; + } else if (other.isZero()) { + return Long.ZERO; + } + + if (this.equals(Long.MIN_VALUE)) { + return other.isOdd() ? Long.MIN_VALUE : Long.ZERO; + } else if (other.equals(Long.MIN_VALUE)) { + return this.isOdd() ? Long.MIN_VALUE : Long.ZERO; + } + + if (this.isNegative()) { + if (other.isNegative()) { + return this.negate().multiply(other.negate()); + } else { + return this.negate().multiply(other).negate(); + } + } else if (other.isNegative()) { + return this.multiply(other.negate()).negate(); + } + + // If both Longs are small, use float multiplication + if (this.lessThan(Long.TWO_PWR_24_) && + other.lessThan(Long.TWO_PWR_24_)) { + return Long.fromNumber(this.toNumber() * other.toNumber()); + } + + // Divide each Long into 4 chunks of 16 bits, and then add up 4x4 products. + // We can skip products that would overflow. + + var a48 = this.high_ >>> 16; + var a32 = this.high_ & 0xFFFF; + var a16 = this.low_ >>> 16; + var a00 = this.low_ & 0xFFFF; + + var b48 = other.high_ >>> 16; + var b32 = other.high_ & 0xFFFF; + var b16 = other.low_ >>> 16; + var b00 = other.low_ & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 * b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 * b00; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c16 += a00 * b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 * b00; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a16 * b16; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a00 * b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; + c48 &= 0xFFFF; + return Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32); +}; + +/** + * Returns this Long divided by the given one. + * + * @param {Long} other Long by which to divide. + * @return {Long} this Long divided by the given one. + * @api public + */ +Long.prototype.div = function(other) { + if (other.isZero()) { + throw Error('division by zero'); + } else if (this.isZero()) { + return Long.ZERO; + } + + if (this.equals(Long.MIN_VALUE)) { + if (other.equals(Long.ONE) || + other.equals(Long.NEG_ONE)) { + return Long.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE + } else if (other.equals(Long.MIN_VALUE)) { + return Long.ONE; + } else { + // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. + var halfThis = this.shiftRight(1); + var approx = halfThis.div(other).shiftLeft(1); + if (approx.equals(Long.ZERO)) { + return other.isNegative() ? Long.ONE : Long.NEG_ONE; + } else { + var rem = this.subtract(other.multiply(approx)); + var result = approx.add(rem.div(other)); + return result; + } + } + } else if (other.equals(Long.MIN_VALUE)) { + return Long.ZERO; + } + + if (this.isNegative()) { + if (other.isNegative()) { + return this.negate().div(other.negate()); + } else { + return this.negate().div(other).negate(); + } + } else if (other.isNegative()) { + return this.div(other.negate()).negate(); + } + + // Repeat the following until the remainder is less than other: find a + // floating-point that approximates remainder / other *from below*, add this + // into the result, and subtract it from the remainder. It is critical that + // the approximate value is less than or equal to the real value so that the + // remainder never becomes negative. + var res = Long.ZERO; + var rem = this; + while (rem.greaterThanOrEqual(other)) { + // Approximate the result of division. This may be a little greater or + // smaller than the actual value. + var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())); + + // We will tweak the approximate result by changing it in the 48-th digit or + // the smallest non-fractional digit, whichever is larger. + var log2 = Math.ceil(Math.log(approx) / Math.LN2); + var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48); + + // Decrease the approximation until it is smaller than the remainder. Note + // that if it is too large, the product overflows and is negative. + var approxRes = Long.fromNumber(approx); + var approxRem = approxRes.multiply(other); + while (approxRem.isNegative() || approxRem.greaterThan(rem)) { + approx -= delta; + approxRes = Long.fromNumber(approx); + approxRem = approxRes.multiply(other); + } + + // We know the answer can't be zero... and actually, zero would cause + // infinite recursion since we would make no progress. + if (approxRes.isZero()) { + approxRes = Long.ONE; + } + + res = res.add(approxRes); + rem = rem.subtract(approxRem); + } + return res; +}; + +/** + * Returns this Long modulo the given one. + * + * @param {Long} other Long by which to mod. + * @return {Long} this Long modulo the given one. + * @api public + */ +Long.prototype.modulo = function(other) { + return this.subtract(this.div(other).multiply(other)); +}; + +/** + * The bitwise-NOT of this value. + * + * @return {Long} the bitwise-NOT of this value. + * @api public + */ +Long.prototype.not = function() { + return Long.fromBits(~this.low_, ~this.high_); +}; + +/** + * Returns the bitwise-AND of this Long and the given one. + * + * @param {Long} other the Long with which to AND. + * @return {Long} the bitwise-AND of this and the other. + * @api public + */ +Long.prototype.and = function(other) { + return Long.fromBits(this.low_ & other.low_, this.high_ & other.high_); +}; + +/** + * Returns the bitwise-OR of this Long and the given one. + * + * @param {Long} other the Long with which to OR. + * @return {Long} the bitwise-OR of this and the other. + * @api public + */ +Long.prototype.or = function(other) { + return Long.fromBits(this.low_ | other.low_, this.high_ | other.high_); +}; + +/** + * Returns the bitwise-XOR of this Long and the given one. + * + * @param {Long} other the Long with which to XOR. + * @return {Long} the bitwise-XOR of this and the other. + * @api public + */ +Long.prototype.xor = function(other) { + return Long.fromBits(this.low_ ^ other.low_, this.high_ ^ other.high_); +}; + +/** + * Returns this Long with bits shifted to the left by the given amount. + * + * @param {Number} numBits the number of bits by which to shift. + * @return {Long} this shifted to the left by the given amount. + * @api public + */ +Long.prototype.shiftLeft = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var low = this.low_; + if (numBits < 32) { + var high = this.high_; + return Long.fromBits( + low << numBits, + (high << numBits) | (low >>> (32 - numBits))); + } else { + return Long.fromBits(0, low << (numBits - 32)); + } + } +}; + +/** + * Returns this Long with bits shifted to the right by the given amount. + * + * @param {Number} numBits the number of bits by which to shift. + * @return {Long} this shifted to the right by the given amount. + * @api public + */ +Long.prototype.shiftRight = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var high = this.high_; + if (numBits < 32) { + var low = this.low_; + return Long.fromBits( + (low >>> numBits) | (high << (32 - numBits)), + high >> numBits); + } else { + return Long.fromBits( + high >> (numBits - 32), + high >= 0 ? 0 : -1); + } + } +}; + +/** + * Returns this Long with bits shifted to the right by the given amount, with the new top bits matching the current sign bit. + * + * @param {Number} numBits the number of bits by which to shift. + * @return {Long} this shifted to the right by the given amount, with zeros placed into the new leading bits. + * @api public + */ +Long.prototype.shiftRightUnsigned = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var high = this.high_; + if (numBits < 32) { + var low = this.low_; + return Long.fromBits( + (low >>> numBits) | (high << (32 - numBits)), + high >>> numBits); + } else if (numBits == 32) { + return Long.fromBits(high, 0); + } else { + return Long.fromBits(high >>> (numBits - 32), 0); + } + } +}; + +/** + * Returns a Long representing the given (32-bit) integer value. + * + * @param {Number} value the 32-bit integer in question. + * @return {Long} the corresponding Long value. + * @api public + */ +Long.fromInt = function(value) { + if (-128 <= value && value < 128) { + var cachedObj = Long.INT_CACHE_[value]; + if (cachedObj) { + return cachedObj; + } + } + + var obj = new Long(value | 0, value < 0 ? -1 : 0); + if (-128 <= value && value < 128) { + Long.INT_CACHE_[value] = obj; + } + return obj; +}; + +/** + * Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned. + * + * @param {Number} value the number in question. + * @return {Long} the corresponding Long value. + * @api public + */ +Long.fromNumber = function(value) { + if (isNaN(value) || !isFinite(value)) { + return Long.ZERO; + } else if (value <= -Long.TWO_PWR_63_DBL_) { + return Long.MIN_VALUE; + } else if (value + 1 >= Long.TWO_PWR_63_DBL_) { + return Long.MAX_VALUE; + } else if (value < 0) { + return Long.fromNumber(-value).negate(); + } else { + return new Long( + (value % Long.TWO_PWR_32_DBL_) | 0, + (value / Long.TWO_PWR_32_DBL_) | 0); + } +}; + +/** + * Returns a Long representing the 64-bit integer that comes by concatenating the given high and low bits. Each is assumed to use 32 bits. + * + * @param {Number} lowBits the low 32-bits. + * @param {Number} highBits the high 32-bits. + * @return {Long} the corresponding Long value. + * @api public + */ +Long.fromBits = function(lowBits, highBits) { + return new Long(lowBits, highBits); +}; + +/** + * Returns a Long representation of the given string, written using the given radix. + * + * @param {String} str the textual representation of the Long. + * @param {Number} opt_radix the radix in which the text is written. + * @return {Long} the corresponding Long value. + * @api public + */ +Long.fromString = function(str, opt_radix) { + if (str.length == 0) { + throw Error('number format error: empty string'); + } + + var radix = opt_radix || 10; + if (radix < 2 || 36 < radix) { + throw Error('radix out of range: ' + radix); + } + + if (str.charAt(0) == '-') { + return Long.fromString(str.substring(1), radix).negate(); + } else if (str.indexOf('-') >= 0) { + throw Error('number format error: interior "-" character: ' + str); + } + + // Do several (8) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = Long.fromNumber(Math.pow(radix, 8)); + + var result = Long.ZERO; + for (var i = 0; i < str.length; i += 8) { + var size = Math.min(8, str.length - i); + var value = parseInt(str.substring(i, i + size), radix); + if (size < 8) { + var power = Long.fromNumber(Math.pow(radix, size)); + result = result.multiply(power).add(Long.fromNumber(value)); + } else { + result = result.multiply(radixToPower); + result = result.add(Long.fromNumber(value)); + } + } + return result; +}; + +// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the +// from* methods on which they depend. + + +/** + * A cache of the Long representations of small integer values. + * @type {Object} + * @api private + */ +Long.INT_CACHE_ = {}; + +// NOTE: the compiler should inline these constant values below and then remove +// these variables, so there should be no runtime penalty for these. + +/** + * Number used repeated below in calculations. This must appear before the + * first call to any from* function below. + * @type {number} + * @api private + */ +Long.TWO_PWR_16_DBL_ = 1 << 16; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_24_DBL_ = 1 << 24; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_32_DBL_ = Long.TWO_PWR_16_DBL_ * Long.TWO_PWR_16_DBL_; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_31_DBL_ = Long.TWO_PWR_32_DBL_ / 2; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_48_DBL_ = Long.TWO_PWR_32_DBL_ * Long.TWO_PWR_16_DBL_; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_64_DBL_ = Long.TWO_PWR_32_DBL_ * Long.TWO_PWR_32_DBL_; + +/** + * @type {number} + * @api private + */ +Long.TWO_PWR_63_DBL_ = Long.TWO_PWR_64_DBL_ / 2; + +/** @type {Long} */ +Long.ZERO = Long.fromInt(0); + +/** @type {Long} */ +Long.ONE = Long.fromInt(1); + +/** @type {Long} */ +Long.NEG_ONE = Long.fromInt(-1); + +/** @type {Long} */ +Long.MAX_VALUE = + Long.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); + +/** @type {Long} */ +Long.MIN_VALUE = Long.fromBits(0, 0x80000000 | 0); + +/** + * @type {Long} + * @api private + */ +Long.TWO_PWR_24_ = Long.fromInt(1 << 24); + +/** + * Expose. + */ +exports.Long = Long; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/max_key.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/max_key.js new file mode 100644 index 0000000..0825408 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/max_key.js @@ -0,0 +1,13 @@ +/** + * A class representation of the BSON MaxKey type. + * + * @class Represents the BSON MaxKey type. + * @return {MaxKey} + */ +function MaxKey() { + if(!(this instanceof MaxKey)) return new MaxKey(); + + this._bsontype = 'MaxKey'; +} + +exports.MaxKey = MaxKey; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/min_key.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/min_key.js new file mode 100644 index 0000000..230c2e6 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/min_key.js @@ -0,0 +1,13 @@ +/** + * A class representation of the BSON MinKey type. + * + * @class Represents the BSON MinKey type. + * @return {MinKey} + */ +function MinKey() { + if(!(this instanceof MinKey)) return new MinKey(); + + this._bsontype = 'MinKey'; +} + +exports.MinKey = MinKey; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/objectid.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/objectid.js new file mode 100644 index 0000000..183bbc3 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/objectid.js @@ -0,0 +1,253 @@ +/** + * Module dependencies. + */ +var BinaryParser = require('./binary_parser').BinaryParser; + +/** + * Machine id. + * + * Create a random 3-byte value (i.e. unique for this + * process). Other drivers use a md5 of the machine id here, but + * that would mean an asyc call to gethostname, so we don't bother. + */ +var MACHINE_ID = parseInt(Math.random() * 0xFFFFFF, 10); + +// Regular expression that checks for hex value +var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$"); + +/** +* Create a new ObjectID instance +* +* @class Represents the BSON ObjectID type +* @param {String|Number} id Can be a 24 byte hex string, 12 byte binary string or a Number. +* @return {Object} instance of ObjectID. +*/ +var ObjectID = function ObjectID(id, _hex) { + if(!(this instanceof ObjectID)) return new ObjectID(id, _hex); + + this._bsontype = 'ObjectID'; + var __id = null; + + // Throw an error if it's not a valid setup + if(id != null && 'number' != typeof id && (id.length != 12 && id.length != 24)) + throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters"); + + // Generate id based on the input + if(id == null || typeof id == 'number') { + // convert to 12 byte binary string + this.id = this.generate(id); + } else if(id != null && id.length === 12) { + // assume 12 byte string + this.id = id; + } else if(checkForHexRegExp.test(id)) { + return ObjectID.createFromHexString(id); + } else { + throw new Error("Value passed in is not a valid 24 character hex string"); + } + + if(ObjectID.cacheHexString) this.__id = this.toHexString(); +}; + +// Allow usage of ObjectId aswell as ObjectID +var ObjectId = ObjectID; + +/** +* Return the ObjectID id as a 24 byte hex string representation +* +* @return {String} return the 24 byte hex string representation. +* @api public +*/ +ObjectID.prototype.toHexString = function() { + if(ObjectID.cacheHexString && this.__id) return this.__id; + + var hexString = '' + , number + , value; + + for (var index = 0, len = this.id.length; index < len; index++) { + value = BinaryParser.toByte(this.id[index]); + number = value <= 15 + ? '0' + value.toString(16) + : value.toString(16); + hexString = hexString + number; + } + + if(ObjectID.cacheHexString) this.__id = hexString; + return hexString; +}; + +/** +* Update the ObjectID index used in generating new ObjectID's on the driver +* +* @return {Number} returns next index value. +* @api private +*/ +ObjectID.prototype.get_inc = function() { + return ObjectID.index = (ObjectID.index + 1) % 0xFFFFFF; +}; + +/** +* Update the ObjectID index used in generating new ObjectID's on the driver +* +* @return {Number} returns next index value. +* @api private +*/ +ObjectID.prototype.getInc = function() { + return this.get_inc(); +}; + +/** +* Generate a 12 byte id string used in ObjectID's +* +* @param {Number} [time] optional parameter allowing to pass in a second based timestamp. +* @return {String} return the 12 byte id binary string. +* @api private +*/ +ObjectID.prototype.generate = function(time) { + if ('number' == typeof time) { + var time4Bytes = BinaryParser.encodeInt(time, 32, true, true); + /* for time-based ObjectID the bytes following the time will be zeroed */ + var machine3Bytes = BinaryParser.encodeInt(MACHINE_ID, 24, false); + var pid2Bytes = BinaryParser.fromShort(typeof process === 'undefined' ? Math.floor(Math.random() * 100000) : process.pid); + var index3Bytes = BinaryParser.encodeInt(this.get_inc(), 24, false, true); + } else { + var unixTime = parseInt(Date.now()/1000,10); + var time4Bytes = BinaryParser.encodeInt(unixTime, 32, true, true); + var machine3Bytes = BinaryParser.encodeInt(MACHINE_ID, 24, false); + var pid2Bytes = BinaryParser.fromShort(typeof process === 'undefined' ? Math.floor(Math.random() * 100000) : process.pid); + var index3Bytes = BinaryParser.encodeInt(this.get_inc(), 24, false, true); + } + + return time4Bytes + machine3Bytes + pid2Bytes + index3Bytes; +}; + +/** +* Converts the id into a 24 byte hex string for printing +* +* @return {String} return the 24 byte hex string representation. +* @api private +*/ +ObjectID.prototype.toString = function() { + return this.toHexString(); +}; + +/** +* Converts to a string representation of this Id. +* +* @return {String} return the 24 byte hex string representation. +* @api private +*/ +ObjectID.prototype.inspect = ObjectID.prototype.toString; + +/** +* Converts to its JSON representation. +* +* @return {String} return the 24 byte hex string representation. +* @api private +*/ +ObjectID.prototype.toJSON = function() { + return this.toHexString(); +}; + +/** +* Compares the equality of this ObjectID with `otherID`. +* +* @param {Object} otherID ObjectID instance to compare against. +* @return {Bool} the result of comparing two ObjectID's +* @api public +*/ +ObjectID.prototype.equals = function equals (otherID) { + var id = (otherID instanceof ObjectID || otherID.toHexString) + ? otherID.id + : ObjectID.createFromHexString(otherID).id; + + return this.id === id; +} + +/** +* Returns the generation date (accurate up to the second) that this ID was generated. +* +* @return {Date} the generation date +* @api public +*/ +ObjectID.prototype.getTimestamp = function() { + var timestamp = new Date(); + timestamp.setTime(Math.floor(BinaryParser.decodeInt(this.id.substring(0,4), 32, true, true)) * 1000); + return timestamp; +} + +/** +* @ignore +* @api private +*/ +ObjectID.index = 0; + +ObjectID.createPk = function createPk () { + return new ObjectID(); +}; + +/** +* Creates an ObjectID from a second based number, with the rest of the ObjectID zeroed out. Used for comparisons or sorting the ObjectID. +* +* @param {Number} time an integer number representing a number of seconds. +* @return {ObjectID} return the created ObjectID +* @api public +*/ +ObjectID.createFromTime = function createFromTime (time) { + var id = BinaryParser.encodeInt(time, 32, true, true) + + BinaryParser.encodeInt(0, 64, true, true); + return new ObjectID(id); +}; + +/** +* Creates an ObjectID from a hex string representation of an ObjectID. +* +* @param {String} hexString create a ObjectID from a passed in 24 byte hexstring. +* @return {ObjectID} return the created ObjectID +* @api public +*/ +ObjectID.createFromHexString = function createFromHexString (hexString) { + // Throw an error if it's not a valid setup + if(typeof hexString === 'undefined' || hexString != null && hexString.length != 24) + throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters"); + + var len = hexString.length; + + if(len > 12*2) { + throw new Error('Id cannot be longer than 12 bytes'); + } + + var result = '' + , string + , number; + + for (var index = 0; index < len; index += 2) { + string = hexString.substr(index, 2); + number = parseInt(string, 16); + result += BinaryParser.fromByte(number); + } + + return new ObjectID(result, hexString); +}; + +/** +* @ignore +*/ +Object.defineProperty(ObjectID.prototype, "generationTime", { + enumerable: true + , get: function () { + return Math.floor(BinaryParser.decodeInt(this.id.substring(0,4), 32, true, true)); + } + , set: function (value) { + var value = BinaryParser.encodeInt(value, 32, true, true); + this.id = value + this.id.substr(4); + // delete this.__id; + this.toHexString(); + } +}); + +/** + * Expose. + */ +exports.ObjectID = ObjectID; +exports.ObjectId = ObjectID; diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/symbol.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/symbol.js new file mode 100644 index 0000000..8e2838d --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/symbol.js @@ -0,0 +1,48 @@ +/** + * A class representation of the BSON Symbol type. + * + * @class Represents the BSON Symbol type. + * @param {String} value the string representing the symbol. + * @return {Symbol} + */ +function Symbol(value) { + if(!(this instanceof Symbol)) return new Symbol(value); + this._bsontype = 'Symbol'; + this.value = value; +} + +/** + * Access the wrapped string value. + * + * @return {String} returns the wrapped string. + * @api public + */ +Symbol.prototype.valueOf = function() { + return this.value; +}; + +/** + * @ignore + * @api private + */ +Symbol.prototype.toString = function() { + return this.value; +} + +/** + * @ignore + * @api private + */ +Symbol.prototype.inspect = function() { + return this.value; +} + +/** + * @ignore + * @api private + */ +Symbol.prototype.toJSON = function() { + return this.value; +} + +exports.Symbol = Symbol; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/timestamp.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/timestamp.js new file mode 100644 index 0000000..c650d15 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/lib/bson/timestamp.js @@ -0,0 +1,853 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Copyright 2009 Google Inc. All Rights Reserved + +/** + * Defines a Timestamp class for representing a 64-bit two's-complement + * integer value, which faithfully simulates the behavior of a Java "Timestamp". This + * implementation is derived from TimestampLib in GWT. + * + * Constructs a 64-bit two's-complement integer, given its low and high 32-bit + * values as *signed* integers. See the from* functions below for more + * convenient ways of constructing Timestamps. + * + * The internal representation of a Timestamp is the two given signed, 32-bit values. + * We use 32-bit pieces because these are the size of integers on which + * Javascript performs bit-operations. For operations like addition and + * multiplication, we split each number into 16-bit pieces, which can easily be + * multiplied within Javascript's floating-point representation without overflow + * or change in sign. + * + * In the algorithms below, we frequently reduce the negative case to the + * positive case by negating the input(s) and then post-processing the result. + * Note that we must ALWAYS check specially whether those values are MIN_VALUE + * (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as + * a positive number, it overflows back into a negative). Not handling this + * case would often result in infinite recursion. + * + * @class Represents the BSON Timestamp type. + * @param {Number} low the low (signed) 32 bits of the Timestamp. + * @param {Number} high the high (signed) 32 bits of the Timestamp. + */ +function Timestamp(low, high) { + if(!(this instanceof Timestamp)) return new Timestamp(low, high); + this._bsontype = 'Timestamp'; + /** + * @type {number} + * @api private + */ + this.low_ = low | 0; // force into 32 signed bits. + + /** + * @type {number} + * @api private + */ + this.high_ = high | 0; // force into 32 signed bits. +}; + +/** + * Return the int value. + * + * @return {Number} the value, assuming it is a 32-bit integer. + * @api public + */ +Timestamp.prototype.toInt = function() { + return this.low_; +}; + +/** + * Return the Number value. + * + * @return {Number} the closest floating-point representation to this value. + * @api public + */ +Timestamp.prototype.toNumber = function() { + return this.high_ * Timestamp.TWO_PWR_32_DBL_ + + this.getLowBitsUnsigned(); +}; + +/** + * Return the JSON value. + * + * @return {String} the JSON representation. + * @api public + */ +Timestamp.prototype.toJSON = function() { + return this.toString(); +} + +/** + * Return the String value. + * + * @param {Number} [opt_radix] the radix in which the text should be written. + * @return {String} the textual representation of this value. + * @api public + */ +Timestamp.prototype.toString = function(opt_radix) { + var radix = opt_radix || 10; + if (radix < 2 || 36 < radix) { + throw Error('radix out of range: ' + radix); + } + + if (this.isZero()) { + return '0'; + } + + if (this.isNegative()) { + if (this.equals(Timestamp.MIN_VALUE)) { + // We need to change the Timestamp value before it can be negated, so we remove + // the bottom-most digit in this base and then recurse to do the rest. + var radixTimestamp = Timestamp.fromNumber(radix); + var div = this.div(radixTimestamp); + var rem = div.multiply(radixTimestamp).subtract(this); + return div.toString(radix) + rem.toInt().toString(radix); + } else { + return '-' + this.negate().toString(radix); + } + } + + // Do several (6) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = Timestamp.fromNumber(Math.pow(radix, 6)); + + var rem = this; + var result = ''; + while (true) { + var remDiv = rem.div(radixToPower); + var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt(); + var digits = intval.toString(radix); + + rem = remDiv; + if (rem.isZero()) { + return digits + result; + } else { + while (digits.length < 6) { + digits = '0' + digits; + } + result = '' + digits + result; + } + } +}; + +/** + * Return the high 32-bits value. + * + * @return {Number} the high 32-bits as a signed value. + * @api public + */ +Timestamp.prototype.getHighBits = function() { + return this.high_; +}; + +/** + * Return the low 32-bits value. + * + * @return {Number} the low 32-bits as a signed value. + * @api public + */ +Timestamp.prototype.getLowBits = function() { + return this.low_; +}; + +/** + * Return the low unsigned 32-bits value. + * + * @return {Number} the low 32-bits as an unsigned value. + * @api public + */ +Timestamp.prototype.getLowBitsUnsigned = function() { + return (this.low_ >= 0) ? + this.low_ : Timestamp.TWO_PWR_32_DBL_ + this.low_; +}; + +/** + * Returns the number of bits needed to represent the absolute value of this Timestamp. + * + * @return {Number} Returns the number of bits needed to represent the absolute value of this Timestamp. + * @api public + */ +Timestamp.prototype.getNumBitsAbs = function() { + if (this.isNegative()) { + if (this.equals(Timestamp.MIN_VALUE)) { + return 64; + } else { + return this.negate().getNumBitsAbs(); + } + } else { + var val = this.high_ != 0 ? this.high_ : this.low_; + for (var bit = 31; bit > 0; bit--) { + if ((val & (1 << bit)) != 0) { + break; + } + } + return this.high_ != 0 ? bit + 33 : bit + 1; + } +}; + +/** + * Return whether this value is zero. + * + * @return {Boolean} whether this value is zero. + * @api public + */ +Timestamp.prototype.isZero = function() { + return this.high_ == 0 && this.low_ == 0; +}; + +/** + * Return whether this value is negative. + * + * @return {Boolean} whether this value is negative. + * @api public + */ +Timestamp.prototype.isNegative = function() { + return this.high_ < 0; +}; + +/** + * Return whether this value is odd. + * + * @return {Boolean} whether this value is odd. + * @api public + */ +Timestamp.prototype.isOdd = function() { + return (this.low_ & 1) == 1; +}; + +/** + * Return whether this Timestamp equals the other + * + * @param {Timestamp} other Timestamp to compare against. + * @return {Boolean} whether this Timestamp equals the other + * @api public + */ +Timestamp.prototype.equals = function(other) { + return (this.high_ == other.high_) && (this.low_ == other.low_); +}; + +/** + * Return whether this Timestamp does not equal the other. + * + * @param {Timestamp} other Timestamp to compare against. + * @return {Boolean} whether this Timestamp does not equal the other. + * @api public + */ +Timestamp.prototype.notEquals = function(other) { + return (this.high_ != other.high_) || (this.low_ != other.low_); +}; + +/** + * Return whether this Timestamp is less than the other. + * + * @param {Timestamp} other Timestamp to compare against. + * @return {Boolean} whether this Timestamp is less than the other. + * @api public + */ +Timestamp.prototype.lessThan = function(other) { + return this.compare(other) < 0; +}; + +/** + * Return whether this Timestamp is less than or equal to the other. + * + * @param {Timestamp} other Timestamp to compare against. + * @return {Boolean} whether this Timestamp is less than or equal to the other. + * @api public + */ +Timestamp.prototype.lessThanOrEqual = function(other) { + return this.compare(other) <= 0; +}; + +/** + * Return whether this Timestamp is greater than the other. + * + * @param {Timestamp} other Timestamp to compare against. + * @return {Boolean} whether this Timestamp is greater than the other. + * @api public + */ +Timestamp.prototype.greaterThan = function(other) { + return this.compare(other) > 0; +}; + +/** + * Return whether this Timestamp is greater than or equal to the other. + * + * @param {Timestamp} other Timestamp to compare against. + * @return {Boolean} whether this Timestamp is greater than or equal to the other. + * @api public + */ +Timestamp.prototype.greaterThanOrEqual = function(other) { + return this.compare(other) >= 0; +}; + +/** + * Compares this Timestamp with the given one. + * + * @param {Timestamp} other Timestamp to compare against. + * @return {Boolean} 0 if they are the same, 1 if the this is greater, and -1 if the given one is greater. + * @api public + */ +Timestamp.prototype.compare = function(other) { + if (this.equals(other)) { + return 0; + } + + var thisNeg = this.isNegative(); + var otherNeg = other.isNegative(); + if (thisNeg && !otherNeg) { + return -1; + } + if (!thisNeg && otherNeg) { + return 1; + } + + // at this point, the signs are the same, so subtraction will not overflow + if (this.subtract(other).isNegative()) { + return -1; + } else { + return 1; + } +}; + +/** + * The negation of this value. + * + * @return {Timestamp} the negation of this value. + * @api public + */ +Timestamp.prototype.negate = function() { + if (this.equals(Timestamp.MIN_VALUE)) { + return Timestamp.MIN_VALUE; + } else { + return this.not().add(Timestamp.ONE); + } +}; + +/** + * Returns the sum of this and the given Timestamp. + * + * @param {Timestamp} other Timestamp to add to this one. + * @return {Timestamp} the sum of this and the given Timestamp. + * @api public + */ +Timestamp.prototype.add = function(other) { + // Divide each number into 4 chunks of 16 bits, and then sum the chunks. + + var a48 = this.high_ >>> 16; + var a32 = this.high_ & 0xFFFF; + var a16 = this.low_ >>> 16; + var a00 = this.low_ & 0xFFFF; + + var b48 = other.high_ >>> 16; + var b32 = other.high_ & 0xFFFF; + var b16 = other.low_ >>> 16; + var b00 = other.low_ & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 + b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 + b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 + b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 + b48; + c48 &= 0xFFFF; + return Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32); +}; + +/** + * Returns the difference of this and the given Timestamp. + * + * @param {Timestamp} other Timestamp to subtract from this. + * @return {Timestamp} the difference of this and the given Timestamp. + * @api public + */ +Timestamp.prototype.subtract = function(other) { + return this.add(other.negate()); +}; + +/** + * Returns the product of this and the given Timestamp. + * + * @param {Timestamp} other Timestamp to multiply with this. + * @return {Timestamp} the product of this and the other. + * @api public + */ +Timestamp.prototype.multiply = function(other) { + if (this.isZero()) { + return Timestamp.ZERO; + } else if (other.isZero()) { + return Timestamp.ZERO; + } + + if (this.equals(Timestamp.MIN_VALUE)) { + return other.isOdd() ? Timestamp.MIN_VALUE : Timestamp.ZERO; + } else if (other.equals(Timestamp.MIN_VALUE)) { + return this.isOdd() ? Timestamp.MIN_VALUE : Timestamp.ZERO; + } + + if (this.isNegative()) { + if (other.isNegative()) { + return this.negate().multiply(other.negate()); + } else { + return this.negate().multiply(other).negate(); + } + } else if (other.isNegative()) { + return this.multiply(other.negate()).negate(); + } + + // If both Timestamps are small, use float multiplication + if (this.lessThan(Timestamp.TWO_PWR_24_) && + other.lessThan(Timestamp.TWO_PWR_24_)) { + return Timestamp.fromNumber(this.toNumber() * other.toNumber()); + } + + // Divide each Timestamp into 4 chunks of 16 bits, and then add up 4x4 products. + // We can skip products that would overflow. + + var a48 = this.high_ >>> 16; + var a32 = this.high_ & 0xFFFF; + var a16 = this.low_ >>> 16; + var a00 = this.low_ & 0xFFFF; + + var b48 = other.high_ >>> 16; + var b32 = other.high_ & 0xFFFF; + var b16 = other.low_ >>> 16; + var b00 = other.low_ & 0xFFFF; + + var c48 = 0, c32 = 0, c16 = 0, c00 = 0; + c00 += a00 * b00; + c16 += c00 >>> 16; + c00 &= 0xFFFF; + c16 += a16 * b00; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c16 += a00 * b16; + c32 += c16 >>> 16; + c16 &= 0xFFFF; + c32 += a32 * b00; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a16 * b16; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c32 += a00 * b32; + c48 += c32 >>> 16; + c32 &= 0xFFFF; + c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; + c48 &= 0xFFFF; + return Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32); +}; + +/** + * Returns this Timestamp divided by the given one. + * + * @param {Timestamp} other Timestamp by which to divide. + * @return {Timestamp} this Timestamp divided by the given one. + * @api public + */ +Timestamp.prototype.div = function(other) { + if (other.isZero()) { + throw Error('division by zero'); + } else if (this.isZero()) { + return Timestamp.ZERO; + } + + if (this.equals(Timestamp.MIN_VALUE)) { + if (other.equals(Timestamp.ONE) || + other.equals(Timestamp.NEG_ONE)) { + return Timestamp.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE + } else if (other.equals(Timestamp.MIN_VALUE)) { + return Timestamp.ONE; + } else { + // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. + var halfThis = this.shiftRight(1); + var approx = halfThis.div(other).shiftLeft(1); + if (approx.equals(Timestamp.ZERO)) { + return other.isNegative() ? Timestamp.ONE : Timestamp.NEG_ONE; + } else { + var rem = this.subtract(other.multiply(approx)); + var result = approx.add(rem.div(other)); + return result; + } + } + } else if (other.equals(Timestamp.MIN_VALUE)) { + return Timestamp.ZERO; + } + + if (this.isNegative()) { + if (other.isNegative()) { + return this.negate().div(other.negate()); + } else { + return this.negate().div(other).negate(); + } + } else if (other.isNegative()) { + return this.div(other.negate()).negate(); + } + + // Repeat the following until the remainder is less than other: find a + // floating-point that approximates remainder / other *from below*, add this + // into the result, and subtract it from the remainder. It is critical that + // the approximate value is less than or equal to the real value so that the + // remainder never becomes negative. + var res = Timestamp.ZERO; + var rem = this; + while (rem.greaterThanOrEqual(other)) { + // Approximate the result of division. This may be a little greater or + // smaller than the actual value. + var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())); + + // We will tweak the approximate result by changing it in the 48-th digit or + // the smallest non-fractional digit, whichever is larger. + var log2 = Math.ceil(Math.log(approx) / Math.LN2); + var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48); + + // Decrease the approximation until it is smaller than the remainder. Note + // that if it is too large, the product overflows and is negative. + var approxRes = Timestamp.fromNumber(approx); + var approxRem = approxRes.multiply(other); + while (approxRem.isNegative() || approxRem.greaterThan(rem)) { + approx -= delta; + approxRes = Timestamp.fromNumber(approx); + approxRem = approxRes.multiply(other); + } + + // We know the answer can't be zero... and actually, zero would cause + // infinite recursion since we would make no progress. + if (approxRes.isZero()) { + approxRes = Timestamp.ONE; + } + + res = res.add(approxRes); + rem = rem.subtract(approxRem); + } + return res; +}; + +/** + * Returns this Timestamp modulo the given one. + * + * @param {Timestamp} other Timestamp by which to mod. + * @return {Timestamp} this Timestamp modulo the given one. + * @api public + */ +Timestamp.prototype.modulo = function(other) { + return this.subtract(this.div(other).multiply(other)); +}; + +/** + * The bitwise-NOT of this value. + * + * @return {Timestamp} the bitwise-NOT of this value. + * @api public + */ +Timestamp.prototype.not = function() { + return Timestamp.fromBits(~this.low_, ~this.high_); +}; + +/** + * Returns the bitwise-AND of this Timestamp and the given one. + * + * @param {Timestamp} other the Timestamp with which to AND. + * @return {Timestamp} the bitwise-AND of this and the other. + * @api public + */ +Timestamp.prototype.and = function(other) { + return Timestamp.fromBits(this.low_ & other.low_, this.high_ & other.high_); +}; + +/** + * Returns the bitwise-OR of this Timestamp and the given one. + * + * @param {Timestamp} other the Timestamp with which to OR. + * @return {Timestamp} the bitwise-OR of this and the other. + * @api public + */ +Timestamp.prototype.or = function(other) { + return Timestamp.fromBits(this.low_ | other.low_, this.high_ | other.high_); +}; + +/** + * Returns the bitwise-XOR of this Timestamp and the given one. + * + * @param {Timestamp} other the Timestamp with which to XOR. + * @return {Timestamp} the bitwise-XOR of this and the other. + * @api public + */ +Timestamp.prototype.xor = function(other) { + return Timestamp.fromBits(this.low_ ^ other.low_, this.high_ ^ other.high_); +}; + +/** + * Returns this Timestamp with bits shifted to the left by the given amount. + * + * @param {Number} numBits the number of bits by which to shift. + * @return {Timestamp} this shifted to the left by the given amount. + * @api public + */ +Timestamp.prototype.shiftLeft = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var low = this.low_; + if (numBits < 32) { + var high = this.high_; + return Timestamp.fromBits( + low << numBits, + (high << numBits) | (low >>> (32 - numBits))); + } else { + return Timestamp.fromBits(0, low << (numBits - 32)); + } + } +}; + +/** + * Returns this Timestamp with bits shifted to the right by the given amount. + * + * @param {Number} numBits the number of bits by which to shift. + * @return {Timestamp} this shifted to the right by the given amount. + * @api public + */ +Timestamp.prototype.shiftRight = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var high = this.high_; + if (numBits < 32) { + var low = this.low_; + return Timestamp.fromBits( + (low >>> numBits) | (high << (32 - numBits)), + high >> numBits); + } else { + return Timestamp.fromBits( + high >> (numBits - 32), + high >= 0 ? 0 : -1); + } + } +}; + +/** + * Returns this Timestamp with bits shifted to the right by the given amount, with the new top bits matching the current sign bit. + * + * @param {Number} numBits the number of bits by which to shift. + * @return {Timestamp} this shifted to the right by the given amount, with zeros placed into the new leading bits. + * @api public + */ +Timestamp.prototype.shiftRightUnsigned = function(numBits) { + numBits &= 63; + if (numBits == 0) { + return this; + } else { + var high = this.high_; + if (numBits < 32) { + var low = this.low_; + return Timestamp.fromBits( + (low >>> numBits) | (high << (32 - numBits)), + high >>> numBits); + } else if (numBits == 32) { + return Timestamp.fromBits(high, 0); + } else { + return Timestamp.fromBits(high >>> (numBits - 32), 0); + } + } +}; + +/** + * Returns a Timestamp representing the given (32-bit) integer value. + * + * @param {Number} value the 32-bit integer in question. + * @return {Timestamp} the corresponding Timestamp value. + * @api public + */ +Timestamp.fromInt = function(value) { + if (-128 <= value && value < 128) { + var cachedObj = Timestamp.INT_CACHE_[value]; + if (cachedObj) { + return cachedObj; + } + } + + var obj = new Timestamp(value | 0, value < 0 ? -1 : 0); + if (-128 <= value && value < 128) { + Timestamp.INT_CACHE_[value] = obj; + } + return obj; +}; + +/** + * Returns a Timestamp representing the given value, provided that it is a finite number. Otherwise, zero is returned. + * + * @param {Number} value the number in question. + * @return {Timestamp} the corresponding Timestamp value. + * @api public + */ +Timestamp.fromNumber = function(value) { + if (isNaN(value) || !isFinite(value)) { + return Timestamp.ZERO; + } else if (value <= -Timestamp.TWO_PWR_63_DBL_) { + return Timestamp.MIN_VALUE; + } else if (value + 1 >= Timestamp.TWO_PWR_63_DBL_) { + return Timestamp.MAX_VALUE; + } else if (value < 0) { + return Timestamp.fromNumber(-value).negate(); + } else { + return new Timestamp( + (value % Timestamp.TWO_PWR_32_DBL_) | 0, + (value / Timestamp.TWO_PWR_32_DBL_) | 0); + } +}; + +/** + * Returns a Timestamp representing the 64-bit integer that comes by concatenating the given high and low bits. Each is assumed to use 32 bits. + * + * @param {Number} lowBits the low 32-bits. + * @param {Number} highBits the high 32-bits. + * @return {Timestamp} the corresponding Timestamp value. + * @api public + */ +Timestamp.fromBits = function(lowBits, highBits) { + return new Timestamp(lowBits, highBits); +}; + +/** + * Returns a Timestamp representation of the given string, written using the given radix. + * + * @param {String} str the textual representation of the Timestamp. + * @param {Number} opt_radix the radix in which the text is written. + * @return {Timestamp} the corresponding Timestamp value. + * @api public + */ +Timestamp.fromString = function(str, opt_radix) { + if (str.length == 0) { + throw Error('number format error: empty string'); + } + + var radix = opt_radix || 10; + if (radix < 2 || 36 < radix) { + throw Error('radix out of range: ' + radix); + } + + if (str.charAt(0) == '-') { + return Timestamp.fromString(str.substring(1), radix).negate(); + } else if (str.indexOf('-') >= 0) { + throw Error('number format error: interior "-" character: ' + str); + } + + // Do several (8) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = Timestamp.fromNumber(Math.pow(radix, 8)); + + var result = Timestamp.ZERO; + for (var i = 0; i < str.length; i += 8) { + var size = Math.min(8, str.length - i); + var value = parseInt(str.substring(i, i + size), radix); + if (size < 8) { + var power = Timestamp.fromNumber(Math.pow(radix, size)); + result = result.multiply(power).add(Timestamp.fromNumber(value)); + } else { + result = result.multiply(radixToPower); + result = result.add(Timestamp.fromNumber(value)); + } + } + return result; +}; + +// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the +// from* methods on which they depend. + + +/** + * A cache of the Timestamp representations of small integer values. + * @type {Object} + * @api private + */ +Timestamp.INT_CACHE_ = {}; + +// NOTE: the compiler should inline these constant values below and then remove +// these variables, so there should be no runtime penalty for these. + +/** + * Number used repeated below in calculations. This must appear before the + * first call to any from* function below. + * @type {number} + * @api private + */ +Timestamp.TWO_PWR_16_DBL_ = 1 << 16; + +/** + * @type {number} + * @api private + */ +Timestamp.TWO_PWR_24_DBL_ = 1 << 24; + +/** + * @type {number} + * @api private + */ +Timestamp.TWO_PWR_32_DBL_ = Timestamp.TWO_PWR_16_DBL_ * Timestamp.TWO_PWR_16_DBL_; + +/** + * @type {number} + * @api private + */ +Timestamp.TWO_PWR_31_DBL_ = Timestamp.TWO_PWR_32_DBL_ / 2; + +/** + * @type {number} + * @api private + */ +Timestamp.TWO_PWR_48_DBL_ = Timestamp.TWO_PWR_32_DBL_ * Timestamp.TWO_PWR_16_DBL_; + +/** + * @type {number} + * @api private + */ +Timestamp.TWO_PWR_64_DBL_ = Timestamp.TWO_PWR_32_DBL_ * Timestamp.TWO_PWR_32_DBL_; + +/** + * @type {number} + * @api private + */ +Timestamp.TWO_PWR_63_DBL_ = Timestamp.TWO_PWR_64_DBL_ / 2; + +/** @type {Timestamp} */ +Timestamp.ZERO = Timestamp.fromInt(0); + +/** @type {Timestamp} */ +Timestamp.ONE = Timestamp.fromInt(1); + +/** @type {Timestamp} */ +Timestamp.NEG_ONE = Timestamp.fromInt(-1); + +/** @type {Timestamp} */ +Timestamp.MAX_VALUE = + Timestamp.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); + +/** @type {Timestamp} */ +Timestamp.MIN_VALUE = Timestamp.fromBits(0, 0x80000000 | 0); + +/** + * @type {Timestamp} + * @api private + */ +Timestamp.TWO_PWR_24_ = Timestamp.fromInt(1 << 24); + +/** + * Expose. + */ +exports.Timestamp = Timestamp; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/package.json b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/package.json new file mode 100644 index 0000000..ac6c5a6 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/package.json @@ -0,0 +1,55 @@ +{ + "name": "bson", + "description": "A bson parser for node.js and the browser", + "keywords": [ + "mongodb", + "bson", + "parser" + ], + "version": "0.2.2", + "author": { + "name": "Christian Amor Kvalheim", + "email": "christkv@gmail.com" + }, + "contributors": [], + "repository": { + "type": "git", + "url": "git://github.com/mongodb/js-bson.git" + }, + "bugs": { + "url": "https://github.com/mongodb/js-bson/issues" + }, + "devDependencies": { + "nodeunit": "0.7.3", + "gleak": "0.2.3", + "one": "2.X.X" + }, + "config": { + "native": false + }, + "main": "./lib/bson/index", + "directories": { + "lib": "./lib/bson" + }, + "engines": { + "node": ">=0.6.19" + }, + "scripts": { + "install": "(node-gyp rebuild 2> builderror.log) || (exit 0)", + "test": "nodeunit ./test/node && TEST_NATIVE=TRUE nodeunit ./test/node" + }, + "licenses": [ + { + "type": "Apache License, Version 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0" + } + ], + "readme": "Javascript + C++ BSON parser\n============================\n\nThis BSON parser is primarily meant for usage with the `mongodb` node.js driver. However thanks to such wonderful tools at `onejs` we are able to package up a BSON parser that will work in the browser aswell. The current build is located in the `browser_build/bson.js` file.\n\nA simple example on how to use it\n\n \n \n \n \n \n \n\n It's got two simple methods to use in your application.\n\n * BSON.serialize(object, checkKeys, asBuffer, serializeFunctions)\n * @param {Object} object the Javascript object to serialize.\n * @param {Boolean} checkKeys the serializer will check if keys are valid.\n * @param {Boolean} asBuffer return the serialized object as a Buffer object **(ignore)**.\n * @param {Boolean} serializeFunctions serialize the javascript functions **(default:false)**\n * @return {TypedArray/Array} returns a TypedArray or Array depending on what your browser supports\n \n * BSON.deserialize(buffer, options, isArray)\n * Options\n * **evalFunctions** {Boolean, default:false}, evaluate functions in the BSON document scoped to the object deserialized.\n * **cacheFunctions** {Boolean, default:false}, cache evaluated functions for reuse.\n * **cacheFunctionsCrc32** {Boolean, default:false}, use a crc32 code for caching, otherwise use the string of the function.\n * @param {TypedArray/Array} a TypedArray/Array containing the BSON data\n * @param {Object} [options] additional options used for the deserialization.\n * @param {Boolean} [isArray] ignore used for recursive parsing.\n * @return {Object} returns the deserialized Javascript Object.\n", + "readmeFilename": "README.md", + "_id": "bson@0.2.2", + "dist": { + "shasum": "c4bae9d0803bf49178f458bf94d8b592b4c1ee68" + }, + "_from": "bson@0.2.2", + "_resolved": "https://registry.npmjs.org/bson/-/bson-0.2.2.tgz" +} diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/gleak.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/gleak.js new file mode 100644 index 0000000..c707cfc --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/gleak.js @@ -0,0 +1,21 @@ + +var gleak = require('gleak')(); +gleak.ignore('AssertionError'); +gleak.ignore('testFullSpec_param_found'); +gleak.ignore('events'); +gleak.ignore('Uint8Array'); +gleak.ignore('Uint8ClampedArray'); +gleak.ignore('TAP_Global_Harness'); +gleak.ignore('setImmediate'); +gleak.ignore('clearImmediate'); + +gleak.ignore('DTRACE_NET_SERVER_CONNECTION'); +gleak.ignore('DTRACE_NET_STREAM_END'); +gleak.ignore('DTRACE_NET_SOCKET_READ'); +gleak.ignore('DTRACE_NET_SOCKET_WRITE'); +gleak.ignore('DTRACE_HTTP_SERVER_REQUEST'); +gleak.ignore('DTRACE_HTTP_SERVER_RESPONSE'); +gleak.ignore('DTRACE_HTTP_CLIENT_REQUEST'); +gleak.ignore('DTRACE_HTTP_CLIENT_RESPONSE'); + +module.exports = gleak; diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/jasmine-1.1.0/MIT.LICENSE b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/jasmine-1.1.0/MIT.LICENSE new file mode 100644 index 0000000..7c435ba --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/jasmine-1.1.0/MIT.LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2008-2011 Pivotal Labs + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/jasmine-1.1.0/jasmine-html.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/jasmine-1.1.0/jasmine-html.js new file mode 100644 index 0000000..7383401 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/jasmine-1.1.0/jasmine-html.js @@ -0,0 +1,190 @@ +jasmine.TrivialReporter = function(doc) { + this.document = doc || document; + this.suiteDivs = {}; + this.logRunningSpecs = false; +}; + +jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) { + var el = document.createElement(type); + + for (var i = 2; i < arguments.length; i++) { + var child = arguments[i]; + + if (typeof child === 'string') { + el.appendChild(document.createTextNode(child)); + } else { + if (child) { el.appendChild(child); } + } + } + + for (var attr in attrs) { + if (attr == "className") { + el[attr] = attrs[attr]; + } else { + el.setAttribute(attr, attrs[attr]); + } + } + + return el; +}; + +jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { + var showPassed, showSkipped; + + this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' }, + this.createDom('div', { className: 'banner' }, + this.createDom('div', { className: 'logo' }, + this.createDom('span', { className: 'title' }, "Jasmine"), + this.createDom('span', { className: 'version' }, runner.env.versionString())), + this.createDom('div', { className: 'options' }, + "Show ", + showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }), + this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "), + showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }), + this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped") + ) + ), + + this.runnerDiv = this.createDom('div', { className: 'runner running' }, + this.createDom('a', { className: 'run_spec', href: '?' }, "run all"), + this.runnerMessageSpan = this.createDom('span', {}, "Running..."), + this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, "")) + ); + + this.document.body.appendChild(this.outerDiv); + + var suites = runner.suites(); + for (var i = 0; i < suites.length; i++) { + var suite = suites[i]; + var suiteDiv = this.createDom('div', { className: 'suite' }, + this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"), + this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description)); + this.suiteDivs[suite.id] = suiteDiv; + var parentDiv = this.outerDiv; + if (suite.parentSuite) { + parentDiv = this.suiteDivs[suite.parentSuite.id]; + } + parentDiv.appendChild(suiteDiv); + } + + this.startedAt = new Date(); + + var self = this; + showPassed.onclick = function(evt) { + if (showPassed.checked) { + self.outerDiv.className += ' show-passed'; + } else { + self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, ''); + } + }; + + showSkipped.onclick = function(evt) { + if (showSkipped.checked) { + self.outerDiv.className += ' show-skipped'; + } else { + self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, ''); + } + }; +}; + +jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) { + var results = runner.results(); + var className = (results.failedCount > 0) ? "runner failed" : "runner passed"; + this.runnerDiv.setAttribute("class", className); + //do it twice for IE + this.runnerDiv.setAttribute("className", className); + var specs = runner.specs(); + var specCount = 0; + for (var i = 0; i < specs.length; i++) { + if (this.specFilter(specs[i])) { + specCount++; + } + } + var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); + message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; + this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); + + this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString())); +}; + +jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { + var results = suite.results(); + var status = results.passed() ? 'passed' : 'failed'; + if (results.totalCount === 0) { // todo: change this to check results.skipped + status = 'skipped'; + } + this.suiteDivs[suite.id].className += " " + status; +}; + +jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { + if (this.logRunningSpecs) { + this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); + } +}; + +jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { + var results = spec.results(); + var status = results.passed() ? 'passed' : 'failed'; + if (results.skipped) { + status = 'skipped'; + } + var specDiv = this.createDom('div', { className: 'spec ' + status }, + this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), + this.createDom('a', { + className: 'description', + href: '?spec=' + encodeURIComponent(spec.getFullName()), + title: spec.getFullName() + }, spec.description)); + + + var resultItems = results.getItems(); + var messagesDiv = this.createDom('div', { className: 'messages' }); + for (var i = 0; i < resultItems.length; i++) { + var result = resultItems[i]; + + if (result.type == 'log') { + messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); + } else if (result.type == 'expect' && result.passed && !result.passed()) { + messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); + + if (result.trace.stack) { + messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); + } + } + } + + if (messagesDiv.childNodes.length > 0) { + specDiv.appendChild(messagesDiv); + } + + this.suiteDivs[spec.suite.id].appendChild(specDiv); +}; + +jasmine.TrivialReporter.prototype.log = function() { + var console = jasmine.getGlobal().console; + if (console && console.log) { + if (console.log.apply) { + console.log.apply(console, arguments); + } else { + console.log(arguments); // ie fix: console.log.apply doesn't exist on ie + } + } +}; + +jasmine.TrivialReporter.prototype.getLocation = function() { + return this.document.location; +}; + +jasmine.TrivialReporter.prototype.specFilter = function(spec) { + var paramMap = {}; + var params = this.getLocation().search.substring(1).split('&'); + for (var i = 0; i < params.length; i++) { + var p = params[i].split('='); + paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); + } + + if (!paramMap.spec) { + return true; + } + return spec.getFullName().indexOf(paramMap.spec) === 0; +}; diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/jasmine-1.1.0/jasmine.css b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/jasmine-1.1.0/jasmine.css new file mode 100644 index 0000000..6583fe7 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/jasmine-1.1.0/jasmine.css @@ -0,0 +1,166 @@ +body { + font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; +} + + +.jasmine_reporter a:visited, .jasmine_reporter a { + color: #303; +} + +.jasmine_reporter a:hover, .jasmine_reporter a:active { + color: blue; +} + +.run_spec { + float:right; + padding-right: 5px; + font-size: .8em; + text-decoration: none; +} + +.jasmine_reporter { + margin: 0 5px; +} + +.banner { + color: #303; + background-color: #fef; + padding: 5px; +} + +.logo { + float: left; + font-size: 1.1em; + padding-left: 5px; +} + +.logo .version { + font-size: .6em; + padding-left: 1em; +} + +.runner.running { + background-color: yellow; +} + + +.options { + text-align: right; + font-size: .8em; +} + + + + +.suite { + border: 1px outset gray; + margin: 5px 0; + padding-left: 1em; +} + +.suite .suite { + margin: 5px; +} + +.suite.passed { + background-color: #dfd; +} + +.suite.failed { + background-color: #fdd; +} + +.spec { + margin: 5px; + padding-left: 1em; + clear: both; +} + +.spec.failed, .spec.passed, .spec.skipped { + padding-bottom: 5px; + border: 1px solid gray; +} + +.spec.failed { + background-color: #fbb; + border-color: red; +} + +.spec.passed { + background-color: #bfb; + border-color: green; +} + +.spec.skipped { + background-color: #bbb; +} + +.messages { + border-left: 1px dashed gray; + padding-left: 1em; + padding-right: 1em; +} + +.passed { + background-color: #cfc; + display: none; +} + +.failed { + background-color: #fbb; +} + +.skipped { + color: #777; + background-color: #eee; + display: none; +} + + +/*.resultMessage {*/ + /*white-space: pre;*/ +/*}*/ + +.resultMessage span.result { + display: block; + line-height: 2em; + color: black; +} + +.resultMessage .mismatch { + color: black; +} + +.stackTrace { + white-space: pre; + font-size: .8em; + margin-left: 10px; + max-height: 5em; + overflow: auto; + border: 1px inset red; + padding: 1em; + background: #eef; +} + +.finished-at { + padding-left: 1em; + font-size: .6em; +} + +.show-passed .passed, +.show-skipped .skipped { + display: block; +} + + +#jasmine_content { + position:fixed; + right: 100%; +} + +.runner { + border: 1px solid gray; + display: block; + margin: 5px 0; + padding: 2px 0 2px 10px; +} diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/jasmine-1.1.0/jasmine.js b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/jasmine-1.1.0/jasmine.js new file mode 100644 index 0000000..c3d2dc7 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/jasmine-1.1.0/jasmine.js @@ -0,0 +1,2476 @@ +var isCommonJS = typeof window == "undefined"; + +/** + * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework. + * + * @namespace + */ +var jasmine = {}; +if (isCommonJS) exports.jasmine = jasmine; +/** + * @private + */ +jasmine.unimplementedMethod_ = function() { + throw new Error("unimplemented method"); +}; + +/** + * Use jasmine.undefined instead of undefined, since undefined is just + * a plain old variable and may be redefined by somebody else. + * + * @private + */ +jasmine.undefined = jasmine.___undefined___; + +/** + * Show diagnostic messages in the console if set to true + * + */ +jasmine.VERBOSE = false; + +/** + * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed. + * + */ +jasmine.DEFAULT_UPDATE_INTERVAL = 250; + +/** + * Default timeout interval in milliseconds for waitsFor() blocks. + */ +jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; + +jasmine.getGlobal = function() { + function getGlobal() { + return this; + } + + return getGlobal(); +}; + +/** + * Allows for bound functions to be compared. Internal use only. + * + * @ignore + * @private + * @param base {Object} bound 'this' for the function + * @param name {Function} function to find + */ +jasmine.bindOriginal_ = function(base, name) { + var original = base[name]; + if (original.apply) { + return function() { + return original.apply(base, arguments); + }; + } else { + // IE support + return jasmine.getGlobal()[name]; + } +}; + +jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout'); +jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout'); +jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval'); +jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval'); + +jasmine.MessageResult = function(values) { + this.type = 'log'; + this.values = values; + this.trace = new Error(); // todo: test better +}; + +jasmine.MessageResult.prototype.toString = function() { + var text = ""; + for (var i = 0; i < this.values.length; i++) { + if (i > 0) text += " "; + if (jasmine.isString_(this.values[i])) { + text += this.values[i]; + } else { + text += jasmine.pp(this.values[i]); + } + } + return text; +}; + +jasmine.ExpectationResult = function(params) { + this.type = 'expect'; + this.matcherName = params.matcherName; + this.passed_ = params.passed; + this.expected = params.expected; + this.actual = params.actual; + this.message = this.passed_ ? 'Passed.' : params.message; + + var trace = (params.trace || new Error(this.message)); + this.trace = this.passed_ ? '' : trace; +}; + +jasmine.ExpectationResult.prototype.toString = function () { + return this.message; +}; + +jasmine.ExpectationResult.prototype.passed = function () { + return this.passed_; +}; + +/** + * Getter for the Jasmine environment. Ensures one gets created + */ +jasmine.getEnv = function() { + var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env(); + return env; +}; + +/** + * @ignore + * @private + * @param value + * @returns {Boolean} + */ +jasmine.isArray_ = function(value) { + return jasmine.isA_("Array", value); +}; + +/** + * @ignore + * @private + * @param value + * @returns {Boolean} + */ +jasmine.isString_ = function(value) { + return jasmine.isA_("String", value); +}; + +/** + * @ignore + * @private + * @param value + * @returns {Boolean} + */ +jasmine.isNumber_ = function(value) { + return jasmine.isA_("Number", value); +}; + +/** + * @ignore + * @private + * @param {String} typeName + * @param value + * @returns {Boolean} + */ +jasmine.isA_ = function(typeName, value) { + return Object.prototype.toString.apply(value) === '[object ' + typeName + ']'; +}; + +/** + * Pretty printer for expecations. Takes any object and turns it into a human-readable string. + * + * @param value {Object} an object to be outputted + * @returns {String} + */ +jasmine.pp = function(value) { + var stringPrettyPrinter = new jasmine.StringPrettyPrinter(); + stringPrettyPrinter.format(value); + return stringPrettyPrinter.string; +}; + +/** + * Returns true if the object is a DOM Node. + * + * @param {Object} obj object to check + * @returns {Boolean} + */ +jasmine.isDomNode = function(obj) { + return obj.nodeType > 0; +}; + +/** + * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter. + * + * @example + * // don't care about which function is passed in, as long as it's a function + * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function)); + * + * @param {Class} clazz + * @returns matchable object of the type clazz + */ +jasmine.any = function(clazz) { + return new jasmine.Matchers.Any(clazz); +}; + +/** + * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks. + * + * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine + * expectation syntax. Spies can be checked if they were called or not and what the calling params were. + * + * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs). + * + * Spies are torn down at the end of every spec. + * + * Note: Do not call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj. + * + * @example + * // a stub + * var myStub = jasmine.createSpy('myStub'); // can be used anywhere + * + * // spy example + * var foo = { + * not: function(bool) { return !bool; } + * } + * + * // actual foo.not will not be called, execution stops + * spyOn(foo, 'not'); + + // foo.not spied upon, execution will continue to implementation + * spyOn(foo, 'not').andCallThrough(); + * + * // fake example + * var foo = { + * not: function(bool) { return !bool; } + * } + * + * // foo.not(val) will return val + * spyOn(foo, 'not').andCallFake(function(value) {return value;}); + * + * // mock example + * foo.not(7 == 7); + * expect(foo.not).toHaveBeenCalled(); + * expect(foo.not).toHaveBeenCalledWith(true); + * + * @constructor + * @see spyOn, jasmine.createSpy, jasmine.createSpyObj + * @param {String} name + */ +jasmine.Spy = function(name) { + /** + * The name of the spy, if provided. + */ + this.identity = name || 'unknown'; + /** + * Is this Object a spy? + */ + this.isSpy = true; + /** + * The actual function this spy stubs. + */ + this.plan = function() { + }; + /** + * Tracking of the most recent call to the spy. + * @example + * var mySpy = jasmine.createSpy('foo'); + * mySpy(1, 2); + * mySpy.mostRecentCall.args = [1, 2]; + */ + this.mostRecentCall = {}; + + /** + * Holds arguments for each call to the spy, indexed by call count + * @example + * var mySpy = jasmine.createSpy('foo'); + * mySpy(1, 2); + * mySpy(7, 8); + * mySpy.mostRecentCall.args = [7, 8]; + * mySpy.argsForCall[0] = [1, 2]; + * mySpy.argsForCall[1] = [7, 8]; + */ + this.argsForCall = []; + this.calls = []; +}; + +/** + * Tells a spy to call through to the actual implemenatation. + * + * @example + * var foo = { + * bar: function() { // do some stuff } + * } + * + * // defining a spy on an existing property: foo.bar + * spyOn(foo, 'bar').andCallThrough(); + */ +jasmine.Spy.prototype.andCallThrough = function() { + this.plan = this.originalValue; + return this; +}; + +/** + * For setting the return value of a spy. + * + * @example + * // defining a spy from scratch: foo() returns 'baz' + * var foo = jasmine.createSpy('spy on foo').andReturn('baz'); + * + * // defining a spy on an existing property: foo.bar() returns 'baz' + * spyOn(foo, 'bar').andReturn('baz'); + * + * @param {Object} value + */ +jasmine.Spy.prototype.andReturn = function(value) { + this.plan = function() { + return value; + }; + return this; +}; + +/** + * For throwing an exception when a spy is called. + * + * @example + * // defining a spy from scratch: foo() throws an exception w/ message 'ouch' + * var foo = jasmine.createSpy('spy on foo').andThrow('baz'); + * + * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch' + * spyOn(foo, 'bar').andThrow('baz'); + * + * @param {String} exceptionMsg + */ +jasmine.Spy.prototype.andThrow = function(exceptionMsg) { + this.plan = function() { + throw exceptionMsg; + }; + return this; +}; + +/** + * Calls an alternate implementation when a spy is called. + * + * @example + * var baz = function() { + * // do some stuff, return something + * } + * // defining a spy from scratch: foo() calls the function baz + * var foo = jasmine.createSpy('spy on foo').andCall(baz); + * + * // defining a spy on an existing property: foo.bar() calls an anonymnous function + * spyOn(foo, 'bar').andCall(function() { return 'baz';} ); + * + * @param {Function} fakeFunc + */ +jasmine.Spy.prototype.andCallFake = function(fakeFunc) { + this.plan = fakeFunc; + return this; +}; + +/** + * Resets all of a spy's the tracking variables so that it can be used again. + * + * @example + * spyOn(foo, 'bar'); + * + * foo.bar(); + * + * expect(foo.bar.callCount).toEqual(1); + * + * foo.bar.reset(); + * + * expect(foo.bar.callCount).toEqual(0); + */ +jasmine.Spy.prototype.reset = function() { + this.wasCalled = false; + this.callCount = 0; + this.argsForCall = []; + this.calls = []; + this.mostRecentCall = {}; +}; + +jasmine.createSpy = function(name) { + + var spyObj = function() { + spyObj.wasCalled = true; + spyObj.callCount++; + var args = jasmine.util.argsToArray(arguments); + spyObj.mostRecentCall.object = this; + spyObj.mostRecentCall.args = args; + spyObj.argsForCall.push(args); + spyObj.calls.push({object: this, args: args}); + return spyObj.plan.apply(this, arguments); + }; + + var spy = new jasmine.Spy(name); + + for (var prop in spy) { + spyObj[prop] = spy[prop]; + } + + spyObj.reset(); + + return spyObj; +}; + +/** + * Determines whether an object is a spy. + * + * @param {jasmine.Spy|Object} putativeSpy + * @returns {Boolean} + */ +jasmine.isSpy = function(putativeSpy) { + return putativeSpy && putativeSpy.isSpy; +}; + +/** + * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something + * large in one call. + * + * @param {String} baseName name of spy class + * @param {Array} methodNames array of names of methods to make spies + */ +jasmine.createSpyObj = function(baseName, methodNames) { + if (!jasmine.isArray_(methodNames) || methodNames.length === 0) { + throw new Error('createSpyObj requires a non-empty array of method names to create spies for'); + } + var obj = {}; + for (var i = 0; i < methodNames.length; i++) { + obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]); + } + return obj; +}; + +/** + * All parameters are pretty-printed and concatenated together, then written to the current spec's output. + * + * Be careful not to leave calls to jasmine.log in production code. + */ +jasmine.log = function() { + var spec = jasmine.getEnv().currentSpec; + spec.log.apply(spec, arguments); +}; + +/** + * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy. + * + * @example + * // spy example + * var foo = { + * not: function(bool) { return !bool; } + * } + * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops + * + * @see jasmine.createSpy + * @param obj + * @param methodName + * @returns a Jasmine spy that can be chained with all spy methods + */ +var spyOn = function(obj, methodName) { + return jasmine.getEnv().currentSpec.spyOn(obj, methodName); +}; +if (isCommonJS) exports.spyOn = spyOn; + +/** + * Creates a Jasmine spec that will be added to the current suite. + * + * // TODO: pending tests + * + * @example + * it('should be true', function() { + * expect(true).toEqual(true); + * }); + * + * @param {String} desc description of this specification + * @param {Function} func defines the preconditions and expectations of the spec + */ +var it = function(desc, func) { + return jasmine.getEnv().it(desc, func); +}; +if (isCommonJS) exports.it = it; + +/** + * Creates a disabled Jasmine spec. + * + * A convenience method that allows existing specs to be disabled temporarily during development. + * + * @param {String} desc description of this specification + * @param {Function} func defines the preconditions and expectations of the spec + */ +var xit = function(desc, func) { + return jasmine.getEnv().xit(desc, func); +}; +if (isCommonJS) exports.xit = xit; + +/** + * Starts a chain for a Jasmine expectation. + * + * It is passed an Object that is the actual value and should chain to one of the many + * jasmine.Matchers functions. + * + * @param {Object} actual Actual value to test against and expected value + */ +var expect = function(actual) { + return jasmine.getEnv().currentSpec.expect(actual); +}; +if (isCommonJS) exports.expect = expect; + +/** + * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs. + * + * @param {Function} func Function that defines part of a jasmine spec. + */ +var runs = function(func) { + jasmine.getEnv().currentSpec.runs(func); +}; +if (isCommonJS) exports.runs = runs; + +/** + * Waits a fixed time period before moving to the next block. + * + * @deprecated Use waitsFor() instead + * @param {Number} timeout milliseconds to wait + */ +var waits = function(timeout) { + jasmine.getEnv().currentSpec.waits(timeout); +}; +if (isCommonJS) exports.waits = waits; + +/** + * Waits for the latchFunction to return true before proceeding to the next block. + * + * @param {Function} latchFunction + * @param {String} optional_timeoutMessage + * @param {Number} optional_timeout + */ +var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { + jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments); +}; +if (isCommonJS) exports.waitsFor = waitsFor; + +/** + * A function that is called before each spec in a suite. + * + * Used for spec setup, including validating assumptions. + * + * @param {Function} beforeEachFunction + */ +var beforeEach = function(beforeEachFunction) { + jasmine.getEnv().beforeEach(beforeEachFunction); +}; +if (isCommonJS) exports.beforeEach = beforeEach; + +/** + * A function that is called after each spec in a suite. + * + * Used for restoring any state that is hijacked during spec execution. + * + * @param {Function} afterEachFunction + */ +var afterEach = function(afterEachFunction) { + jasmine.getEnv().afterEach(afterEachFunction); +}; +if (isCommonJS) exports.afterEach = afterEach; + +/** + * Defines a suite of specifications. + * + * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared + * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization + * of setup in some tests. + * + * @example + * // TODO: a simple suite + * + * // TODO: a simple suite with a nested describe block + * + * @param {String} description A string, usually the class under test. + * @param {Function} specDefinitions function that defines several specs. + */ +var describe = function(description, specDefinitions) { + return jasmine.getEnv().describe(description, specDefinitions); +}; +if (isCommonJS) exports.describe = describe; + +/** + * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development. + * + * @param {String} description A string, usually the class under test. + * @param {Function} specDefinitions function that defines several specs. + */ +var xdescribe = function(description, specDefinitions) { + return jasmine.getEnv().xdescribe(description, specDefinitions); +}; +if (isCommonJS) exports.xdescribe = xdescribe; + + +// Provide the XMLHttpRequest class for IE 5.x-6.x: +jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() { + function tryIt(f) { + try { + return f(); + } catch(e) { + } + return null; + } + + var xhr = tryIt(function() { + return new ActiveXObject("Msxml2.XMLHTTP.6.0"); + }) || + tryIt(function() { + return new ActiveXObject("Msxml2.XMLHTTP.3.0"); + }) || + tryIt(function() { + return new ActiveXObject("Msxml2.XMLHTTP"); + }) || + tryIt(function() { + return new ActiveXObject("Microsoft.XMLHTTP"); + }); + + if (!xhr) throw new Error("This browser does not support XMLHttpRequest."); + + return xhr; +} : XMLHttpRequest; +/** + * @namespace + */ +jasmine.util = {}; + +/** + * Declare that a child class inherit it's prototype from the parent class. + * + * @private + * @param {Function} childClass + * @param {Function} parentClass + */ +jasmine.util.inherit = function(childClass, parentClass) { + /** + * @private + */ + var subclass = function() { + }; + subclass.prototype = parentClass.prototype; + childClass.prototype = new subclass(); +}; + +jasmine.util.formatException = function(e) { + var lineNumber; + if (e.line) { + lineNumber = e.line; + } + else if (e.lineNumber) { + lineNumber = e.lineNumber; + } + + var file; + + if (e.sourceURL) { + file = e.sourceURL; + } + else if (e.fileName) { + file = e.fileName; + } + + var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString(); + + if (file && lineNumber) { + message += ' in ' + file + ' (line ' + lineNumber + ')'; + } + + return message; +}; + +jasmine.util.htmlEscape = function(str) { + if (!str) return str; + return str.replace(/&/g, '&') + .replace(//g, '>'); +}; + +jasmine.util.argsToArray = function(args) { + var arrayOfArgs = []; + for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]); + return arrayOfArgs; +}; + +jasmine.util.extend = function(destination, source) { + for (var property in source) destination[property] = source[property]; + return destination; +}; + +/** + * Environment for Jasmine + * + * @constructor + */ +jasmine.Env = function() { + this.currentSpec = null; + this.currentSuite = null; + this.currentRunner_ = new jasmine.Runner(this); + + this.reporter = new jasmine.MultiReporter(); + + this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; + this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL; + this.lastUpdate = 0; + this.specFilter = function() { + return true; + }; + + this.nextSpecId_ = 0; + this.nextSuiteId_ = 0; + this.equalityTesters_ = []; + + // wrap matchers + this.matchersClass = function() { + jasmine.Matchers.apply(this, arguments); + }; + jasmine.util.inherit(this.matchersClass, jasmine.Matchers); + + jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass); +}; + + +jasmine.Env.prototype.setTimeout = jasmine.setTimeout; +jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; +jasmine.Env.prototype.setInterval = jasmine.setInterval; +jasmine.Env.prototype.clearInterval = jasmine.clearInterval; + +/** + * @returns an object containing jasmine version build info, if set. + */ +jasmine.Env.prototype.version = function () { + if (jasmine.version_) { + return jasmine.version_; + } else { + throw new Error('Version not set'); + } +}; + +/** + * @returns string containing jasmine version build info, if set. + */ +jasmine.Env.prototype.versionString = function() { + if (!jasmine.version_) { + return "version unknown"; + } + + var version = this.version(); + var versionString = version.major + "." + version.minor + "." + version.build; + if (version.release_candidate) { + versionString += ".rc" + version.release_candidate; + } + versionString += " revision " + version.revision; + return versionString; +}; + +/** + * @returns a sequential integer starting at 0 + */ +jasmine.Env.prototype.nextSpecId = function () { + return this.nextSpecId_++; +}; + +/** + * @returns a sequential integer starting at 0 + */ +jasmine.Env.prototype.nextSuiteId = function () { + return this.nextSuiteId_++; +}; + +/** + * Register a reporter to receive status updates from Jasmine. + * @param {jasmine.Reporter} reporter An object which will receive status updates. + */ +jasmine.Env.prototype.addReporter = function(reporter) { + this.reporter.addReporter(reporter); +}; + +jasmine.Env.prototype.execute = function() { + this.currentRunner_.execute(); +}; + +jasmine.Env.prototype.describe = function(description, specDefinitions) { + var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite); + + var parentSuite = this.currentSuite; + if (parentSuite) { + parentSuite.add(suite); + } else { + this.currentRunner_.add(suite); + } + + this.currentSuite = suite; + + var declarationError = null; + try { + specDefinitions.call(suite); + } catch(e) { + declarationError = e; + } + + if (declarationError) { + this.it("encountered a declaration exception", function() { + throw declarationError; + }); + } + + this.currentSuite = parentSuite; + + return suite; +}; + +jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { + if (this.currentSuite) { + this.currentSuite.beforeEach(beforeEachFunction); + } else { + this.currentRunner_.beforeEach(beforeEachFunction); + } +}; + +jasmine.Env.prototype.currentRunner = function () { + return this.currentRunner_; +}; + +jasmine.Env.prototype.afterEach = function(afterEachFunction) { + if (this.currentSuite) { + this.currentSuite.afterEach(afterEachFunction); + } else { + this.currentRunner_.afterEach(afterEachFunction); + } + +}; + +jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { + return { + execute: function() { + } + }; +}; + +jasmine.Env.prototype.it = function(description, func) { + var spec = new jasmine.Spec(this, this.currentSuite, description); + this.currentSuite.add(spec); + this.currentSpec = spec; + + if (func) { + spec.runs(func); + } + + return spec; +}; + +jasmine.Env.prototype.xit = function(desc, func) { + return { + id: this.nextSpecId(), + runs: function() { + } + }; +}; + +jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { + if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { + return true; + } + + a.__Jasmine_been_here_before__ = b; + b.__Jasmine_been_here_before__ = a; + + var hasKey = function(obj, keyName) { + return obj !== null && obj[keyName] !== jasmine.undefined; + }; + + for (var property in b) { + if (!hasKey(a, property) && hasKey(b, property)) { + mismatchKeys.push("expected has key '" + property + "', but missing from actual."); + } + } + for (property in a) { + if (!hasKey(b, property) && hasKey(a, property)) { + mismatchKeys.push("expected missing key '" + property + "', but present in actual."); + } + } + for (property in b) { + if (property == '__Jasmine_been_here_before__') continue; + if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) { + mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual."); + } + } + + if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) { + mismatchValues.push("arrays were not the same length"); + } + + delete a.__Jasmine_been_here_before__; + delete b.__Jasmine_been_here_before__; + return (mismatchKeys.length === 0 && mismatchValues.length === 0); +}; + +jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { + mismatchKeys = mismatchKeys || []; + mismatchValues = mismatchValues || []; + + for (var i = 0; i < this.equalityTesters_.length; i++) { + var equalityTester = this.equalityTesters_[i]; + var result = equalityTester(a, b, this, mismatchKeys, mismatchValues); + if (result !== jasmine.undefined) return result; + } + + if (a === b) return true; + + if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) { + return (a == jasmine.undefined && b == jasmine.undefined); + } + + if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) { + return a === b; + } + + if (a instanceof Date && b instanceof Date) { + return a.getTime() == b.getTime(); + } + + if (a instanceof jasmine.Matchers.Any) { + return a.matches(b); + } + + if (b instanceof jasmine.Matchers.Any) { + return b.matches(a); + } + + if (jasmine.isString_(a) && jasmine.isString_(b)) { + return (a == b); + } + + if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) { + return (a == b); + } + + if (typeof a === "object" && typeof b === "object") { + return this.compareObjects_(a, b, mismatchKeys, mismatchValues); + } + + //Straight check + return (a === b); +}; + +jasmine.Env.prototype.contains_ = function(haystack, needle) { + if (jasmine.isArray_(haystack)) { + for (var i = 0; i < haystack.length; i++) { + if (this.equals_(haystack[i], needle)) return true; + } + return false; + } + return haystack.indexOf(needle) >= 0; +}; + +jasmine.Env.prototype.addEqualityTester = function(equalityTester) { + this.equalityTesters_.push(equalityTester); +}; +/** No-op base class for Jasmine reporters. + * + * @constructor + */ +jasmine.Reporter = function() { +}; + +//noinspection JSUnusedLocalSymbols +jasmine.Reporter.prototype.reportRunnerStarting = function(runner) { +}; + +//noinspection JSUnusedLocalSymbols +jasmine.Reporter.prototype.reportRunnerResults = function(runner) { +}; + +//noinspection JSUnusedLocalSymbols +jasmine.Reporter.prototype.reportSuiteResults = function(suite) { +}; + +//noinspection JSUnusedLocalSymbols +jasmine.Reporter.prototype.reportSpecStarting = function(spec) { +}; + +//noinspection JSUnusedLocalSymbols +jasmine.Reporter.prototype.reportSpecResults = function(spec) { +}; + +//noinspection JSUnusedLocalSymbols +jasmine.Reporter.prototype.log = function(str) { +}; + +/** + * Blocks are functions with executable code that make up a spec. + * + * @constructor + * @param {jasmine.Env} env + * @param {Function} func + * @param {jasmine.Spec} spec + */ +jasmine.Block = function(env, func, spec) { + this.env = env; + this.func = func; + this.spec = spec; +}; + +jasmine.Block.prototype.execute = function(onComplete) { + try { + this.func.apply(this.spec); + } catch (e) { + this.spec.fail(e); + } + onComplete(); +}; +/** JavaScript API reporter. + * + * @constructor + */ +jasmine.JsApiReporter = function() { + this.started = false; + this.finished = false; + this.suites_ = []; + this.results_ = {}; +}; + +jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) { + this.started = true; + var suites = runner.topLevelSuites(); + for (var i = 0; i < suites.length; i++) { + var suite = suites[i]; + this.suites_.push(this.summarize_(suite)); + } +}; + +jasmine.JsApiReporter.prototype.suites = function() { + return this.suites_; +}; + +jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) { + var isSuite = suiteOrSpec instanceof jasmine.Suite; + var summary = { + id: suiteOrSpec.id, + name: suiteOrSpec.description, + type: isSuite ? 'suite' : 'spec', + children: [] + }; + + if (isSuite) { + var children = suiteOrSpec.children(); + for (var i = 0; i < children.length; i++) { + summary.children.push(this.summarize_(children[i])); + } + } + return summary; +}; + +jasmine.JsApiReporter.prototype.results = function() { + return this.results_; +}; + +jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) { + return this.results_[specId]; +}; + +//noinspection JSUnusedLocalSymbols +jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) { + this.finished = true; +}; + +//noinspection JSUnusedLocalSymbols +jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) { +}; + +//noinspection JSUnusedLocalSymbols +jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) { + this.results_[spec.id] = { + messages: spec.results().getItems(), + result: spec.results().failedCount > 0 ? "failed" : "passed" + }; +}; + +//noinspection JSUnusedLocalSymbols +jasmine.JsApiReporter.prototype.log = function(str) { +}; + +jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){ + var results = {}; + for (var i = 0; i < specIds.length; i++) { + var specId = specIds[i]; + results[specId] = this.summarizeResult_(this.results_[specId]); + } + return results; +}; + +jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){ + var summaryMessages = []; + var messagesLength = result.messages.length; + for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) { + var resultMessage = result.messages[messageIndex]; + summaryMessages.push({ + text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined, + passed: resultMessage.passed ? resultMessage.passed() : true, + type: resultMessage.type, + message: resultMessage.message, + trace: { + stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined + } + }); + } + + return { + result : result.result, + messages : summaryMessages + }; +}; + +/** + * @constructor + * @param {jasmine.Env} env + * @param actual + * @param {jasmine.Spec} spec + */ +jasmine.Matchers = function(env, actual, spec, opt_isNot) { + this.env = env; + this.actual = actual; + this.spec = spec; + this.isNot = opt_isNot || false; + this.reportWasCalled_ = false; +}; + +// todo: @deprecated as of Jasmine 0.11, remove soon [xw] +jasmine.Matchers.pp = function(str) { + throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!"); +}; + +// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw] +jasmine.Matchers.prototype.report = function(result, failing_message, details) { + throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs"); +}; + +jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) { + for (var methodName in prototype) { + if (methodName == 'report') continue; + var orig = prototype[methodName]; + matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig); + } +}; + +jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) { + return function() { + var matcherArgs = jasmine.util.argsToArray(arguments); + var result = matcherFunction.apply(this, arguments); + + if (this.isNot) { + result = !result; + } + + if (this.reportWasCalled_) return result; + + var message; + if (!result) { + if (this.message) { + message = this.message.apply(this, arguments); + if (jasmine.isArray_(message)) { + message = message[this.isNot ? 1 : 0]; + } + } else { + var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); }); + message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate; + if (matcherArgs.length > 0) { + for (var i = 0; i < matcherArgs.length; i++) { + if (i > 0) message += ","; + message += " " + jasmine.pp(matcherArgs[i]); + } + } + message += "."; + } + } + var expectationResult = new jasmine.ExpectationResult({ + matcherName: matcherName, + passed: result, + expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0], + actual: this.actual, + message: message + }); + this.spec.addMatcherResult(expectationResult); + return jasmine.undefined; + }; +}; + + + + +/** + * toBe: compares the actual to the expected using === + * @param expected + */ +jasmine.Matchers.prototype.toBe = function(expected) { + return this.actual === expected; +}; + +/** + * toNotBe: compares the actual to the expected using !== + * @param expected + * @deprecated as of 1.0. Use not.toBe() instead. + */ +jasmine.Matchers.prototype.toNotBe = function(expected) { + return this.actual !== expected; +}; + +/** + * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc. + * + * @param expected + */ +jasmine.Matchers.prototype.toEqual = function(expected) { + return this.env.equals_(this.actual, expected); +}; + +/** + * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual + * @param expected + * @deprecated as of 1.0. Use not.toNotEqual() instead. + */ +jasmine.Matchers.prototype.toNotEqual = function(expected) { + return !this.env.equals_(this.actual, expected); +}; + +/** + * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes + * a pattern or a String. + * + * @param expected + */ +jasmine.Matchers.prototype.toMatch = function(expected) { + return new RegExp(expected).test(this.actual); +}; + +/** + * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch + * @param expected + * @deprecated as of 1.0. Use not.toMatch() instead. + */ +jasmine.Matchers.prototype.toNotMatch = function(expected) { + return !(new RegExp(expected).test(this.actual)); +}; + +/** + * Matcher that compares the actual to jasmine.undefined. + */ +jasmine.Matchers.prototype.toBeDefined = function() { + return (this.actual !== jasmine.undefined); +}; + +/** + * Matcher that compares the actual to jasmine.undefined. + */ +jasmine.Matchers.prototype.toBeUndefined = function() { + return (this.actual === jasmine.undefined); +}; + +/** + * Matcher that compares the actual to null. + */ +jasmine.Matchers.prototype.toBeNull = function() { + return (this.actual === null); +}; + +/** + * Matcher that boolean not-nots the actual. + */ +jasmine.Matchers.prototype.toBeTruthy = function() { + return !!this.actual; +}; + + +/** + * Matcher that boolean nots the actual. + */ +jasmine.Matchers.prototype.toBeFalsy = function() { + return !this.actual; +}; + + +/** + * Matcher that checks to see if the actual, a Jasmine spy, was called. + */ +jasmine.Matchers.prototype.toHaveBeenCalled = function() { + if (arguments.length > 0) { + throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith'); + } + + if (!jasmine.isSpy(this.actual)) { + throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); + } + + this.message = function() { + return [ + "Expected spy " + this.actual.identity + " to have been called.", + "Expected spy " + this.actual.identity + " not to have been called." + ]; + }; + + return this.actual.wasCalled; +}; + +/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */ +jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled; + +/** + * Matcher that checks to see if the actual, a Jasmine spy, was not called. + * + * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead + */ +jasmine.Matchers.prototype.wasNotCalled = function() { + if (arguments.length > 0) { + throw new Error('wasNotCalled does not take arguments'); + } + + if (!jasmine.isSpy(this.actual)) { + throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); + } + + this.message = function() { + return [ + "Expected spy " + this.actual.identity + " to not have been called.", + "Expected spy " + this.actual.identity + " to have been called." + ]; + }; + + return !this.actual.wasCalled; +}; + +/** + * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters. + * + * @example + * + */ +jasmine.Matchers.prototype.toHaveBeenCalledWith = function() { + var expectedArgs = jasmine.util.argsToArray(arguments); + if (!jasmine.isSpy(this.actual)) { + throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); + } + this.message = function() { + if (this.actual.callCount === 0) { + // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw] + return [ + "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.", + "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was." + ]; + } else { + return [ + "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall), + "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall) + ]; + } + }; + + return this.env.contains_(this.actual.argsForCall, expectedArgs); +}; + +/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */ +jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith; + +/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */ +jasmine.Matchers.prototype.wasNotCalledWith = function() { + var expectedArgs = jasmine.util.argsToArray(arguments); + if (!jasmine.isSpy(this.actual)) { + throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); + } + + this.message = function() { + return [ + "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was", + "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was" + ]; + }; + + return !this.env.contains_(this.actual.argsForCall, expectedArgs); +}; + +/** + * Matcher that checks that the expected item is an element in the actual Array. + * + * @param {Object} expected + */ +jasmine.Matchers.prototype.toContain = function(expected) { + return this.env.contains_(this.actual, expected); +}; + +/** + * Matcher that checks that the expected item is NOT an element in the actual Array. + * + * @param {Object} expected + * @deprecated as of 1.0. Use not.toNotContain() instead. + */ +jasmine.Matchers.prototype.toNotContain = function(expected) { + return !this.env.contains_(this.actual, expected); +}; + +jasmine.Matchers.prototype.toBeLessThan = function(expected) { + return this.actual < expected; +}; + +jasmine.Matchers.prototype.toBeGreaterThan = function(expected) { + return this.actual > expected; +}; + +/** + * Matcher that checks that the expected item is equal to the actual item + * up to a given level of decimal precision (default 2). + * + * @param {Number} expected + * @param {Number} precision + */ +jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) { + if (!(precision === 0)) { + precision = precision || 2; + } + var multiplier = Math.pow(10, precision); + var actual = Math.round(this.actual * multiplier); + expected = Math.round(expected * multiplier); + return expected == actual; +}; + +/** + * Matcher that checks that the expected exception was thrown by the actual. + * + * @param {String} expected + */ +jasmine.Matchers.prototype.toThrow = function(expected) { + var result = false; + var exception; + if (typeof this.actual != 'function') { + throw new Error('Actual is not a function'); + } + try { + this.actual(); + } catch (e) { + exception = e; + } + if (exception) { + result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected)); + } + + var not = this.isNot ? "not " : ""; + + this.message = function() { + if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) { + return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' '); + } else { + return "Expected function to throw an exception."; + } + }; + + return result; +}; + +jasmine.Matchers.Any = function(expectedClass) { + this.expectedClass = expectedClass; +}; + +jasmine.Matchers.Any.prototype.matches = function(other) { + if (this.expectedClass == String) { + return typeof other == 'string' || other instanceof String; + } + + if (this.expectedClass == Number) { + return typeof other == 'number' || other instanceof Number; + } + + if (this.expectedClass == Function) { + return typeof other == 'function' || other instanceof Function; + } + + if (this.expectedClass == Object) { + return typeof other == 'object'; + } + + return other instanceof this.expectedClass; +}; + +jasmine.Matchers.Any.prototype.toString = function() { + return ''; +}; + +/** + * @constructor + */ +jasmine.MultiReporter = function() { + this.subReporters_ = []; +}; +jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter); + +jasmine.MultiReporter.prototype.addReporter = function(reporter) { + this.subReporters_.push(reporter); +}; + +(function() { + var functionNames = [ + "reportRunnerStarting", + "reportRunnerResults", + "reportSuiteResults", + "reportSpecStarting", + "reportSpecResults", + "log" + ]; + for (var i = 0; i < functionNames.length; i++) { + var functionName = functionNames[i]; + jasmine.MultiReporter.prototype[functionName] = (function(functionName) { + return function() { + for (var j = 0; j < this.subReporters_.length; j++) { + var subReporter = this.subReporters_[j]; + if (subReporter[functionName]) { + subReporter[functionName].apply(subReporter, arguments); + } + } + }; + })(functionName); + } +})(); +/** + * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults + * + * @constructor + */ +jasmine.NestedResults = function() { + /** + * The total count of results + */ + this.totalCount = 0; + /** + * Number of passed results + */ + this.passedCount = 0; + /** + * Number of failed results + */ + this.failedCount = 0; + /** + * Was this suite/spec skipped? + */ + this.skipped = false; + /** + * @ignore + */ + this.items_ = []; +}; + +/** + * Roll up the result counts. + * + * @param result + */ +jasmine.NestedResults.prototype.rollupCounts = function(result) { + this.totalCount += result.totalCount; + this.passedCount += result.passedCount; + this.failedCount += result.failedCount; +}; + +/** + * Adds a log message. + * @param values Array of message parts which will be concatenated later. + */ +jasmine.NestedResults.prototype.log = function(values) { + this.items_.push(new jasmine.MessageResult(values)); +}; + +/** + * Getter for the results: message & results. + */ +jasmine.NestedResults.prototype.getItems = function() { + return this.items_; +}; + +/** + * Adds a result, tracking counts (total, passed, & failed) + * @param {jasmine.ExpectationResult|jasmine.NestedResults} result + */ +jasmine.NestedResults.prototype.addResult = function(result) { + if (result.type != 'log') { + if (result.items_) { + this.rollupCounts(result); + } else { + this.totalCount++; + if (result.passed()) { + this.passedCount++; + } else { + this.failedCount++; + } + } + } + this.items_.push(result); +}; + +/** + * @returns {Boolean} True if everything below passed + */ +jasmine.NestedResults.prototype.passed = function() { + return this.passedCount === this.totalCount; +}; +/** + * Base class for pretty printing for expectation results. + */ +jasmine.PrettyPrinter = function() { + this.ppNestLevel_ = 0; +}; + +/** + * Formats a value in a nice, human-readable string. + * + * @param value + */ +jasmine.PrettyPrinter.prototype.format = function(value) { + if (this.ppNestLevel_ > 40) { + throw new Error('jasmine.PrettyPrinter: format() nested too deeply!'); + } + + this.ppNestLevel_++; + try { + if (value === jasmine.undefined) { + this.emitScalar('undefined'); + } else if (value === null) { + this.emitScalar('null'); + } else if (value === jasmine.getGlobal()) { + this.emitScalar(''); + } else if (value instanceof jasmine.Matchers.Any) { + this.emitScalar(value.toString()); + } else if (typeof value === 'string') { + this.emitString(value); + } else if (jasmine.isSpy(value)) { + this.emitScalar("spy on " + value.identity); + } else if (value instanceof RegExp) { + this.emitScalar(value.toString()); + } else if (typeof value === 'function') { + this.emitScalar('Function'); + } else if (typeof value.nodeType === 'number') { + this.emitScalar('HTMLNode'); + } else if (value instanceof Date) { + this.emitScalar('Date(' + value + ')'); + } else if (value.__Jasmine_been_here_before__) { + this.emitScalar(''); + } else if (jasmine.isArray_(value) || typeof value == 'object') { + value.__Jasmine_been_here_before__ = true; + if (jasmine.isArray_(value)) { + this.emitArray(value); + } else { + this.emitObject(value); + } + delete value.__Jasmine_been_here_before__; + } else { + this.emitScalar(value.toString()); + } + } finally { + this.ppNestLevel_--; + } +}; + +jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { + for (var property in obj) { + if (property == '__Jasmine_been_here_before__') continue; + fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined && + obj.__lookupGetter__(property) !== null) : false); + } +}; + +jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_; +jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_; +jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_; +jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_; + +jasmine.StringPrettyPrinter = function() { + jasmine.PrettyPrinter.call(this); + + this.string = ''; +}; +jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter); + +jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) { + this.append(value); +}; + +jasmine.StringPrettyPrinter.prototype.emitString = function(value) { + this.append("'" + value + "'"); +}; + +jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { + this.append('[ '); + for (var i = 0; i < array.length; i++) { + if (i > 0) { + this.append(', '); + } + this.format(array[i]); + } + this.append(' ]'); +}; + +jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { + var self = this; + this.append('{ '); + var first = true; + + this.iterateObject(obj, function(property, isGetter) { + if (first) { + first = false; + } else { + self.append(', '); + } + + self.append(property); + self.append(' : '); + if (isGetter) { + self.append(''); + } else { + self.format(obj[property]); + } + }); + + this.append(' }'); +}; + +jasmine.StringPrettyPrinter.prototype.append = function(value) { + this.string += value; +}; +jasmine.Queue = function(env) { + this.env = env; + this.blocks = []; + this.running = false; + this.index = 0; + this.offset = 0; + this.abort = false; +}; + +jasmine.Queue.prototype.addBefore = function(block) { + this.blocks.unshift(block); +}; + +jasmine.Queue.prototype.add = function(block) { + this.blocks.push(block); +}; + +jasmine.Queue.prototype.insertNext = function(block) { + this.blocks.splice((this.index + this.offset + 1), 0, block); + this.offset++; +}; + +jasmine.Queue.prototype.start = function(onComplete) { + this.running = true; + this.onComplete = onComplete; + this.next_(); +}; + +jasmine.Queue.prototype.isRunning = function() { + return this.running; +}; + +jasmine.Queue.LOOP_DONT_RECURSE = true; + +jasmine.Queue.prototype.next_ = function() { + var self = this; + var goAgain = true; + + while (goAgain) { + goAgain = false; + + if (self.index < self.blocks.length && !this.abort) { + var calledSynchronously = true; + var completedSynchronously = false; + + var onComplete = function () { + if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) { + completedSynchronously = true; + return; + } + + if (self.blocks[self.index].abort) { + self.abort = true; + } + + self.offset = 0; + self.index++; + + var now = new Date().getTime(); + if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) { + self.env.lastUpdate = now; + self.env.setTimeout(function() { + self.next_(); + }, 0); + } else { + if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) { + goAgain = true; + } else { + self.next_(); + } + } + }; + self.blocks[self.index].execute(onComplete); + + calledSynchronously = false; + if (completedSynchronously) { + onComplete(); + } + + } else { + self.running = false; + if (self.onComplete) { + self.onComplete(); + } + } + } +}; + +jasmine.Queue.prototype.results = function() { + var results = new jasmine.NestedResults(); + for (var i = 0; i < this.blocks.length; i++) { + if (this.blocks[i].results) { + results.addResult(this.blocks[i].results()); + } + } + return results; +}; + + +/** + * Runner + * + * @constructor + * @param {jasmine.Env} env + */ +jasmine.Runner = function(env) { + var self = this; + self.env = env; + self.queue = new jasmine.Queue(env); + self.before_ = []; + self.after_ = []; + self.suites_ = []; +}; + +jasmine.Runner.prototype.execute = function() { + var self = this; + if (self.env.reporter.reportRunnerStarting) { + self.env.reporter.reportRunnerStarting(this); + } + self.queue.start(function () { + self.finishCallback(); + }); +}; + +jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) { + beforeEachFunction.typeName = 'beforeEach'; + this.before_.splice(0,0,beforeEachFunction); +}; + +jasmine.Runner.prototype.afterEach = function(afterEachFunction) { + afterEachFunction.typeName = 'afterEach'; + this.after_.splice(0,0,afterEachFunction); +}; + + +jasmine.Runner.prototype.finishCallback = function() { + this.env.reporter.reportRunnerResults(this); +}; + +jasmine.Runner.prototype.addSuite = function(suite) { + this.suites_.push(suite); +}; + +jasmine.Runner.prototype.add = function(block) { + if (block instanceof jasmine.Suite) { + this.addSuite(block); + } + this.queue.add(block); +}; + +jasmine.Runner.prototype.specs = function () { + var suites = this.suites(); + var specs = []; + for (var i = 0; i < suites.length; i++) { + specs = specs.concat(suites[i].specs()); + } + return specs; +}; + +jasmine.Runner.prototype.suites = function() { + return this.suites_; +}; + +jasmine.Runner.prototype.topLevelSuites = function() { + var topLevelSuites = []; + for (var i = 0; i < this.suites_.length; i++) { + if (!this.suites_[i].parentSuite) { + topLevelSuites.push(this.suites_[i]); + } + } + return topLevelSuites; +}; + +jasmine.Runner.prototype.results = function() { + return this.queue.results(); +}; +/** + * Internal representation of a Jasmine specification, or test. + * + * @constructor + * @param {jasmine.Env} env + * @param {jasmine.Suite} suite + * @param {String} description + */ +jasmine.Spec = function(env, suite, description) { + if (!env) { + throw new Error('jasmine.Env() required'); + } + if (!suite) { + throw new Error('jasmine.Suite() required'); + } + var spec = this; + spec.id = env.nextSpecId ? env.nextSpecId() : null; + spec.env = env; + spec.suite = suite; + spec.description = description; + spec.queue = new jasmine.Queue(env); + + spec.afterCallbacks = []; + spec.spies_ = []; + + spec.results_ = new jasmine.NestedResults(); + spec.results_.description = description; + spec.matchersClass = null; +}; + +jasmine.Spec.prototype.getFullName = function() { + return this.suite.getFullName() + ' ' + this.description + '.'; +}; + + +jasmine.Spec.prototype.results = function() { + return this.results_; +}; + +/** + * All parameters are pretty-printed and concatenated together, then written to the spec's output. + * + * Be careful not to leave calls to jasmine.log in production code. + */ +jasmine.Spec.prototype.log = function() { + return this.results_.log(arguments); +}; + +jasmine.Spec.prototype.runs = function (func) { + var block = new jasmine.Block(this.env, func, this); + this.addToQueue(block); + return this; +}; + +jasmine.Spec.prototype.addToQueue = function (block) { + if (this.queue.isRunning()) { + this.queue.insertNext(block); + } else { + this.queue.add(block); + } +}; + +/** + * @param {jasmine.ExpectationResult} result + */ +jasmine.Spec.prototype.addMatcherResult = function(result) { + this.results_.addResult(result); +}; + +jasmine.Spec.prototype.expect = function(actual) { + var positive = new (this.getMatchersClass_())(this.env, actual, this); + positive.not = new (this.getMatchersClass_())(this.env, actual, this, true); + return positive; +}; + +/** + * Waits a fixed time period before moving to the next block. + * + * @deprecated Use waitsFor() instead + * @param {Number} timeout milliseconds to wait + */ +jasmine.Spec.prototype.waits = function(timeout) { + var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this); + this.addToQueue(waitsFunc); + return this; +}; + +/** + * Waits for the latchFunction to return true before proceeding to the next block. + * + * @param {Function} latchFunction + * @param {String} optional_timeoutMessage + * @param {Number} optional_timeout + */ +jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { + var latchFunction_ = null; + var optional_timeoutMessage_ = null; + var optional_timeout_ = null; + + for (var i = 0; i < arguments.length; i++) { + var arg = arguments[i]; + switch (typeof arg) { + case 'function': + latchFunction_ = arg; + break; + case 'string': + optional_timeoutMessage_ = arg; + break; + case 'number': + optional_timeout_ = arg; + break; + } + } + + var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this); + this.addToQueue(waitsForFunc); + return this; +}; + +jasmine.Spec.prototype.fail = function (e) { + var expectationResult = new jasmine.ExpectationResult({ + passed: false, + message: e ? jasmine.util.formatException(e) : 'Exception', + trace: { stack: e.stack } + }); + this.results_.addResult(expectationResult); +}; + +jasmine.Spec.prototype.getMatchersClass_ = function() { + return this.matchersClass || this.env.matchersClass; +}; + +jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { + var parent = this.getMatchersClass_(); + var newMatchersClass = function() { + parent.apply(this, arguments); + }; + jasmine.util.inherit(newMatchersClass, parent); + jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass); + this.matchersClass = newMatchersClass; +}; + +jasmine.Spec.prototype.finishCallback = function() { + this.env.reporter.reportSpecResults(this); +}; + +jasmine.Spec.prototype.finish = function(onComplete) { + this.removeAllSpies(); + this.finishCallback(); + if (onComplete) { + onComplete(); + } +}; + +jasmine.Spec.prototype.after = function(doAfter) { + if (this.queue.isRunning()) { + this.queue.add(new jasmine.Block(this.env, doAfter, this)); + } else { + this.afterCallbacks.unshift(doAfter); + } +}; + +jasmine.Spec.prototype.execute = function(onComplete) { + var spec = this; + if (!spec.env.specFilter(spec)) { + spec.results_.skipped = true; + spec.finish(onComplete); + return; + } + + this.env.reporter.reportSpecStarting(this); + + spec.env.currentSpec = spec; + + spec.addBeforesAndAftersToQueue(); + + spec.queue.start(function () { + spec.finish(onComplete); + }); +}; + +jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() { + var runner = this.env.currentRunner(); + var i; + + for (var suite = this.suite; suite; suite = suite.parentSuite) { + for (i = 0; i < suite.before_.length; i++) { + this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this)); + } + } + for (i = 0; i < runner.before_.length; i++) { + this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this)); + } + for (i = 0; i < this.afterCallbacks.length; i++) { + this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this)); + } + for (suite = this.suite; suite; suite = suite.parentSuite) { + for (i = 0; i < suite.after_.length; i++) { + this.queue.add(new jasmine.Block(this.env, suite.after_[i], this)); + } + } + for (i = 0; i < runner.after_.length; i++) { + this.queue.add(new jasmine.Block(this.env, runner.after_[i], this)); + } +}; + +jasmine.Spec.prototype.explodes = function() { + throw 'explodes function should not have been called'; +}; + +jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) { + if (obj == jasmine.undefined) { + throw "spyOn could not find an object to spy upon for " + methodName + "()"; + } + + if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) { + throw methodName + '() method does not exist'; + } + + if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) { + throw new Error(methodName + ' has already been spied upon'); + } + + var spyObj = jasmine.createSpy(methodName); + + this.spies_.push(spyObj); + spyObj.baseObj = obj; + spyObj.methodName = methodName; + spyObj.originalValue = obj[methodName]; + + obj[methodName] = spyObj; + + return spyObj; +}; + +jasmine.Spec.prototype.removeAllSpies = function() { + for (var i = 0; i < this.spies_.length; i++) { + var spy = this.spies_[i]; + spy.baseObj[spy.methodName] = spy.originalValue; + } + this.spies_ = []; +}; + +/** + * Internal representation of a Jasmine suite. + * + * @constructor + * @param {jasmine.Env} env + * @param {String} description + * @param {Function} specDefinitions + * @param {jasmine.Suite} parentSuite + */ +jasmine.Suite = function(env, description, specDefinitions, parentSuite) { + var self = this; + self.id = env.nextSuiteId ? env.nextSuiteId() : null; + self.description = description; + self.queue = new jasmine.Queue(env); + self.parentSuite = parentSuite; + self.env = env; + self.before_ = []; + self.after_ = []; + self.children_ = []; + self.suites_ = []; + self.specs_ = []; +}; + +jasmine.Suite.prototype.getFullName = function() { + var fullName = this.description; + for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { + fullName = parentSuite.description + ' ' + fullName; + } + return fullName; +}; + +jasmine.Suite.prototype.finish = function(onComplete) { + this.env.reporter.reportSuiteResults(this); + this.finished = true; + if (typeof(onComplete) == 'function') { + onComplete(); + } +}; + +jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) { + beforeEachFunction.typeName = 'beforeEach'; + this.before_.unshift(beforeEachFunction); +}; + +jasmine.Suite.prototype.afterEach = function(afterEachFunction) { + afterEachFunction.typeName = 'afterEach'; + this.after_.unshift(afterEachFunction); +}; + +jasmine.Suite.prototype.results = function() { + return this.queue.results(); +}; + +jasmine.Suite.prototype.add = function(suiteOrSpec) { + this.children_.push(suiteOrSpec); + if (suiteOrSpec instanceof jasmine.Suite) { + this.suites_.push(suiteOrSpec); + this.env.currentRunner().addSuite(suiteOrSpec); + } else { + this.specs_.push(suiteOrSpec); + } + this.queue.add(suiteOrSpec); +}; + +jasmine.Suite.prototype.specs = function() { + return this.specs_; +}; + +jasmine.Suite.prototype.suites = function() { + return this.suites_; +}; + +jasmine.Suite.prototype.children = function() { + return this.children_; +}; + +jasmine.Suite.prototype.execute = function(onComplete) { + var self = this; + this.queue.start(function () { + self.finish(onComplete); + }); +}; +jasmine.WaitsBlock = function(env, timeout, spec) { + this.timeout = timeout; + jasmine.Block.call(this, env, null, spec); +}; + +jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block); + +jasmine.WaitsBlock.prototype.execute = function (onComplete) { + if (jasmine.VERBOSE) { + this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...'); + } + this.env.setTimeout(function () { + onComplete(); + }, this.timeout); +}; +/** + * A block which waits for some condition to become true, with timeout. + * + * @constructor + * @extends jasmine.Block + * @param {jasmine.Env} env The Jasmine environment. + * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true. + * @param {Function} latchFunction A function which returns true when the desired condition has been met. + * @param {String} message The message to display if the desired condition hasn't been met within the given time period. + * @param {jasmine.Spec} spec The Jasmine spec. + */ +jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) { + this.timeout = timeout || env.defaultTimeoutInterval; + this.latchFunction = latchFunction; + this.message = message; + this.totalTimeSpentWaitingForLatch = 0; + jasmine.Block.call(this, env, null, spec); +}; +jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block); + +jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10; + +jasmine.WaitsForBlock.prototype.execute = function(onComplete) { + if (jasmine.VERBOSE) { + this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen')); + } + var latchFunctionResult; + try { + latchFunctionResult = this.latchFunction.apply(this.spec); + } catch (e) { + this.spec.fail(e); + onComplete(); + return; + } + + if (latchFunctionResult) { + onComplete(); + } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) { + var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen'); + this.spec.fail({ + name: 'timeout', + message: message + }); + + this.abort = true; + onComplete(); + } else { + this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT; + var self = this; + this.env.setTimeout(function() { + self.execute(onComplete); + }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT); + } +}; +// Mock setTimeout, clearTimeout +// Contributed by Pivotal Computer Systems, www.pivotalsf.com + +jasmine.FakeTimer = function() { + this.reset(); + + var self = this; + self.setTimeout = function(funcToCall, millis) { + self.timeoutsMade++; + self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false); + return self.timeoutsMade; + }; + + self.setInterval = function(funcToCall, millis) { + self.timeoutsMade++; + self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true); + return self.timeoutsMade; + }; + + self.clearTimeout = function(timeoutKey) { + self.scheduledFunctions[timeoutKey] = jasmine.undefined; + }; + + self.clearInterval = function(timeoutKey) { + self.scheduledFunctions[timeoutKey] = jasmine.undefined; + }; + +}; + +jasmine.FakeTimer.prototype.reset = function() { + this.timeoutsMade = 0; + this.scheduledFunctions = {}; + this.nowMillis = 0; +}; + +jasmine.FakeTimer.prototype.tick = function(millis) { + var oldMillis = this.nowMillis; + var newMillis = oldMillis + millis; + this.runFunctionsWithinRange(oldMillis, newMillis); + this.nowMillis = newMillis; +}; + +jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) { + var scheduledFunc; + var funcsToRun = []; + for (var timeoutKey in this.scheduledFunctions) { + scheduledFunc = this.scheduledFunctions[timeoutKey]; + if (scheduledFunc != jasmine.undefined && + scheduledFunc.runAtMillis >= oldMillis && + scheduledFunc.runAtMillis <= nowMillis) { + funcsToRun.push(scheduledFunc); + this.scheduledFunctions[timeoutKey] = jasmine.undefined; + } + } + + if (funcsToRun.length > 0) { + funcsToRun.sort(function(a, b) { + return a.runAtMillis - b.runAtMillis; + }); + for (var i = 0; i < funcsToRun.length; ++i) { + try { + var funcToRun = funcsToRun[i]; + this.nowMillis = funcToRun.runAtMillis; + funcToRun.funcToCall(); + if (funcToRun.recurring) { + this.scheduleFunction(funcToRun.timeoutKey, + funcToRun.funcToCall, + funcToRun.millis, + true); + } + } catch(e) { + } + } + this.runFunctionsWithinRange(oldMillis, nowMillis); + } +}; + +jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) { + this.scheduledFunctions[timeoutKey] = { + runAtMillis: this.nowMillis + millis, + funcToCall: funcToCall, + recurring: recurring, + timeoutKey: timeoutKey, + millis: millis + }; +}; + +/** + * @namespace + */ +jasmine.Clock = { + defaultFakeTimer: new jasmine.FakeTimer(), + + reset: function() { + jasmine.Clock.assertInstalled(); + jasmine.Clock.defaultFakeTimer.reset(); + }, + + tick: function(millis) { + jasmine.Clock.assertInstalled(); + jasmine.Clock.defaultFakeTimer.tick(millis); + }, + + runFunctionsWithinRange: function(oldMillis, nowMillis) { + jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis); + }, + + scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) { + jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring); + }, + + useMock: function() { + if (!jasmine.Clock.isInstalled()) { + var spec = jasmine.getEnv().currentSpec; + spec.after(jasmine.Clock.uninstallMock); + + jasmine.Clock.installMock(); + } + }, + + installMock: function() { + jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer; + }, + + uninstallMock: function() { + jasmine.Clock.assertInstalled(); + jasmine.Clock.installed = jasmine.Clock.real; + }, + + real: { + setTimeout: jasmine.getGlobal().setTimeout, + clearTimeout: jasmine.getGlobal().clearTimeout, + setInterval: jasmine.getGlobal().setInterval, + clearInterval: jasmine.getGlobal().clearInterval + }, + + assertInstalled: function() { + if (!jasmine.Clock.isInstalled()) { + throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()"); + } + }, + + isInstalled: function() { + return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer; + }, + + installed: null +}; +jasmine.Clock.installed = jasmine.Clock.real; + +//else for IE support +jasmine.getGlobal().setTimeout = function(funcToCall, millis) { + if (jasmine.Clock.installed.setTimeout.apply) { + return jasmine.Clock.installed.setTimeout.apply(this, arguments); + } else { + return jasmine.Clock.installed.setTimeout(funcToCall, millis); + } +}; + +jasmine.getGlobal().setInterval = function(funcToCall, millis) { + if (jasmine.Clock.installed.setInterval.apply) { + return jasmine.Clock.installed.setInterval.apply(this, arguments); + } else { + return jasmine.Clock.installed.setInterval(funcToCall, millis); + } +}; + +jasmine.getGlobal().clearTimeout = function(timeoutKey) { + if (jasmine.Clock.installed.clearTimeout.apply) { + return jasmine.Clock.installed.clearTimeout.apply(this, arguments); + } else { + return jasmine.Clock.installed.clearTimeout(timeoutKey); + } +}; + +jasmine.getGlobal().clearInterval = function(timeoutKey) { + if (jasmine.Clock.installed.clearTimeout.apply) { + return jasmine.Clock.installed.clearInterval.apply(this, arguments); + } else { + return jasmine.Clock.installed.clearInterval(timeoutKey); + } +}; + +jasmine.version_= { + "major": 1, + "minor": 1, + "build": 0, + "revision": 1315677058 +}; diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/jasmine-1.1.0/jasmine_favicon.png b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/jasmine-1.1.0/jasmine_favicon.png new file mode 100644 index 0000000..218f3b4 Binary files /dev/null and b/node_modules/mongoose/node_modules/mongodb/node_modules/bson/tools/jasmine-1.1.0/jasmine_favicon.png differ diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/LICENSE b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/README.md b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/README.md new file mode 100644 index 0000000..7428b0d --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/README.md @@ -0,0 +1,4 @@ +kerberos +======== + +Kerberos library for node.js \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/binding.gyp b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/binding.gyp new file mode 100644 index 0000000..027a70f --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/binding.gyp @@ -0,0 +1,41 @@ +{ + 'targets': [ + { + 'target_name': 'kerberos', + 'cflags!': [ '-fno-exceptions' ], + 'cflags_cc!': [ '-fno-exceptions' ], + 'conditions': [ + ['OS=="mac"', { + 'sources': [ 'lib/kerberos.cc', 'lib/worker.cc', 'lib/kerberosgss.c', 'lib/base64.c', 'lib/kerberos_context.cc' ], + 'defines': [ + '__MACOSX_CORE__' + ], + 'xcode_settings': { + 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES' + }, + "link_settings": { + "libraries": [ + "-lkrb5" + ] + } + }], + ['OS=="win"', { + 'sources': [ + 'lib/win32/kerberos.cc', + 'lib/win32/base64.c', + 'lib/win32/worker.cc', + 'lib/win32/kerberos_sspi.c', + 'lib/win32/wrappers/security_buffer.cc', + 'lib/win32/wrappers/security_buffer_descriptor.cc', + 'lib/win32/wrappers/security_context.cc', + 'lib/win32/wrappers/security_credentials.cc' + ], + "link_settings": { + "libraries": [ + ] + } + }] + ] + } + ] +} \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Makefile b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Makefile new file mode 100644 index 0000000..f366b39 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Makefile @@ -0,0 +1,354 @@ +# We borrow heavily from the kernel build setup, though we are simpler since +# we don't have Kconfig tweaking settings on us. + +# The implicit make rules have it looking for RCS files, among other things. +# We instead explicitly write all the rules we care about. +# It's even quicker (saves ~200ms) to pass -r on the command line. +MAKEFLAGS=-r + +# The source directory tree. +srcdir := .. +abs_srcdir := $(abspath $(srcdir)) + +# The name of the builddir. +builddir_name ?= . + +# The V=1 flag on command line makes us verbosely print command lines. +ifdef V + quiet= +else + quiet=quiet_ +endif + +# Specify BUILDTYPE=Release on the command line for a release build. +BUILDTYPE ?= Release + +# Directory all our build output goes into. +# Note that this must be two directories beneath src/ for unit tests to pass, +# as they reach into the src/ directory for data with relative paths. +builddir ?= $(builddir_name)/$(BUILDTYPE) +abs_builddir := $(abspath $(builddir)) +depsdir := $(builddir)/.deps + +# Object output directory. +obj := $(builddir)/obj +abs_obj := $(abspath $(obj)) + +# We build up a list of every single one of the targets so we can slurp in the +# generated dependency rule Makefiles in one pass. +all_deps := + + + +# C++ apps need to be linked with g++. +# +# Note: flock is used to seralize linking. Linking is a memory-intensive +# process so running parallel links can often lead to thrashing. To disable +# the serialization, override LINK via an envrionment variable as follows: +# +# export LINK=g++ +# +# This will allow make to invoke N linker processes as specified in -jN. +LINK ?= ./gyp-mac-tool flock $(builddir)/linker.lock $(CXX.target) + +CC.target ?= $(CC) +CFLAGS.target ?= $(CFLAGS) +CXX.target ?= $(CXX) +CXXFLAGS.target ?= $(CXXFLAGS) +LINK.target ?= $(LINK) +LDFLAGS.target ?= $(LDFLAGS) +AR.target ?= $(AR) + +# TODO(evan): move all cross-compilation logic to gyp-time so we don't need +# to replicate this environment fallback in make as well. +CC.host ?= gcc +CFLAGS.host ?= +CXX.host ?= g++ +CXXFLAGS.host ?= +LINK.host ?= g++ +LDFLAGS.host ?= +AR.host ?= ar + +# Define a dir function that can handle spaces. +# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions +# "leading spaces cannot appear in the text of the first argument as written. +# These characters can be put into the argument value by variable substitution." +empty := +space := $(empty) $(empty) + +# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces +replace_spaces = $(subst $(space),?,$1) +unreplace_spaces = $(subst ?,$(space),$1) +dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1))) + +# Flags to make gcc output dependency info. Note that you need to be +# careful here to use the flags that ccache and distcc can understand. +# We write to a dep file on the side first and then rename at the end +# so we can't end up with a broken dep file. +depfile = $(depsdir)/$(call replace_spaces,$@).d +DEPFLAGS = -MMD -MF $(depfile).raw + +# We have to fixup the deps output in a few ways. +# (1) the file output should mention the proper .o file. +# ccache or distcc lose the path to the target, so we convert a rule of +# the form: +# foobar.o: DEP1 DEP2 +# into +# path/to/foobar.o: DEP1 DEP2 +# (2) we want missing files not to cause us to fail to build. +# We want to rewrite +# foobar.o: DEP1 DEP2 \ +# DEP3 +# to +# DEP1: +# DEP2: +# DEP3: +# so if the files are missing, they're just considered phony rules. +# We have to do some pretty insane escaping to get those backslashes +# and dollar signs past make, the shell, and sed at the same time. +# Doesn't work with spaces, but that's fine: .d files have spaces in +# their names replaced with other characters. +define fixup_dep +# The depfile may not exist if the input file didn't have any #includes. +touch $(depfile).raw +# Fixup path as in (1). +sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile) +# Add extra rules as in (2). +# We remove slashes and replace spaces with new lines; +# remove blank lines; +# delete the first line and append a colon to the remaining lines. +sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ + grep -v '^$$' |\ + sed -e 1d -e 's|$$|:|' \ + >> $(depfile) +rm $(depfile).raw +endef + +# Command definitions: +# - cmd_foo is the actual command to run; +# - quiet_cmd_foo is the brief-output summary of the command. + +quiet_cmd_cc = CC($(TOOLSET)) $@ +cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_cxx = CXX($(TOOLSET)) $@ +cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_objc = CXX($(TOOLSET)) $@ +cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< + +quiet_cmd_objcxx = CXX($(TOOLSET)) $@ +cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# Commands for precompiled header files. +quiet_cmd_pch_c = CXX($(TOOLSET)) $@ +cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_cc = CXX($(TOOLSET)) $@ +cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< +quiet_cmd_pch_m = CXX($(TOOLSET)) $@ +cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $< +quiet_cmd_pch_mm = CXX($(TOOLSET)) $@ +cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $< + +# gyp-mac-tool is written next to the root Makefile by gyp. +# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd +# already. +quiet_cmd_mac_tool = MACTOOL $(4) $< +cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@" + +quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@ +cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4) + +quiet_cmd_infoplist = INFOPLIST $@ +cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@" + +quiet_cmd_touch = TOUCH $@ +cmd_touch = touch $@ + +quiet_cmd_copy = COPY $@ +# send stderr to /dev/null to ignore messages when linking directories. +cmd_copy = rm -rf "$@" && cp -af "$<" "$@" + +quiet_cmd_alink = LIBTOOL-STATIC $@ +cmd_alink = rm -f $@ && ./gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^) + +quiet_cmd_link = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +# TODO(thakis): Find out and document the difference between shared_library and +# loadable_module on mac. +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS) + +# TODO(thakis): The solink_module rule is likely wrong. Xcode seems to pass +# -bundle -single_module here (for osmesa.so). +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) + + +# Define an escape_quotes function to escape single quotes. +# This allows us to handle quotes properly as long as we always use +# use single quotes and escape_quotes. +escape_quotes = $(subst ','\'',$(1)) +# This comment is here just to include a ' to unconfuse syntax highlighting. +# Define an escape_vars function to escape '$' variable syntax. +# This allows us to read/write command lines with shell variables (e.g. +# $LD_LIBRARY_PATH), without triggering make substitution. +escape_vars = $(subst $$,$$$$,$(1)) +# Helper that expands to a shell command to echo a string exactly as it is in +# make. This uses printf instead of echo because printf's behaviour with respect +# to escape sequences is more portable than echo's across different shells +# (e.g., dash, bash). +exact_echo = printf '%s\n' '$(call escape_quotes,$(1))' + +# Helper to compare the command we're about to run against the command +# we logged the last time we ran the command. Produces an empty +# string (false) when the commands match. +# Tricky point: Make has no string-equality test function. +# The kernel uses the following, but it seems like it would have false +# positives, where one string reordered its arguments. +# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ +# $(filter-out $(cmd_$@), $(cmd_$(1)))) +# We instead substitute each for the empty string into the other, and +# say they're equal if both substitutions produce the empty string. +# .d files contain ? instead of spaces, take that into account. +command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\ + $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1)))) + +# Helper that is non-empty when a prerequisite changes. +# Normally make does this implicitly, but we force rules to always run +# so we can check their command lines. +# $? -- new prerequisites +# $| -- order-only dependencies +prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) + +# Helper that executes all postbuilds until one fails. +define do_postbuilds + @E=0;\ + for p in $(POSTBUILDS); do\ + eval $$p;\ + E=$$?;\ + if [ $$E -ne 0 ]; then\ + break;\ + fi;\ + done;\ + if [ $$E -ne 0 ]; then\ + rm -rf "$@";\ + exit $$E;\ + fi +endef + +# do_cmd: run a command via the above cmd_foo names, if necessary. +# Should always run for a given target to handle command-line changes. +# Second argument, if non-zero, makes it do asm/C/C++ dependency munging. +# Third argument, if non-zero, makes it do POSTBUILDS processing. +# Note: We intentionally do NOT call dirx for depfile, since it contains ? for +# spaces already and dirx strips the ? characters. +define do_cmd +$(if $(or $(command_changed),$(prereq_changed)), + @$(call exact_echo, $($(quiet)cmd_$(1))) + @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))" + $(if $(findstring flock,$(word 2,$(cmd_$1))), + @$(cmd_$(1)) + @echo " $(quiet_cmd_$(1)): Finished", + @$(cmd_$(1)) + ) + @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) + @$(if $(2),$(fixup_dep)) + $(if $(and $(3), $(POSTBUILDS)), + $(call do_postbuilds) + ) +) +endef + +# Declare the "all" target first so it is the default, +# even though we don't have the deps yet. +.PHONY: all +all: + +# make looks for ways to re-generate included makefiles, but in our case, we +# don't have a direct way. Explicitly telling make that it has nothing to do +# for them makes it go faster. +%.d: ; + +# Use FORCE_DO_CMD to force a target to run. Should be coupled with +# do_cmd. +.PHONY: FORCE_DO_CMD +FORCE_DO_CMD: + +TOOLSET := target +# Suffix rules, putting all outputs into $(obj). +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.m FORCE_DO_CMD + @$(call do_cmd,objc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.mm FORCE_DO_CMD + @$(call do_cmd,objcxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) + + +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,kerberos.target.mk)))),) + include kerberos.target.mk +endif + +quiet_cmd_regen_makefile = ACTION Regenerating $@ +cmd_regen_makefile = /usr/local/Cellar/node/0.10.21/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -I/Users/brandon/OpenSource/mousewheeldatacollector/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/config.gypi -I/usr/local/Cellar/node/0.10.21/lib/node_modules/npm/node_modules/node-gyp/addon.gypi -I/Users/brandon/.node-gyp/0.10.21/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/brandon/.node-gyp/0.10.21" "-Dmodule_root_dir=/Users/brandon/OpenSource/mousewheeldatacollector/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos" binding.gyp +Makefile: $(srcdir)/../../../../../../../../.node-gyp/0.10.21/common.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp $(srcdir)/../../../../../../../../../../usr/local/Cellar/node/0.10.21/lib/node_modules/npm/node_modules/node-gyp/addon.gypi + $(call do_cmd,regen_makefile) + +# "all" is a concatenation of the "all" targets from all the included +# sub-makefiles. This is just here to clarify. +all: + +# Add in dependency-tracking rules. $(all_deps) is the list of every single +# target in our tree. Only consider the ones with .d (dependency) info: +d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) +ifneq ($(d_files),) + include $(d_files) +endif diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/kerberos.node.d b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/kerberos.node.d new file mode 100644 index 0000000..13950b5 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/kerberos.node.d @@ -0,0 +1 @@ +cmd_Release/kerberos.node := ./gyp-mac-tool flock ./Release/linker.lock c++ -shared -Wl,-search_paths_first -mmacosx-version-min=10.5 -arch x86_64 -L./Release -install_name @rpath/kerberos.node -o Release/kerberos.node Release/obj.target/kerberos/lib/kerberos.o Release/obj.target/kerberos/lib/worker.o Release/obj.target/kerberos/lib/kerberosgss.o Release/obj.target/kerberos/lib/base64.o Release/obj.target/kerberos/lib/kerberos_context.o -undefined dynamic_lookup -lkrb5 diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/obj.target/kerberos/lib/base64.o.d b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/obj.target/kerberos/lib/base64.o.d new file mode 100644 index 0000000..bb55424 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/obj.target/kerberos/lib/base64.o.d @@ -0,0 +1,4 @@ +cmd_Release/obj.target/kerberos/lib/base64.o := cc '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__MACOSX_CORE__' '-DBUILDING_NODE_EXTENSION' -I/Users/brandon/.node-gyp/0.10.21/src -I/Users/brandon/.node-gyp/0.10.21/deps/uv/include -I/Users/brandon/.node-gyp/0.10.21/deps/v8/include -Os -gdwarf-2 -mmacosx-version-min=10.5 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/kerberos/lib/base64.o.d.raw -c -o Release/obj.target/kerberos/lib/base64.o ../lib/base64.c +Release/obj.target/kerberos/lib/base64.o: ../lib/base64.c ../lib/base64.h +../lib/base64.c: +../lib/base64.h: diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/obj.target/kerberos/lib/kerberos.o.d b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/obj.target/kerberos/lib/kerberos.o.d new file mode 100644 index 0000000..10fb4e1 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/obj.target/kerberos/lib/kerberos.o.d @@ -0,0 +1,24 @@ +cmd_Release/obj.target/kerberos/lib/kerberos.o := c++ '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__MACOSX_CORE__' '-DBUILDING_NODE_EXTENSION' -I/Users/brandon/.node-gyp/0.10.21/src -I/Users/brandon/.node-gyp/0.10.21/deps/uv/include -I/Users/brandon/.node-gyp/0.10.21/deps/v8/include -Os -gdwarf-2 -mmacosx-version-min=10.5 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-rtti -fno-threadsafe-statics -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/kerberos/lib/kerberos.o.d.raw -c -o Release/obj.target/kerberos/lib/kerberos.o ../lib/kerberos.cc +Release/obj.target/kerberos/lib/kerberos.o: ../lib/kerberos.cc \ + ../lib/kerberos.h /Users/brandon/.node-gyp/0.10.21/src/node.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-unix.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/ngx-queue.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-darwin.h \ + /Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8.h \ + /Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8stdint.h \ + /Users/brandon/.node-gyp/0.10.21/src/node_object_wrap.h \ + ../lib/kerberosgss.h ../lib/worker.h ../lib/kerberos_context.h +../lib/kerberos.cc: +../lib/kerberos.h: +/Users/brandon/.node-gyp/0.10.21/src/node.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-unix.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/ngx-queue.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-darwin.h: +/Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8.h: +/Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8stdint.h: +/Users/brandon/.node-gyp/0.10.21/src/node_object_wrap.h: +../lib/kerberosgss.h: +../lib/worker.h: +../lib/kerberos_context.h: diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/obj.target/kerberos/lib/kerberos_context.o.d b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/obj.target/kerberos/lib/kerberos_context.o.d new file mode 100644 index 0000000..4a45ae7 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/obj.target/kerberos/lib/kerberos_context.o.d @@ -0,0 +1,23 @@ +cmd_Release/obj.target/kerberos/lib/kerberos_context.o := c++ '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__MACOSX_CORE__' '-DBUILDING_NODE_EXTENSION' -I/Users/brandon/.node-gyp/0.10.21/src -I/Users/brandon/.node-gyp/0.10.21/deps/uv/include -I/Users/brandon/.node-gyp/0.10.21/deps/v8/include -Os -gdwarf-2 -mmacosx-version-min=10.5 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-rtti -fno-threadsafe-statics -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/kerberos/lib/kerberos_context.o.d.raw -c -o Release/obj.target/kerberos/lib/kerberos_context.o ../lib/kerberos_context.cc +Release/obj.target/kerberos/lib/kerberos_context.o: \ + ../lib/kerberos_context.cc ../lib/kerberos_context.h \ + /Users/brandon/.node-gyp/0.10.21/src/node.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-unix.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/ngx-queue.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-darwin.h \ + /Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8.h \ + /Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8stdint.h \ + /Users/brandon/.node-gyp/0.10.21/src/node_object_wrap.h \ + ../lib/kerberosgss.h +../lib/kerberos_context.cc: +../lib/kerberos_context.h: +/Users/brandon/.node-gyp/0.10.21/src/node.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-unix.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/ngx-queue.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-darwin.h: +/Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8.h: +/Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8stdint.h: +/Users/brandon/.node-gyp/0.10.21/src/node_object_wrap.h: +../lib/kerberosgss.h: diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/obj.target/kerberos/lib/kerberosgss.o.d b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/obj.target/kerberos/lib/kerberosgss.o.d new file mode 100644 index 0000000..580b361 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/obj.target/kerberos/lib/kerberosgss.o.d @@ -0,0 +1,6 @@ +cmd_Release/obj.target/kerberos/lib/kerberosgss.o := cc '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__MACOSX_CORE__' '-DBUILDING_NODE_EXTENSION' -I/Users/brandon/.node-gyp/0.10.21/src -I/Users/brandon/.node-gyp/0.10.21/deps/uv/include -I/Users/brandon/.node-gyp/0.10.21/deps/v8/include -Os -gdwarf-2 -mmacosx-version-min=10.5 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/kerberos/lib/kerberosgss.o.d.raw -c -o Release/obj.target/kerberos/lib/kerberosgss.o ../lib/kerberosgss.c +Release/obj.target/kerberos/lib/kerberosgss.o: ../lib/kerberosgss.c \ + ../lib/kerberosgss.h ../lib/base64.h +../lib/kerberosgss.c: +../lib/kerberosgss.h: +../lib/base64.h: diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/obj.target/kerberos/lib/worker.o.d b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/obj.target/kerberos/lib/worker.o.d new file mode 100644 index 0000000..0e808ab --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/.deps/Release/obj.target/kerberos/lib/worker.o.d @@ -0,0 +1,20 @@ +cmd_Release/obj.target/kerberos/lib/worker.o := c++ '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D__MACOSX_CORE__' '-DBUILDING_NODE_EXTENSION' -I/Users/brandon/.node-gyp/0.10.21/src -I/Users/brandon/.node-gyp/0.10.21/deps/uv/include -I/Users/brandon/.node-gyp/0.10.21/deps/v8/include -Os -gdwarf-2 -mmacosx-version-min=10.5 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-rtti -fno-threadsafe-statics -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/kerberos/lib/worker.o.d.raw -c -o Release/obj.target/kerberos/lib/worker.o ../lib/worker.cc +Release/obj.target/kerberos/lib/worker.o: ../lib/worker.cc \ + ../lib/worker.h /Users/brandon/.node-gyp/0.10.21/src/node.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-unix.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/ngx-queue.h \ + /Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-darwin.h \ + /Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8.h \ + /Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8stdint.h \ + /Users/brandon/.node-gyp/0.10.21/src/node_object_wrap.h +../lib/worker.cc: +../lib/worker.h: +/Users/brandon/.node-gyp/0.10.21/src/node.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-unix.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/ngx-queue.h: +/Users/brandon/.node-gyp/0.10.21/deps/uv/include/uv-private/uv-darwin.h: +/Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8.h: +/Users/brandon/.node-gyp/0.10.21/deps/v8/include/v8stdint.h: +/Users/brandon/.node-gyp/0.10.21/src/node_object_wrap.h: diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/kerberos.node b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/kerberos.node new file mode 100755 index 0000000..c74882c Binary files /dev/null and b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/kerberos.node differ diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/linker.lock b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/linker.lock new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/obj.target/kerberos/lib/base64.o b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/obj.target/kerberos/lib/base64.o new file mode 100644 index 0000000..a37f9db Binary files /dev/null and b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/obj.target/kerberos/lib/base64.o differ diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/obj.target/kerberos/lib/kerberos.o b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/obj.target/kerberos/lib/kerberos.o new file mode 100644 index 0000000..25bb73f Binary files /dev/null and b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/obj.target/kerberos/lib/kerberos.o differ diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/obj.target/kerberos/lib/kerberos_context.o b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/obj.target/kerberos/lib/kerberos_context.o new file mode 100644 index 0000000..5342cf4 Binary files /dev/null and b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/obj.target/kerberos/lib/kerberos_context.o differ diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/obj.target/kerberos/lib/kerberosgss.o b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/obj.target/kerberos/lib/kerberosgss.o new file mode 100644 index 0000000..feaf4e0 Binary files /dev/null and b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/obj.target/kerberos/lib/kerberosgss.o differ diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/obj.target/kerberos/lib/worker.o b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/obj.target/kerberos/lib/worker.o new file mode 100644 index 0000000..0f8a0f7 Binary files /dev/null and b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/Release/obj.target/kerberos/lib/worker.o differ diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/binding.Makefile b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/binding.Makefile new file mode 100644 index 0000000..d0d9c64 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/binding.Makefile @@ -0,0 +1,6 @@ +# This file is generated by gyp; do not edit. + +export builddir_name ?= build/./. +.PHONY: all +all: + $(MAKE) kerberos diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/config.gypi b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/config.gypi new file mode 100644 index 0000000..b433275 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/config.gypi @@ -0,0 +1,112 @@ +# Do not edit. File was generated by node-gyp's "configure" step +{ + "target_defaults": { + "cflags": [], + "default_configuration": "Release", + "defines": [], + "include_dirs": [], + "libraries": [] + }, + "variables": { + "clang": 1, + "host_arch": "x64", + "node_install_npm": "true", + "node_prefix": "/usr/local/Cellar/node/0.10.21", + "node_shared_cares": "false", + "node_shared_http_parser": "false", + "node_shared_libuv": "false", + "node_shared_openssl": "false", + "node_shared_v8": "false", + "node_shared_zlib": "false", + "node_tag": "", + "node_unsafe_optimizations": 0, + "node_use_dtrace": "true", + "node_use_etw": "false", + "node_use_openssl": "true", + "node_use_perfctr": "false", + "python": "/usr/bin/python", + "target_arch": "x64", + "v8_enable_gdbjit": 0, + "v8_no_strict_aliasing": 1, + "v8_use_snapshot": "true", + "nodedir": "/Users/brandon/.node-gyp/0.10.21", + "copy_dev_lib": "true", + "standalone_static_library": 1, + "save_dev": "", + "browser": "", + "viewer": "man", + "rollback": "true", + "usage": "", + "globalignorefile": "/usr/local/etc/npmignore", + "init_author_url": "", + "shell": "/bin/zsh", + "parseable": "", + "shrinkwrap": "true", + "userignorefile": "/Users/brandon/.npmignore", + "cache_max": "null", + "init_author_email": "", + "sign_git_tag": "", + "ignore": "", + "long": "", + "registry": "https://registry.npmjs.org/", + "fetch_retries": "2", + "npat": "", + "message": "%s", + "versions": "", + "globalconfig": "/usr/local/etc/npmrc", + "always_auth": "", + "cache_lock_retries": "10", + "fetch_retry_mintimeout": "10000", + "proprietary_attribs": "true", + "coverage": "", + "json": "", + "pre": "", + "description": "true", + "engine_strict": "", + "https_proxy": "", + "init_module": "/Users/brandon/.npm-init.js", + "userconfig": "/Users/brandon/.npmrc", + "npaturl": "http://npat.npmjs.org/", + "node_version": "v0.10.21", + "user": "", + "editor": "vim", + "save": "", + "tag": "latest", + "global": "", + "optional": "true", + "username": "", + "bin_links": "true", + "force": "", + "searchopts": "", + "depth": "null", + "rebuild_bundle": "true", + "searchsort": "name", + "unicode": "true", + "yes": "", + "fetch_retry_maxtimeout": "60000", + "strict_ssl": "true", + "dev": "", + "fetch_retry_factor": "10", + "group": "20", + "cache_lock_stale": "60000", + "version": "", + "cache_min": "10", + "cache": "/Users/brandon/.npm", + "searchexclude": "", + "color": "true", + "save_optional": "", + "user_agent": "node/v0.10.21 darwin x64", + "cache_lock_wait": "10000", + "production": "", + "save_bundle": "", + "init_version": "0.0.0", + "umask": "18", + "git": "git", + "init_author_name": "", + "onload_script": "", + "tmp": "/var/folders/xf/40fvmk952nz5thhtbgln8vfc0000gn/T/", + "unsafe_perm": "true", + "prefix": "/usr/local", + "link": "" + } +} diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/gyp-mac-tool b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/gyp-mac-tool new file mode 100755 index 0000000..2f5e141 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/gyp-mac-tool @@ -0,0 +1,224 @@ +#!/usr/bin/env python +# Generated by gyp. Do not edit. +# Copyright (c) 2012 Google Inc. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Utility functions to perform Xcode-style build steps. + +These functions are executed via gyp-mac-tool when using the Makefile generator. +""" + +import fcntl +import os +import plistlib +import re +import shutil +import string +import subprocess +import sys + + +def main(args): + executor = MacTool() + exit_code = executor.Dispatch(args) + if exit_code is not None: + sys.exit(exit_code) + + +class MacTool(object): + """This class performs all the Mac tooling steps. The methods can either be + executed directly, or dispatched from an argument list.""" + + def Dispatch(self, args): + """Dispatches a string command to a method.""" + if len(args) < 1: + raise Exception("Not enough arguments") + + method = "Exec%s" % self._CommandifyName(args[0]) + return getattr(self, method)(*args[1:]) + + def _CommandifyName(self, name_string): + """Transforms a tool name like copy-info-plist to CopyInfoPlist""" + return name_string.title().replace('-', '') + + def ExecCopyBundleResource(self, source, dest): + """Copies a resource file to the bundle/Resources directory, performing any + necessary compilation on each resource.""" + extension = os.path.splitext(source)[1].lower() + if os.path.isdir(source): + # Copy tree. + if os.path.exists(dest): + shutil.rmtree(dest) + shutil.copytree(source, dest) + elif extension == '.xib': + return self._CopyXIBFile(source, dest) + elif extension == '.strings': + self._CopyStringsFile(source, dest) + else: + shutil.copyfile(source, dest) + + def _CopyXIBFile(self, source, dest): + """Compiles a XIB file with ibtool into a binary plist in the bundle.""" + tools_dir = os.environ.get('DEVELOPER_BIN_DIR', '/usr/bin') + args = [os.path.join(tools_dir, 'ibtool'), '--errors', '--warnings', + '--notices', '--output-format', 'human-readable-text', '--compile', + dest, source] + ibtool_section_re = re.compile(r'/\*.*\*/') + ibtool_re = re.compile(r'.*note:.*is clipping its content') + ibtoolout = subprocess.Popen(args, stdout=subprocess.PIPE) + current_section_header = None + for line in ibtoolout.stdout: + if ibtool_section_re.match(line): + current_section_header = line + elif not ibtool_re.match(line): + if current_section_header: + sys.stdout.write(current_section_header) + current_section_header = None + sys.stdout.write(line) + return ibtoolout.returncode + + def _CopyStringsFile(self, source, dest): + """Copies a .strings file using iconv to reconvert the input into UTF-16.""" + input_code = self._DetectInputEncoding(source) or "UTF-8" + + # Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call + # CFPropertyListCreateFromXMLData() behind the scenes; at least it prints + # CFPropertyListCreateFromXMLData(): Old-style plist parser: missing + # semicolon in dictionary. + # on invalid files. Do the same kind of validation. + import CoreFoundation + s = open(source).read() + d = CoreFoundation.CFDataCreate(None, s, len(s)) + _, error = CoreFoundation.CFPropertyListCreateFromXMLData(None, d, 0, None) + if error: + return + + fp = open(dest, 'w') + args = ['/usr/bin/iconv', '--from-code', input_code, '--to-code', + 'UTF-16', source] + subprocess.call(args, stdout=fp) + fp.close() + + def _DetectInputEncoding(self, file_name): + """Reads the first few bytes from file_name and tries to guess the text + encoding. Returns None as a guess if it can't detect it.""" + fp = open(file_name, 'rb') + try: + header = fp.read(3) + except e: + fp.close() + return None + fp.close() + if header.startswith("\xFE\xFF"): + return "UTF-16BE" + elif header.startswith("\xFF\xFE"): + return "UTF-16LE" + elif header.startswith("\xEF\xBB\xBF"): + return "UTF-8" + else: + return None + + def ExecCopyInfoPlist(self, source, dest): + """Copies the |source| Info.plist to the destination directory |dest|.""" + # Read the source Info.plist into memory. + fd = open(source, 'r') + lines = fd.read() + fd.close() + + # Go through all the environment variables and replace them as variables in + # the file. + for key in os.environ: + if key.startswith('_'): + continue + evar = '${%s}' % key + lines = string.replace(lines, evar, os.environ[key]) + + # Write out the file with variables replaced. + fd = open(dest, 'w') + fd.write(lines) + fd.close() + + # Now write out PkgInfo file now that the Info.plist file has been + # "compiled". + self._WritePkgInfo(dest) + + def _WritePkgInfo(self, info_plist): + """This writes the PkgInfo file from the data stored in Info.plist.""" + plist = plistlib.readPlist(info_plist) + if not plist: + return + + # Only create PkgInfo for executable types. + package_type = plist['CFBundlePackageType'] + if package_type != 'APPL': + return + + # The format of PkgInfo is eight characters, representing the bundle type + # and bundle signature, each four characters. If that is missing, four + # '?' characters are used instead. + signature_code = plist.get('CFBundleSignature', '????') + if len(signature_code) != 4: # Wrong length resets everything, too. + signature_code = '?' * 4 + + dest = os.path.join(os.path.dirname(info_plist), 'PkgInfo') + fp = open(dest, 'w') + fp.write('%s%s' % (package_type, signature_code)) + fp.close() + + def ExecFlock(self, lockfile, *cmd_list): + """Emulates the most basic behavior of Linux's flock(1).""" + # Rely on exception handling to report errors. + fd = os.open(lockfile, os.O_RDONLY|os.O_NOCTTY|os.O_CREAT, 0o666) + fcntl.flock(fd, fcntl.LOCK_EX) + return subprocess.call(cmd_list) + + def ExecFilterLibtool(self, *cmd_list): + """Calls libtool and filters out 'libtool: file: foo.o has no symbols'.""" + libtool_re = re.compile(r'^libtool: file: .* has no symbols$') + libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE) + _, err = libtoolout.communicate() + for line in err.splitlines(): + if not libtool_re.match(line): + print >>sys.stderr, line + return libtoolout.returncode + + def ExecPackageFramework(self, framework, version): + """Takes a path to Something.framework and the Current version of that and + sets up all the symlinks.""" + # Find the name of the binary based on the part before the ".framework". + binary = os.path.basename(framework).split('.')[0] + + CURRENT = 'Current' + RESOURCES = 'Resources' + VERSIONS = 'Versions' + + if not os.path.exists(os.path.join(framework, VERSIONS, version, binary)): + # Binary-less frameworks don't seem to contain symlinks (see e.g. + # chromium's out/Debug/org.chromium.Chromium.manifest/ bundle). + return + + # Move into the framework directory to set the symlinks correctly. + pwd = os.getcwd() + os.chdir(framework) + + # Set up the Current version. + self._Relink(version, os.path.join(VERSIONS, CURRENT)) + + # Set up the root symlinks. + self._Relink(os.path.join(VERSIONS, CURRENT, binary), binary) + self._Relink(os.path.join(VERSIONS, CURRENT, RESOURCES), RESOURCES) + + # Back to where we were before! + os.chdir(pwd) + + def _Relink(self, dest, link): + """Creates a symlink to |dest| named |link|. If |link| already exists, + it is overwritten.""" + if os.path.lexists(link): + os.remove(link) + os.symlink(dest, link) + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/kerberos.target.mk b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/kerberos.target.mk new file mode 100644 index 0000000..8dd63cb --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/build/kerberos.target.mk @@ -0,0 +1,170 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := kerberos +DEFS_Debug := \ + '-D_DARWIN_USE_64_BIT_INODE=1' \ + '-D_LARGEFILE_SOURCE' \ + '-D_FILE_OFFSET_BITS=64' \ + '-D__MACOSX_CORE__' \ + '-DBUILDING_NODE_EXTENSION' \ + '-DDEBUG' \ + '-D_DEBUG' + +# Flags passed to all source files. +CFLAGS_Debug := \ + -O0 \ + -gdwarf-2 \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -Wall \ + -Wendif-labels \ + -W \ + -Wno-unused-parameter + +# Flags passed to only C files. +CFLAGS_C_Debug := \ + -fno-strict-aliasing + +# Flags passed to only C++ files. +CFLAGS_CC_Debug := \ + -fno-rtti \ + -fno-threadsafe-statics \ + -fno-strict-aliasing + +# Flags passed to only ObjC files. +CFLAGS_OBJC_Debug := + +# Flags passed to only ObjC++ files. +CFLAGS_OBJCC_Debug := + +INCS_Debug := \ + -I/Users/brandon/.node-gyp/0.10.21/src \ + -I/Users/brandon/.node-gyp/0.10.21/deps/uv/include \ + -I/Users/brandon/.node-gyp/0.10.21/deps/v8/include + +DEFS_Release := \ + '-D_DARWIN_USE_64_BIT_INODE=1' \ + '-D_LARGEFILE_SOURCE' \ + '-D_FILE_OFFSET_BITS=64' \ + '-D__MACOSX_CORE__' \ + '-DBUILDING_NODE_EXTENSION' + +# Flags passed to all source files. +CFLAGS_Release := \ + -Os \ + -gdwarf-2 \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -Wall \ + -Wendif-labels \ + -W \ + -Wno-unused-parameter + +# Flags passed to only C files. +CFLAGS_C_Release := \ + -fno-strict-aliasing + +# Flags passed to only C++ files. +CFLAGS_CC_Release := \ + -fno-rtti \ + -fno-threadsafe-statics \ + -fno-strict-aliasing + +# Flags passed to only ObjC files. +CFLAGS_OBJC_Release := + +# Flags passed to only ObjC++ files. +CFLAGS_OBJCC_Release := + +INCS_Release := \ + -I/Users/brandon/.node-gyp/0.10.21/src \ + -I/Users/brandon/.node-gyp/0.10.21/deps/uv/include \ + -I/Users/brandon/.node-gyp/0.10.21/deps/v8/include + +OBJS := \ + $(obj).target/$(TARGET)/lib/kerberos.o \ + $(obj).target/$(TARGET)/lib/worker.o \ + $(obj).target/$(TARGET)/lib/kerberosgss.o \ + $(obj).target/$(TARGET)/lib/base64.o \ + $(obj).target/$(TARGET)/lib/kerberos_context.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) +$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE)) +$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_Debug := \ + -Wl,-search_paths_first \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -L$(builddir) \ + -install_name @rpath/kerberos.node + +LIBTOOLFLAGS_Debug := \ + -Wl,-search_paths_first + +LDFLAGS_Release := \ + -Wl,-search_paths_first \ + -mmacosx-version-min=10.5 \ + -arch x86_64 \ + -L$(builddir) \ + -install_name @rpath/kerberos.node + +LIBTOOLFLAGS_Release := \ + -Wl,-search_paths_first + +LIBS := \ + -undefined dynamic_lookup \ + -lkrb5 + +$(builddir)/kerberos.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(builddir)/kerberos.node: LIBS := $(LIBS) +$(builddir)/kerberos.node: GYP_LIBTOOLFLAGS := $(LIBTOOLFLAGS_$(BUILDTYPE)) +$(builddir)/kerberos.node: TOOLSET := $(TOOLSET) +$(builddir)/kerberos.node: $(OBJS) FORCE_DO_CMD + $(call do_cmd,solink_module) + +all_deps += $(builddir)/kerberos.node +# Add target alias +.PHONY: kerberos +kerberos: $(builddir)/kerberos.node + +# Short alias for building this executable. +.PHONY: kerberos.node +kerberos.node: $(builddir)/kerberos.node + +# Add executable to "all" target. +.PHONY: all +all: $(builddir)/kerberos.node + diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/builderror.log b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/builderror.log new file mode 100644 index 0000000..0ff4d05 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/builderror.log @@ -0,0 +1,201 @@ +gyp http GET http://nodejs.org/dist/v0.10.21/node-v0.10.21.tar.gz +gyp http 200 http://nodejs.org/dist/v0.10.21/node-v0.10.21.tar.gz +../lib/kerberosgss.c:125:14: warning: 'gss_import_name' is deprecated: use GSS.framework [-Wdeprecated-declarations] + maj_stat = gss_import_name(&min_stat, &name_token, gss_krb5_nt_service_name, &state->server_name); + ^ +/usr/include/gssapi/gssapi.h:586:1: note: 'gss_import_name' declared here +gss_import_name( +^ +../lib/kerberosgss.c:148:5: warning: 'gss_delete_sec_context' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_delete_sec_context(&min_stat, &state->context, GSS_C_NO_BUFFER); + ^ +/usr/include/gssapi/gssapi.h:498:1: note: 'gss_delete_sec_context' declared here +gss_delete_sec_context( +^ +../lib/kerberosgss.c:151:5: warning: 'gss_release_name' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_name(&min_stat, &state->server_name); + ^ +/usr/include/gssapi/gssapi.h:593:1: note: 'gss_release_name' declared here +gss_release_name( +^ +../lib/kerberosgss.c:193:14: warning: 'gss_init_sec_context' is deprecated: use GSS.framework [-Wdeprecated-declarations] + maj_stat = gss_init_sec_context(&min_stat, + ^ +/usr/include/gssapi/gssapi.h:461:1: note: 'gss_init_sec_context' declared here +gss_init_sec_context( +^ +../lib/kerberosgss.c:217:16: warning: 'gss_release_buffer' is deprecated: use GSS.framework [-Wdeprecated-declarations] + maj_stat = gss_release_buffer(&min_stat, &output_token); + ^ +/usr/include/gssapi/gssapi.h:598:1: note: 'gss_release_buffer' declared here +gss_release_buffer( +^ +../lib/kerberosgss.c:223:16: warning: 'gss_inquire_context' is deprecated: use GSS.framework [-Wdeprecated-declarations] + maj_stat = gss_inquire_context(&min_stat, state->context, &gssuser, NULL, NULL, NULL, NULL, NULL, NULL); + ^ +/usr/include/gssapi/gssapi.h:618:1: note: 'gss_inquire_context' declared here +gss_inquire_context( +^ +../lib/kerberosgss.c:233:16: warning: 'gss_display_name' is deprecated: use GSS.framework [-Wdeprecated-declarations] + maj_stat = gss_display_name(&min_stat, gssuser, &name_token, NULL); + ^ +/usr/include/gssapi/gssapi.h:578:1: note: 'gss_display_name' declared here +gss_display_name( +^ +../lib/kerberosgss.c:237:9: warning: 'gss_release_buffer' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_buffer(&min_stat, &name_token); + ^ +/usr/include/gssapi/gssapi.h:598:1: note: 'gss_release_buffer' declared here +gss_release_buffer( +^ +../lib/kerberosgss.c:238:7: warning: 'gss_release_name' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_name(&min_stat, &gssuser); + ^ +/usr/include/gssapi/gssapi.h:593:1: note: 'gss_release_name' declared here +gss_release_name( +^ +../lib/kerberosgss.c:247:7: warning: 'gss_release_buffer' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_buffer(&min_stat, &name_token); + ^ +/usr/include/gssapi/gssapi.h:598:1: note: 'gss_release_buffer' declared here +gss_release_buffer( +^ +../lib/kerberosgss.c:248:7: warning: 'gss_release_name' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_name(&min_stat, &gssuser); + ^ +/usr/include/gssapi/gssapi.h:593:1: note: 'gss_release_name' declared here +gss_release_name( +^ +../lib/kerberosgss.c:254:5: warning: 'gss_release_buffer' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_buffer(&min_stat, &output_token); + ^ +/usr/include/gssapi/gssapi.h:598:1: note: 'gss_release_buffer' declared here +gss_release_buffer( +^ +../lib/kerberosgss.c:289:14: warning: 'gss_unwrap' is deprecated: use GSS.framework [-Wdeprecated-declarations] + maj_stat = gss_unwrap(&min_stat, + ^ +/usr/include/gssapi/gssapi.h:544:1: note: 'gss_unwrap' declared here +gss_unwrap( +^ +../lib/kerberosgss.c:307:16: warning: 'gss_release_buffer' is deprecated: use GSS.framework [-Wdeprecated-declarations] + maj_stat = gss_release_buffer(&min_stat, &output_token); + ^ +/usr/include/gssapi/gssapi.h:598:1: note: 'gss_release_buffer' declared here +gss_release_buffer( +^ +../lib/kerberosgss.c:311:5: warning: 'gss_release_buffer' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_buffer(&min_stat, &output_token); + ^ +/usr/include/gssapi/gssapi.h:598:1: note: 'gss_release_buffer' declared here +gss_release_buffer( +^ +../lib/kerberosgss.c:371:14: warning: 'gss_wrap' is deprecated: use GSS.framework [-Wdeprecated-declarations] + maj_stat = gss_wrap(&min_stat, + ^ +/usr/include/gssapi/gssapi.h:532:1: note: 'gss_wrap' declared here +gss_wrap( +^ +../lib/kerberosgss.c:388:16: warning: 'gss_release_buffer' is deprecated: use GSS.framework [-Wdeprecated-declarations] + maj_stat = gss_release_buffer(&min_stat, &output_token); + ^ +/usr/include/gssapi/gssapi.h:598:1: note: 'gss_release_buffer' declared here +gss_release_buffer( +^ +../lib/kerberosgss.c:392:5: warning: 'gss_release_buffer' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_buffer(&min_stat, &output_token); + ^ +/usr/include/gssapi/gssapi.h:598:1: note: 'gss_release_buffer' declared here +gss_release_buffer( +^ +../lib/kerberosgss.c:427:20: warning: 'gss_import_name' is deprecated: use GSS.framework [-Wdeprecated-declarations] + maj_stat = gss_import_name(&min_stat, &name_token, GSS_C_NT_HOSTBASED_SERVICE, &state->server_name); + ^ +/usr/include/gssapi/gssapi.h:586:1: note: 'gss_import_name' declared here +gss_import_name( +^ +../lib/kerberosgss.c:437:20: warning: 'gss_acquire_cred' is deprecated: use GSS.framework [-Wdeprecated-declarations] + maj_stat = gss_acquire_cred(&min_stat, state->server_name, GSS_C_INDEFINITE, + ^ +/usr/include/gssapi/gssapi.h:445:1: note: 'gss_acquire_cred' declared here +gss_acquire_cred( +^ +../lib/kerberosgss.c:458:9: warning: 'gss_delete_sec_context' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_delete_sec_context(&min_stat, &state->context, GSS_C_NO_BUFFER); + ^ +/usr/include/gssapi/gssapi.h:498:1: note: 'gss_delete_sec_context' declared here +gss_delete_sec_context( +^ +../lib/kerberosgss.c:460:9: warning: 'gss_release_name' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_name(&min_stat, &state->server_name); + ^ +/usr/include/gssapi/gssapi.h:593:1: note: 'gss_release_name' declared here +gss_release_name( +^ +../lib/kerberosgss.c:462:9: warning: 'gss_release_name' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_name(&min_stat, &state->client_name); + ^ +/usr/include/gssapi/gssapi.h:593:1: note: 'gss_release_name' declared here +gss_release_name( +^ +../lib/kerberosgss.c:464:9: warning: 'gss_release_cred' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_cred(&min_stat, &state->server_creds); + ^ +/usr/include/gssapi/gssapi.h:456:1: note: 'gss_release_cred' declared here +gss_release_cred( +^ +../lib/kerberosgss.c:466:9: warning: 'gss_release_cred' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_cred(&min_stat, &state->client_creds); + ^ +/usr/include/gssapi/gssapi.h:456:1: note: 'gss_release_cred' declared here +gss_release_cred( +^ +../lib/kerberosgss.c:595:16: warning: 'gss_display_status' is deprecated: use GSS.framework [-Wdeprecated-declarations] + maj_stat = gss_display_status (&min_stat, + ^ +/usr/include/gssapi/gssapi.h:554:1: note: 'gss_display_status' declared here +gss_display_status( +^ +../lib/kerberosgss.c:605:5: warning: 'gss_release_buffer' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_buffer(&min_stat, &status_string); + ^ +/usr/include/gssapi/gssapi.h:598:1: note: 'gss_release_buffer' declared here +gss_release_buffer( +^ +../lib/kerberosgss.c:607:16: warning: 'gss_display_status' is deprecated: use GSS.framework [-Wdeprecated-declarations] + maj_stat = gss_display_status (&min_stat, + ^ +/usr/include/gssapi/gssapi.h:554:1: note: 'gss_display_status' declared here +gss_display_status( +^ +../lib/kerberosgss.c:616:7: warning: 'gss_release_buffer' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_buffer(&min_stat, &status_string); + ^ +/usr/include/gssapi/gssapi.h:598:1: note: 'gss_release_buffer' declared here +gss_release_buffer( +^ +../lib/kerberosgss.c:631:16: warning: 'gss_display_status' is deprecated: use GSS.framework [-Wdeprecated-declarations] + maj_stat = gss_display_status (&min_stat, + ^ +/usr/include/gssapi/gssapi.h:554:1: note: 'gss_display_status' declared here +gss_display_status( +^ +../lib/kerberosgss.c:641:5: warning: 'gss_release_buffer' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_buffer(&min_stat, &status_string); + ^ +/usr/include/gssapi/gssapi.h:598:1: note: 'gss_release_buffer' declared here +gss_release_buffer( +^ +../lib/kerberosgss.c:643:16: warning: 'gss_display_status' is deprecated: use GSS.framework [-Wdeprecated-declarations] + maj_stat = gss_display_status (&min_stat, + ^ +/usr/include/gssapi/gssapi.h:554:1: note: 'gss_display_status' declared here +gss_display_status( +^ +../lib/kerberosgss.c:651:7: warning: 'gss_release_buffer' is deprecated: use GSS.framework [-Wdeprecated-declarations] + gss_release_buffer(&min_stat, &status_string); + ^ +/usr/include/gssapi/gssapi.h:598:1: note: 'gss_release_buffer' declared here +gss_release_buffer( +^ +33 warnings generated. diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/index.js b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/index.js new file mode 100644 index 0000000..b8c8532 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/index.js @@ -0,0 +1,6 @@ +// Get the Kerberos library +module.exports = require('./lib/kerberos'); +// Set up the auth processes +module.exports['processes'] = { + MongoAuthProcess: require('./lib/auth_processes/mongodb').MongoAuthProcess +} \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/auth_processes/mongodb.js b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/auth_processes/mongodb.js new file mode 100644 index 0000000..f1e9231 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/auth_processes/mongodb.js @@ -0,0 +1,281 @@ +var format = require('util').format; + +var MongoAuthProcess = function(host, port, service_name) { + // Check what system we are on + if(process.platform == 'win32') { + this._processor = new Win32MongoProcessor(host, port, service_name); + } else { + this._processor = new UnixMongoProcessor(host, port, service_name); + } +} + +MongoAuthProcess.prototype.init = function(username, password, callback) { + this._processor.init(username, password, callback); +} + +MongoAuthProcess.prototype.transition = function(payload, callback) { + this._processor.transition(payload, callback); +} + +/******************************************************************* + * + * Win32 SSIP Processor for MongoDB + * + *******************************************************************/ +var Win32MongoProcessor = function(host, port, service_name) { + this.host = host; + this.port = port + // SSIP classes + this.ssip = require("../kerberos").SSIP; + // Set up first transition + this._transition = Win32MongoProcessor.first_transition(this); + // Set up service name + service_name = service_name || "mongodb"; + // Set up target + this.target = format("%s/%s", service_name, host); + // Number of retries + this.retries = 10; +} + +Win32MongoProcessor.prototype.init = function(username, password, callback) { + var self = this; + // Save the values used later + this.username = username; + this.password = password; + // Aquire credentials + this.ssip.SecurityCredentials.aquire_kerberos(username, password, function(err, security_credentials) { + if(err) return callback(err); + // Save credentials + self.security_credentials = security_credentials; + // Callback with success + callback(null); + }); +} + +Win32MongoProcessor.prototype.transition = function(payload, callback) { + if(this._transition == null) return callback(new Error("Transition finished")); + this._transition(payload, callback); +} + +Win32MongoProcessor.first_transition = function(self) { + return function(payload, callback) { + self.ssip.SecurityContext.initialize( + self.security_credentials, + self.target, + payload, function(err, security_context) { + if(err) return callback(err); + + // If no context try again until we have no more retries + if(!security_context.hasContext) { + if(self.retries == 0) return callback(new Error("Failed to initialize security context")); + // Update the number of retries + self.retries = self.retries - 1; + // Set next transition + return self.transition(payload, callback); + } + + // Set next transition + self._transition = Win32MongoProcessor.second_transition(self); + self.security_context = security_context; + // Return the payload + callback(null, security_context.payload); + }); + } +} + +Win32MongoProcessor.second_transition = function(self) { + return function(payload, callback) { + // Perform a step + self.security_context.initialize(self.target, payload, function(err, security_context) { + if(err) return callback(err); + + // If no context try again until we have no more retries + if(!security_context.hasContext) { + if(self.retries == 0) return callback(new Error("Failed to initialize security context")); + // Update the number of retries + self.retries = self.retries - 1; + // Set next transition + self._transition = Win32MongoProcessor.first_transition(self); + // Retry + return self.transition(payload, callback); + } + + // Set next transition + self._transition = Win32MongoProcessor.third_transition(self); + // Return the payload + callback(null, security_context.payload); + }); + } +} + +Win32MongoProcessor.third_transition = function(self) { + return function(payload, callback) { + var messageLength = 0; + // Get the raw bytes + var encryptedBytes = new Buffer(payload, 'base64'); + var encryptedMessage = new Buffer(messageLength); + // Copy first byte + encryptedBytes.copy(encryptedMessage, 0, 0, messageLength); + // Set up trailer + var securityTrailerLength = encryptedBytes.length - messageLength; + var securityTrailer = new Buffer(securityTrailerLength); + // Copy the bytes + encryptedBytes.copy(securityTrailer, 0, messageLength, securityTrailerLength); + + // Types used + var SecurityBuffer = self.ssip.SecurityBuffer; + var SecurityBufferDescriptor = self.ssip.SecurityBufferDescriptor; + + // Set up security buffers + var buffers = [ + new SecurityBuffer(SecurityBuffer.DATA, encryptedBytes) + , new SecurityBuffer(SecurityBuffer.STREAM, securityTrailer) + ]; + + // Set up the descriptor + var descriptor = new SecurityBufferDescriptor(buffers); + + // Decrypt the data + self.security_context.decryptMessage(descriptor, function(err, security_context) { + if(err) return callback(err); + + var length = 4; + if(self.username != null) { + length += self.username.length; + } + + var bytesReceivedFromServer = new Buffer(length); + bytesReceivedFromServer[0] = 0x01; // NO_PROTECTION + bytesReceivedFromServer[1] = 0x00; // NO_PROTECTION + bytesReceivedFromServer[2] = 0x00; // NO_PROTECTION + bytesReceivedFromServer[3] = 0x00; // NO_PROTECTION + + if(self.username != null) { + var authorization_id_bytes = new Buffer(self.username, 'utf8'); + authorization_id_bytes.copy(bytesReceivedFromServer, 4, 0); + } + + self.security_context.queryContextAttributes(0x00, function(err, sizes) { + if(err) return callback(err); + + var buffers = [ + new SecurityBuffer(SecurityBuffer.TOKEN, new Buffer(sizes.securityTrailer)) + , new SecurityBuffer(SecurityBuffer.DATA, bytesReceivedFromServer) + , new SecurityBuffer(SecurityBuffer.PADDING, new Buffer(sizes.blockSize)) + ] + + var descriptor = new SecurityBufferDescriptor(buffers); + + self.security_context.encryptMessage(descriptor, 0x80000001, function(err, security_context) { + if(err) return callback(err); + callback(null, security_context.payload); + }); + }); + }); + } +} + +/******************************************************************* + * + * UNIX MIT Kerberos processor + * + *******************************************************************/ +var UnixMongoProcessor = function(host, port, service_name) { + this.host = host; + this.port = port + // SSIP classes + this.Kerberos = require("../kerberos").Kerberos; + this.kerberos = new this.Kerberos(); + service_name = service_name || "mongodb"; + // Set up first transition + this._transition = UnixMongoProcessor.first_transition(this); + // Set up target + this.target = format("%s@%s", service_name, host); + // Number of retries + this.retries = 10; +} + +UnixMongoProcessor.prototype.init = function(username, password, callback) { + var self = this; + this.username = username; + this.password = password; + // Call client initiate + this.kerberos.authGSSClientInit( + self.target + , this.Kerberos.GSS_C_MUTUAL_FLAG, function(err, context) { + self.context = context; + // Return the context + callback(null, context); + }); +} + +UnixMongoProcessor.prototype.transition = function(payload, callback) { + if(this._transition == null) return callback(new Error("Transition finished")); + this._transition(payload, callback); +} + +UnixMongoProcessor.first_transition = function(self) { + return function(payload, callback) { + self.kerberos.authGSSClientStep(self.context, '', function(err, result) { + if(err) return callback(err); + // Set up the next step + self._transition = UnixMongoProcessor.second_transition(self); + // Return the payload + callback(null, self.context.response); + }) + } +} + +UnixMongoProcessor.second_transition = function(self) { + return function(payload, callback) { + self.kerberos.authGSSClientStep(self.context, payload, function(err, result) { + if(err && self.retries == 0) return callback(err); + // Attempt to re-establish a context + if(err) { + // Adjust the number of retries + self.retries = self.retries - 1; + // Call same step again + return self.transition(payload, callback); + } + + // Set up the next step + self._transition = UnixMongoProcessor.third_transition(self); + // Return the payload + callback(null, self.context.response || ''); + }); + } +} + +UnixMongoProcessor.third_transition = function(self) { + return function(payload, callback) { + // GSS Client Unwrap + self.kerberos.authGSSClientUnwrap(self.context, payload, function(err, result) { + if(err) return callback(err, false); + + // Wrap the response + self.kerberos.authGSSClientWrap(self.context, self.context.response, self.username, function(err, result) { + if(err) return callback(err, false); + // Set up the next step + self._transition = UnixMongoProcessor.fourth_transition(self); + // Return the payload + callback(null, self.context.response); + }); + }); + } +} + +UnixMongoProcessor.fourth_transition = function(self) { + return function(payload, callback) { + // Clean up context + self.kerberos.authGSSClientClean(self.context, function(err, result) { + if(err) return callback(err, false); + // Set the transition to null + self._transition = null; + // Callback with valid authentication + callback(null, true); + }); + } +} + +// Set the process +exports.MongoAuthProcess = MongoAuthProcess; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/base64.c b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/base64.c new file mode 100644 index 0000000..4232106 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/base64.c @@ -0,0 +1,120 @@ +/** + * Copyright (c) 2006-2008 Apple Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +#include "base64.h" + +#include +#include + +// base64 tables +static char basis_64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static signed char index_64[128] = +{ + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 +}; +#define CHAR64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)]) + +// base64_encode : base64 encode +// +// value : data to encode +// vlen : length of data +// (result) : new char[] - c-str of result +char *base64_encode(const unsigned char *value, int vlen) +{ + char *result = (char *)malloc((vlen * 4) / 3 + 5); + char *out = result; + while (vlen >= 3) + { + *out++ = basis_64[value[0] >> 2]; + *out++ = basis_64[((value[0] << 4) & 0x30) | (value[1] >> 4)]; + *out++ = basis_64[((value[1] << 2) & 0x3C) | (value[2] >> 6)]; + *out++ = basis_64[value[2] & 0x3F]; + value += 3; + vlen -= 3; + } + if (vlen > 0) + { + *out++ = basis_64[value[0] >> 2]; + unsigned char oval = (value[0] << 4) & 0x30; + if (vlen > 1) oval |= value[1] >> 4; + *out++ = basis_64[oval]; + *out++ = (vlen < 2) ? '=' : basis_64[(value[1] << 2) & 0x3C]; + *out++ = '='; + } + *out = '\0'; + + return result; +} + +// base64_decode : base64 decode +// +// value : c-str to decode +// rlen : length of decoded result +// (result) : new unsigned char[] - decoded result +unsigned char *base64_decode(const char *value, int *rlen) +{ + *rlen = 0; + int c1, c2, c3, c4; + + int vlen = strlen(value); + unsigned char *result =(unsigned char *)malloc((vlen * 3) / 4 + 1); + unsigned char *out = result; + + while (1) + { + if (value[0]==0) + return result; + c1 = value[0]; + if (CHAR64(c1) == -1) + goto base64_decode_error;; + c2 = value[1]; + if (CHAR64(c2) == -1) + goto base64_decode_error;; + c3 = value[2]; + if ((c3 != '=') && (CHAR64(c3) == -1)) + goto base64_decode_error;; + c4 = value[3]; + if ((c4 != '=') && (CHAR64(c4) == -1)) + goto base64_decode_error;; + + value += 4; + *out++ = (CHAR64(c1) << 2) | (CHAR64(c2) >> 4); + *rlen += 1; + if (c3 != '=') + { + *out++ = ((CHAR64(c2) << 4) & 0xf0) | (CHAR64(c3) >> 2); + *rlen += 1; + if (c4 != '=') + { + *out++ = ((CHAR64(c3) << 6) & 0xc0) | CHAR64(c4); + *rlen += 1; + } + } + } + +base64_decode_error: + *result = 0; + *rlen = 0; + return result; +} diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/base64.h b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/base64.h new file mode 100644 index 0000000..f0e1f06 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/base64.h @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2006-2008 Apple Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +char *base64_encode(const unsigned char *value, int vlen); +unsigned char *base64_decode(const char *value, int *rlen); diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberos.cc b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberos.cc new file mode 100644 index 0000000..08eda82 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberos.cc @@ -0,0 +1,563 @@ +#include "kerberos.h" +#include +#include "worker.h" +#include "kerberos_context.h" + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0])) +#endif + +Persistent Kerberos::constructor_template; + +// Call structs +typedef struct AuthGSSClientCall { + uint32_t flags; + char *uri; +} AuthGSSClientCall; + +typedef struct AuthGSSClientStepCall { + KerberosContext *context; + char *challenge; +} AuthGSSClientStepCall; + +typedef struct AuthGSSClientUnwrapCall { + KerberosContext *context; + char *challenge; +} AuthGSSClientUnwrapCall; + +typedef struct AuthGSSClientWrapCall { + KerberosContext *context; + char *challenge; + char *user_name; +} AuthGSSClientWrapCall; + +typedef struct AuthGSSClientCleanCall { + KerberosContext *context; +} AuthGSSClientCleanCall; + +// VException object (causes throw in calling code) +static Handle VException(const char *msg) { + HandleScope scope; + return ThrowException(Exception::Error(String::New(msg))); +} + +Kerberos::Kerberos() : ObjectWrap() { +} + +void Kerberos::Initialize(v8::Handle target) { + // Grab the scope of the call from Node + HandleScope scope; + // Define a new function template + Local t = FunctionTemplate::New(Kerberos::New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("Kerberos")); + + // Set up method for the Kerberos instance + NODE_SET_PROTOTYPE_METHOD(constructor_template, "authGSSClientInit", AuthGSSClientInit); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "authGSSClientStep", AuthGSSClientStep); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "authGSSClientUnwrap", AuthGSSClientUnwrap); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "authGSSClientWrap", AuthGSSClientWrap); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "authGSSClientClean", AuthGSSClientClean); + + // Set the symbol + target->ForceSet(String::NewSymbol("Kerberos"), constructor_template->GetFunction()); +} + +Handle Kerberos::New(const Arguments &args) { + // Create a Kerberos instance + Kerberos *kerberos = new Kerberos(); + // Return the kerberos object + kerberos->Wrap(args.This()); + return args.This(); +} + +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// authGSSClientInit +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +static void _authGSSClientInit(Worker *worker) { + gss_client_state *state; + gss_client_response *response; + + // Allocate state + state = (gss_client_state *)malloc(sizeof(gss_client_state)); + + // Unpack the parameter data struct + AuthGSSClientCall *call = (AuthGSSClientCall *)worker->parameters; + // Start the kerberos client + response = authenticate_gss_client_init(call->uri, call->flags, state); + + // Release the parameter struct memory + free(call->uri); + free(call); + + // If we have an error mark worker as having had an error + if(response->return_code == AUTH_GSS_ERROR) { + worker->error = TRUE; + worker->error_code = response->return_code; + worker->error_message = response->message; + } else { + worker->return_value = state; + } + + // Free structure + free(response); +} + +static Handle _map_authGSSClientInit(Worker *worker) { + HandleScope scope; + + KerberosContext *context = KerberosContext::New(); + context->state = (gss_client_state *)worker->return_value; + // Persistent _context = Persistent::New(context->handle_); + return scope.Close(context->handle_); +} + +// Initialize method +Handle Kerberos::AuthGSSClientInit(const Arguments &args) { + HandleScope scope; + + // Ensure valid call + if(args.Length() != 3) return VException("Requires a service string uri, integer flags and a callback function"); + if(args.Length() == 3 && !args[0]->IsString() && !args[1]->IsInt32() && !args[2]->IsFunction()) + return VException("Requires a service string uri, integer flags and a callback function"); + + Local service = args[0]->ToString(); + // Convert uri string to c-string + char *service_str = (char *)calloc(service->Utf8Length() + 1, sizeof(char)); + // Write v8 string to c-string + service->WriteUtf8(service_str); + + // Allocate a structure + AuthGSSClientCall *call = (AuthGSSClientCall *)calloc(1, sizeof(AuthGSSClientCall)); + call->flags =args[1]->ToInt32()->Uint32Value(); + call->uri = service_str; + + // Unpack the callback + Local callback = Local::Cast(args[2]); + + // Let's allocate some space + Worker *worker = new Worker(); + worker->error = false; + worker->request.data = worker; + worker->callback = Persistent::New(callback); + worker->parameters = call; + worker->execute = _authGSSClientInit; + worker->mapper = _map_authGSSClientInit; + + // Schedule the worker with lib_uv + uv_queue_work(uv_default_loop(), &worker->request, Kerberos::Process, (uv_after_work_cb)Kerberos::After); + // Return no value as it's callback based + return scope.Close(Undefined()); +} + +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// authGSSClientStep +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +static void _authGSSClientStep(Worker *worker) { + gss_client_state *state; + gss_client_response *response; + char *challenge; + + // Unpack the parameter data struct + AuthGSSClientStepCall *call = (AuthGSSClientStepCall *)worker->parameters; + // Get the state + state = call->context->state; + challenge = call->challenge; + + // Check what kind of challenge we have + if(call->challenge == NULL) { + challenge = (char *)""; + } + + // Perform authentication step + response = authenticate_gss_client_step(state, challenge); + + // If we have an error mark worker as having had an error + if(response->return_code == AUTH_GSS_ERROR) { + worker->error = TRUE; + worker->error_code = response->return_code; + worker->error_message = response->message; + } else { + worker->return_code = response->return_code; + } + + // Free up structure + if(call->challenge != NULL) free(call->challenge); + free(call); + free(response); +} + +static Handle _map_authGSSClientStep(Worker *worker) { + HandleScope scope; + // Return the return code + return scope.Close(Int32::New(worker->return_code)); +} + +// Initialize method +Handle Kerberos::AuthGSSClientStep(const Arguments &args) { + HandleScope scope; + + // Ensure valid call + if(args.Length() != 2 && args.Length() != 3) return VException("Requires a GSS context, optional challenge string and callback function"); + if(args.Length() == 2 && !KerberosContext::HasInstance(args[0])) return VException("Requires a GSS context, optional challenge string and callback function"); + if(args.Length() == 3 && !KerberosContext::HasInstance(args[0]) && !args[1]->IsString()) return VException("Requires a GSS context, optional challenge string and callback function"); + + // Challenge string + char *challenge_str = NULL; + // Let's unpack the parameters + Local object = args[0]->ToObject(); + KerberosContext *kerberos_context = KerberosContext::Unwrap(object); + + // If we have a challenge string + if(args.Length() == 3) { + // Unpack the challenge string + Local challenge = args[1]->ToString(); + // Convert uri string to c-string + challenge_str = (char *)calloc(challenge->Utf8Length() + 1, sizeof(char)); + // Write v8 string to c-string + challenge->WriteUtf8(challenge_str); + } + + // Allocate a structure + AuthGSSClientStepCall *call = (AuthGSSClientStepCall *)calloc(1, sizeof(AuthGSSClientCall)); + call->context = kerberos_context; + call->challenge = challenge_str; + + // Unpack the callback + Local callback = Local::Cast(args[2]); + + // Let's allocate some space + Worker *worker = new Worker(); + worker->error = false; + worker->request.data = worker; + worker->callback = Persistent::New(callback); + worker->parameters = call; + worker->execute = _authGSSClientStep; + worker->mapper = _map_authGSSClientStep; + + // Schedule the worker with lib_uv + uv_queue_work(uv_default_loop(), &worker->request, Kerberos::Process, (uv_after_work_cb)Kerberos::After); + + // Return no value as it's callback based + return scope.Close(Undefined()); +} + +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// authGSSClientUnwrap +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +static void _authGSSClientUnwrap(Worker *worker) { + gss_client_response *response; + char *challenge; + + // Unpack the parameter data struct + AuthGSSClientUnwrapCall *call = (AuthGSSClientUnwrapCall *)worker->parameters; + challenge = call->challenge; + + // Check what kind of challenge we have + if(call->challenge == NULL) { + challenge = (char *)""; + } + + // Perform authentication step + response = authenticate_gss_client_unwrap(call->context->state, challenge); + + // If we have an error mark worker as having had an error + if(response->return_code == AUTH_GSS_ERROR) { + worker->error = TRUE; + worker->error_code = response->return_code; + worker->error_message = response->message; + } else { + worker->return_code = response->return_code; + } + + // Free up structure + if(call->challenge != NULL) free(call->challenge); + free(call); + free(response); +} + +static Handle _map_authGSSClientUnwrap(Worker *worker) { + HandleScope scope; + // Return the return code + return scope.Close(Int32::New(worker->return_code)); +} + +// Initialize method +Handle Kerberos::AuthGSSClientUnwrap(const Arguments &args) { + HandleScope scope; + + // Ensure valid call + if(args.Length() != 2 && args.Length() != 3) return VException("Requires a GSS context, optional challenge string and callback function"); + if(args.Length() == 2 && !KerberosContext::HasInstance(args[0]) && !args[1]->IsFunction()) return VException("Requires a GSS context, optional challenge string and callback function"); + if(args.Length() == 3 && !KerberosContext::HasInstance(args[0]) && !args[1]->IsString() && !args[2]->IsFunction()) return VException("Requires a GSS context, optional challenge string and callback function"); + + // Challenge string + char *challenge_str = NULL; + // Let's unpack the parameters + Local object = args[0]->ToObject(); + KerberosContext *kerberos_context = KerberosContext::Unwrap(object); + + // If we have a challenge string + if(args.Length() == 3) { + // Unpack the challenge string + Local challenge = args[1]->ToString(); + // Convert uri string to c-string + challenge_str = (char *)calloc(challenge->Utf8Length() + 1, sizeof(char)); + // Write v8 string to c-string + challenge->WriteUtf8(challenge_str); + } + + // Allocate a structure + AuthGSSClientUnwrapCall *call = (AuthGSSClientUnwrapCall *)calloc(1, sizeof(AuthGSSClientUnwrapCall)); + call->context = kerberos_context; + call->challenge = challenge_str; + + // Unpack the callback + Local callback = args.Length() == 3 ? Local::Cast(args[2]) : Local::Cast(args[1]); + + // Let's allocate some space + Worker *worker = new Worker(); + worker->error = false; + worker->request.data = worker; + worker->callback = Persistent::New(callback); + worker->parameters = call; + worker->execute = _authGSSClientUnwrap; + worker->mapper = _map_authGSSClientUnwrap; + + // Schedule the worker with lib_uv + uv_queue_work(uv_default_loop(), &worker->request, Kerberos::Process, (uv_after_work_cb)Kerberos::After); + + // Return no value as it's callback based + return scope.Close(Undefined()); +} + +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// authGSSClientWrap +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +static void _authGSSClientWrap(Worker *worker) { + gss_client_response *response; + char *user_name = NULL; + + // Unpack the parameter data struct + AuthGSSClientWrapCall *call = (AuthGSSClientWrapCall *)worker->parameters; + user_name = call->user_name; + + // Check what kind of challenge we have + if(call->user_name == NULL) { + user_name = (char *)""; + } + + // Perform authentication step + response = authenticate_gss_client_wrap(call->context->state, call->challenge, user_name); + + // If we have an error mark worker as having had an error + if(response->return_code == AUTH_GSS_ERROR) { + worker->error = TRUE; + worker->error_code = response->return_code; + worker->error_message = response->message; + } else { + worker->return_code = response->return_code; + } + + // Free up structure + if(call->challenge != NULL) free(call->challenge); + if(call->user_name != NULL) free(call->user_name); + free(call); + free(response); +} + +static Handle _map_authGSSClientWrap(Worker *worker) { + HandleScope scope; + // Return the return code + return scope.Close(Int32::New(worker->return_code)); +} + +// Initialize method +Handle Kerberos::AuthGSSClientWrap(const Arguments &args) { + HandleScope scope; + + // Ensure valid call + if(args.Length() != 3 && args.Length() != 4) return VException("Requires a GSS context, the result from the authGSSClientResponse after authGSSClientUnwrap, optional user name and callback function"); + if(args.Length() == 3 && !KerberosContext::HasInstance(args[0]) && !args[1]->IsString() && !args[2]->IsFunction()) return VException("Requires a GSS context, the result from the authGSSClientResponse after authGSSClientUnwrap, optional user name and callback function"); + if(args.Length() == 4 && !KerberosContext::HasInstance(args[0]) && !args[1]->IsString() && !args[2]->IsString() && !args[2]->IsFunction()) return VException("Requires a GSS context, the result from the authGSSClientResponse after authGSSClientUnwrap, optional user name and callback function"); + + // Challenge string + char *challenge_str = NULL; + char *user_name_str = NULL; + + // Let's unpack the kerberos context + Local object = args[0]->ToObject(); + KerberosContext *kerberos_context = KerberosContext::Unwrap(object); + + // Unpack the challenge string + Local challenge = args[1]->ToString(); + // Convert uri string to c-string + challenge_str = (char *)calloc(challenge->Utf8Length() + 1, sizeof(char)); + // Write v8 string to c-string + challenge->WriteUtf8(challenge_str); + + // If we have a user string + if(args.Length() == 4) { + // Unpack user name + Local user_name = args[2]->ToString(); + // Convert uri string to c-string + user_name_str = (char *)calloc(user_name->Utf8Length() + 1, sizeof(char)); + // Write v8 string to c-string + user_name->WriteUtf8(user_name_str); + } + + // Allocate a structure + AuthGSSClientWrapCall *call = (AuthGSSClientWrapCall *)calloc(1, sizeof(AuthGSSClientWrapCall)); + call->context = kerberos_context; + call->challenge = challenge_str; + call->user_name = user_name_str; + + // Unpack the callback + Local callback = args.Length() == 4 ? Local::Cast(args[3]) : Local::Cast(args[2]); + + // Let's allocate some space + Worker *worker = new Worker(); + worker->error = false; + worker->request.data = worker; + worker->callback = Persistent::New(callback); + worker->parameters = call; + worker->execute = _authGSSClientWrap; + worker->mapper = _map_authGSSClientWrap; + + // Schedule the worker with lib_uv + uv_queue_work(uv_default_loop(), &worker->request, Kerberos::Process, (uv_after_work_cb)Kerberos::After); + + // Return no value as it's callback based + return scope.Close(Undefined()); +} + +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// authGSSClientWrap +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +static void _authGSSClientClean(Worker *worker) { + gss_client_response *response; + + // Unpack the parameter data struct + AuthGSSClientCleanCall *call = (AuthGSSClientCleanCall *)worker->parameters; + + // Perform authentication step + response = authenticate_gss_client_clean(call->context->state); + + // If we have an error mark worker as having had an error + if(response->return_code == AUTH_GSS_ERROR) { + worker->error = TRUE; + worker->error_code = response->return_code; + worker->error_message = response->message; + } else { + worker->return_code = response->return_code; + } + + // Free up structure + free(call); + free(response); +} + +static Handle _map_authGSSClientClean(Worker *worker) { + HandleScope scope; + // Return the return code + return scope.Close(Int32::New(worker->return_code)); +} + +// Initialize method +Handle Kerberos::AuthGSSClientClean(const Arguments &args) { + HandleScope scope; + + // // Ensure valid call + if(args.Length() != 2) return VException("Requires a GSS context and callback function"); + if(!KerberosContext::HasInstance(args[0]) && !args[1]->IsFunction()) return VException("Requires a GSS context and callback function"); + + // Let's unpack the kerberos context + Local object = args[0]->ToObject(); + KerberosContext *kerberos_context = KerberosContext::Unwrap(object); + + // Allocate a structure + AuthGSSClientCleanCall *call = (AuthGSSClientCleanCall *)calloc(1, sizeof(AuthGSSClientCleanCall)); + call->context = kerberos_context; + + // Unpack the callback + Local callback = Local::Cast(args[1]); + + // Let's allocate some space + Worker *worker = new Worker(); + worker->error = false; + worker->request.data = worker; + worker->callback = Persistent::New(callback); + worker->parameters = call; + worker->execute = _authGSSClientClean; + worker->mapper = _map_authGSSClientClean; + + // Schedule the worker with lib_uv + uv_queue_work(uv_default_loop(), &worker->request, Kerberos::Process, (uv_after_work_cb)Kerberos::After); + + // Return no value as it's callback based + return scope.Close(Undefined()); +} + +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// UV Lib callbacks +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +void Kerberos::Process(uv_work_t* work_req) { + // Grab the worker + Worker *worker = static_cast(work_req->data); + // Execute the worker code + worker->execute(worker); +} + +void Kerberos::After(uv_work_t* work_req) { + // Grab the scope of the call from Node + v8::HandleScope scope; + + // Get the worker reference + Worker *worker = static_cast(work_req->data); + + // If we have an error + if(worker->error) { + v8::Local err = v8::Exception::Error(v8::String::New(worker->error_message)); + Local obj = err->ToObject(); + obj->Set(NODE_PSYMBOL("code"), Int32::New(worker->error_code)); + v8::Local args[2] = { err, v8::Local::New(v8::Null()) }; + // Execute the error + v8::TryCatch try_catch; + // Call the callback + worker->callback->Call(v8::Context::GetCurrent()->Global(), ARRAY_SIZE(args), args); + // If we have an exception handle it as a fatalexception + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } else { + // // Map the data + v8::Handle result = worker->mapper(worker); + // Set up the callback with a null first + v8::Handle args[2] = { v8::Local::New(v8::Null()), result}; + // Wrap the callback function call in a TryCatch so that we can call + // node's FatalException afterwards. This makes it possible to catch + // the exception from JavaScript land using the + // process.on('uncaughtException') event. + v8::TryCatch try_catch; + // Call the callback + worker->callback->Call(v8::Context::GetCurrent()->Global(), ARRAY_SIZE(args), args); + // If we have an exception handle it as a fatalexception + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } + + // Clean up the memory + worker->callback.Dispose(); + delete worker; +} + +// Exporting function +extern "C" void init(Handle target) { + HandleScope scope; + Kerberos::Initialize(target); + KerberosContext::Initialize(target); +} + +NODE_MODULE(kerberos, init); diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberos.h b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberos.h new file mode 100644 index 0000000..0619957 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberos.h @@ -0,0 +1,47 @@ +#ifndef KERBEROS_H +#define KERBEROS_H + +#include +#include +#include +#include + +#include +#include + +extern "C" { + #include "kerberosgss.h" +} + +using namespace v8; +using namespace node; + +class Kerberos : public ObjectWrap { + +public: + Kerberos(); + ~Kerberos() {}; + + // Constructor used for creating new Kerberos objects from C++ + static Persistent constructor_template; + + // Initialize function for the object + static void Initialize(Handle target); + + // Method available + static Handle AuthGSSClientInit(const Arguments &args); + static Handle AuthGSSClientStep(const Arguments &args); + static Handle AuthGSSClientUnwrap(const Arguments &args); + static Handle AuthGSSClientWrap(const Arguments &args); + static Handle AuthGSSClientClean(const Arguments &args); + +private: + static Handle New(const Arguments &args); + + // Handles the uv calls + static void Process(uv_work_t* work_req); + // Called after work is done + static void After(uv_work_t* work_req); +}; + +#endif \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberos.js b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberos.js new file mode 100644 index 0000000..b1a701b --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberos.js @@ -0,0 +1,91 @@ +var kerberos = require('../build/Release/kerberos') + , KerberosNative = kerberos.Kerberos; + +var Kerberos = function() { + this._native_kerberos = new KerberosNative(); +} + +Kerberos.prototype.authGSSClientInit = function(uri, flags, callback) { + return this._native_kerberos.authGSSClientInit(uri, flags, callback); +} + +Kerberos.prototype.authGSSClientStep = function(context, challenge, callback) { + if(typeof challenge == 'function') { + callback = challenge; + challenge = ''; + } + + return this._native_kerberos.authGSSClientStep(context, challenge, callback); +} + +Kerberos.prototype.authGSSClientUnwrap = function(context, challenge, callback) { + if(typeof challenge == 'function') { + callback = challenge; + challenge = ''; + } + + return this._native_kerberos.authGSSClientUnwrap(context, challenge, callback); +} + +Kerberos.prototype.authGSSClientWrap = function(context, challenge, user_name, callback) { + if(typeof user_name == 'function') { + callback = user_name; + user_name = ''; + } + + return this._native_kerberos.authGSSClientWrap(context, challenge, user_name, callback); +} + +Kerberos.prototype.authGSSClientClean = function(context, callback) { + return this._native_kerberos.authGSSClientClean(context, callback); +} + +Kerberos.prototype.acquireAlternateCredentials = function(user_name, password, domain) { + return this._native_kerberos.acquireAlternateCredentials(user_name, password, domain); +} + +Kerberos.prototype.prepareOutboundPackage = function(principal, inputdata) { + return this._native_kerberos.prepareOutboundPackage(principal, inputdata); +} + +Kerberos.prototype.decryptMessage = function(challenge) { + return this._native_kerberos.decryptMessage(challenge); +} + +Kerberos.prototype.encryptMessage = function(challenge) { + return this._native_kerberos.encryptMessage(challenge); +} + +Kerberos.prototype.queryContextAttribute = function(attribute) { + if(typeof attribute != 'number' && attribute != 0x00) throw new Error("Attribute not supported"); + return this._native_kerberos.queryContextAttribute(attribute); +} + +// Some useful result codes +Kerberos.AUTH_GSS_CONTINUE = 0; +Kerberos.AUTH_GSS_COMPLETE = 1; + +// Some useful gss flags +Kerberos.GSS_C_DELEG_FLAG = 1; +Kerberos.GSS_C_MUTUAL_FLAG = 2; +Kerberos.GSS_C_REPLAY_FLAG = 4; +Kerberos.GSS_C_SEQUENCE_FLAG = 8; +Kerberos.GSS_C_CONF_FLAG = 16; +Kerberos.GSS_C_INTEG_FLAG = 32; +Kerberos.GSS_C_ANON_FLAG = 64; +Kerberos.GSS_C_PROT_READY_FLAG = 128; +Kerberos.GSS_C_TRANS_FLAG = 256; + +// Export Kerberos class +exports.Kerberos = Kerberos; + +// If we have SSPI (windows) +if(kerberos.SecurityCredentials) { + // Put all SSPI classes in it's own namespace + exports.SSIP = { + SecurityCredentials: require('./win32/wrappers/security_credentials').SecurityCredentials + , SecurityContext: require('./win32/wrappers/security_context').SecurityContext + , SecurityBuffer: require('./win32/wrappers/security_buffer').SecurityBuffer + , SecurityBufferDescriptor: require('./win32/wrappers/security_buffer_descriptor').SecurityBufferDescriptor + } +} diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberos_context.cc b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberos_context.cc new file mode 100644 index 0000000..7a5f4eb --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberos_context.cc @@ -0,0 +1,74 @@ +#include "kerberos_context.h" + +Persistent KerberosContext::constructor_template; + +KerberosContext::KerberosContext() : ObjectWrap() { +} + +KerberosContext::~KerberosContext() { +} + +KerberosContext* KerberosContext::New() { + HandleScope scope; + + Local obj = constructor_template->GetFunction()->NewInstance(); + KerberosContext *kerberos_context = ObjectWrap::Unwrap(obj); + + return kerberos_context; +} + +Handle KerberosContext::New(const Arguments &args) { + HandleScope scope; + // Create code object + KerberosContext *kerberos_context = new KerberosContext(); + // Wrap it + kerberos_context->Wrap(args.This()); + // Return the object + return args.This(); +} + +static Persistent response_symbol; + +void KerberosContext::Initialize(Handle target) { + // Grab the scope of the call from Node + HandleScope scope; + // Define a new function template + Local t = FunctionTemplate::New(New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("KerberosContext")); + + // Property symbols + response_symbol = NODE_PSYMBOL("response"); + + // Getter for the response + constructor_template->InstanceTemplate()->SetAccessor(response_symbol, ResponseGetter); + + // Set up the Symbol for the Class on the Module + target->Set(String::NewSymbol("KerberosContext"), constructor_template->GetFunction()); +} + +// +// Response Setter / Getter +Handle KerberosContext::ResponseGetter(Local property, const AccessorInfo& info) { + HandleScope scope; + gss_client_state *state; + + // Unpack the object + KerberosContext *context = ObjectWrap::Unwrap(info.Holder()); + // Let's grab the response + state = context->state; + // No state no response + if(state == NULL || state->response == NULL) return scope.Close(Null()); + // Return the response + return scope.Close(String::New(state->response)); +} + + + + + + + + + diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberos_context.h b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberos_context.h new file mode 100644 index 0000000..8becef6 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberos_context.h @@ -0,0 +1,48 @@ +#ifndef KERBEROS_CONTEXT_H +#define KERBEROS_CONTEXT_H + +#include +#include +#include +#include + +#include +#include + +extern "C" { + #include "kerberosgss.h" +} + +using namespace v8; +using namespace node; + +class KerberosContext : public ObjectWrap { + +public: + KerberosContext(); + ~KerberosContext(); + + static inline bool HasInstance(Handle val) { + if (!val->IsObject()) return false; + Local obj = val->ToObject(); + return constructor_template->HasInstance(obj); + }; + + // Constructor used for creating new Kerberos objects from C++ + static Persistent constructor_template; + + // Initialize function for the object + static void Initialize(Handle target); + + // Public constructor + static KerberosContext* New(); + + // Handle to the kerberos context + gss_client_state *state; + +private: + static Handle New(const Arguments &args); + + static Handle ResponseGetter(Local property, const AccessorInfo& info); +}; +#endif \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberosgss.c b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberosgss.c new file mode 100644 index 0000000..f17003d --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberosgss.c @@ -0,0 +1,666 @@ +/** + * Copyright (c) 2006-2010 Apple Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +#include "kerberosgss.h" + +#include "base64.h" + +#include +#include +#include +#include + +static void set_gss_error(OM_uint32 err_maj, OM_uint32 err_min); + +/*extern PyObject *GssException_class; +extern PyObject *KrbException_class; + +char* server_principal_details(const char* service, const char* hostname) +{ + char match[1024]; + int match_len = 0; + char* result = NULL; + + int code; + krb5_context kcontext; + krb5_keytab kt = NULL; + krb5_kt_cursor cursor = NULL; + krb5_keytab_entry entry; + char* pname = NULL; + + // Generate the principal prefix we want to match + snprintf(match, 1024, "%s/%s@", service, hostname); + match_len = strlen(match); + + code = krb5_init_context(&kcontext); + if (code) + { + PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))", + "Cannot initialize Kerberos5 context", code)); + return NULL; + } + + if ((code = krb5_kt_default(kcontext, &kt))) + { + PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))", + "Cannot get default keytab", code)); + goto end; + } + + if ((code = krb5_kt_start_seq_get(kcontext, kt, &cursor))) + { + PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))", + "Cannot get sequence cursor from keytab", code)); + goto end; + } + + while ((code = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0) + { + if ((code = krb5_unparse_name(kcontext, entry.principal, &pname))) + { + PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))", + "Cannot parse principal name from keytab", code)); + goto end; + } + + if (strncmp(pname, match, match_len) == 0) + { + result = malloc(strlen(pname) + 1); + strcpy(result, pname); + krb5_free_unparsed_name(kcontext, pname); + krb5_free_keytab_entry_contents(kcontext, &entry); + break; + } + + krb5_free_unparsed_name(kcontext, pname); + krb5_free_keytab_entry_contents(kcontext, &entry); + } + + if (result == NULL) + { + PyErr_SetObject(KrbException_class, Py_BuildValue("((s:i))", + "Principal not found in keytab", -1)); + } + +end: + if (cursor) + krb5_kt_end_seq_get(kcontext, kt, &cursor); + if (kt) + krb5_kt_close(kcontext, kt); + krb5_free_context(kcontext); + + return result; +} +*/ +gss_client_response *authenticate_gss_client_init(const char* service, long int gss_flags, gss_client_state* state) { + OM_uint32 maj_stat; + OM_uint32 min_stat; + gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER; + gss_client_response *response = NULL; + int ret = AUTH_GSS_COMPLETE; + + state->server_name = GSS_C_NO_NAME; + state->context = GSS_C_NO_CONTEXT; + state->gss_flags = gss_flags; + state->username = NULL; + state->response = NULL; + + // Import server name first + name_token.length = strlen(service); + name_token.value = (char *)service; + + maj_stat = gss_import_name(&min_stat, &name_token, gss_krb5_nt_service_name, &state->server_name); + + if (GSS_ERROR(maj_stat)) { + response = gss_error(maj_stat, min_stat); + response->return_code = AUTH_GSS_ERROR; + goto end; + } + +end: + if(response == NULL) { + response = calloc(1, sizeof(gss_client_response)); + response->return_code = ret; + } + + return response; +} + +gss_client_response *authenticate_gss_client_clean(gss_client_state *state) { + OM_uint32 min_stat; + int ret = AUTH_GSS_COMPLETE; + gss_client_response *response = NULL; + + if(state->context != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&min_stat, &state->context, GSS_C_NO_BUFFER); + + if(state->server_name != GSS_C_NO_NAME) + gss_release_name(&min_stat, &state->server_name); + + if(state->username != NULL) { + free(state->username); + state->username = NULL; + } + + if (state->response != NULL) { + free(state->response); + state->response = NULL; + } + + if(response == NULL) { + response = calloc(1, sizeof(gss_client_response)); + response->return_code = ret; + } + + return response; +} + +gss_client_response *authenticate_gss_client_step(gss_client_state* state, const char* challenge) { + OM_uint32 maj_stat; + OM_uint32 min_stat; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + int ret = AUTH_GSS_CONTINUE; + gss_client_response *response = NULL; + + // Always clear out the old response + if (state->response != NULL) { + free(state->response); + state->response = NULL; + } + + // If there is a challenge (data from the server) we need to give it to GSS + if (challenge && *challenge) { + int len; + input_token.value = base64_decode(challenge, &len); + input_token.length = len; + } + + // Do GSSAPI step + maj_stat = gss_init_sec_context(&min_stat, + GSS_C_NO_CREDENTIAL, + &state->context, + state->server_name, + GSS_C_NO_OID, + (OM_uint32)state->gss_flags, + 0, + GSS_C_NO_CHANNEL_BINDINGS, + &input_token, + NULL, + &output_token, + NULL, + NULL); + + if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED)) { + response = gss_error(maj_stat, min_stat); + response->return_code = AUTH_GSS_ERROR; + goto end; + } + + ret = (maj_stat == GSS_S_COMPLETE) ? AUTH_GSS_COMPLETE : AUTH_GSS_CONTINUE; + // Grab the client response to send back to the server + if(output_token.length) { + state->response = base64_encode((const unsigned char *)output_token.value, output_token.length); + maj_stat = gss_release_buffer(&min_stat, &output_token); + } + + // Try to get the user name if we have completed all GSS operations + if (ret == AUTH_GSS_COMPLETE) { + gss_name_t gssuser = GSS_C_NO_NAME; + maj_stat = gss_inquire_context(&min_stat, state->context, &gssuser, NULL, NULL, NULL, NULL, NULL, NULL); + + if(GSS_ERROR(maj_stat)) { + response = gss_error(maj_stat, min_stat); + response->return_code = AUTH_GSS_ERROR; + goto end; + } + + gss_buffer_desc name_token; + name_token.length = 0; + maj_stat = gss_display_name(&min_stat, gssuser, &name_token, NULL); + + if(GSS_ERROR(maj_stat)) { + if(name_token.value) + gss_release_buffer(&min_stat, &name_token); + gss_release_name(&min_stat, &gssuser); + + response = gss_error(maj_stat, min_stat); + response->return_code = AUTH_GSS_ERROR; + goto end; + } else { + state->username = (char *)malloc(name_token.length + 1); + strncpy(state->username, (char*) name_token.value, name_token.length); + state->username[name_token.length] = 0; + gss_release_buffer(&min_stat, &name_token); + gss_release_name(&min_stat, &gssuser); + } + } + +end: + if(output_token.value) + gss_release_buffer(&min_stat, &output_token); + if(input_token.value) + free(input_token.value); + + if(response == NULL) { + response = calloc(1, sizeof(gss_client_response)); + response->return_code = ret; + } + + // Return the response + return response; +} + +gss_client_response *authenticate_gss_client_unwrap(gss_client_state *state, const char *challenge) { + OM_uint32 maj_stat; + OM_uint32 min_stat; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + gss_client_response *response = NULL; + int ret = AUTH_GSS_CONTINUE; + + // Always clear out the old response + if(state->response != NULL) { + free(state->response); + state->response = NULL; + } + + // If there is a challenge (data from the server) we need to give it to GSS + if(challenge && *challenge) { + int len; + input_token.value = base64_decode(challenge, &len); + input_token.length = len; + } + + // Do GSSAPI step + maj_stat = gss_unwrap(&min_stat, + state->context, + &input_token, + &output_token, + NULL, + NULL); + + if(maj_stat != GSS_S_COMPLETE) { + response = gss_error(maj_stat, min_stat); + response->return_code = AUTH_GSS_ERROR; + goto end; + } else { + ret = AUTH_GSS_COMPLETE; + } + + // Grab the client response + if(output_token.length) { + state->response = base64_encode((const unsigned char *)output_token.value, output_token.length); + maj_stat = gss_release_buffer(&min_stat, &output_token); + } +end: + if(output_token.value) + gss_release_buffer(&min_stat, &output_token); + if(input_token.value) + free(input_token.value); + + if(response == NULL) { + response = calloc(1, sizeof(gss_client_response)); + response->return_code = ret; + } + + // Return the response + return response; +} + +gss_client_response *authenticate_gss_client_wrap(gss_client_state* state, const char* challenge, const char* user) { + OM_uint32 maj_stat; + OM_uint32 min_stat; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + int ret = AUTH_GSS_CONTINUE; + gss_client_response *response = NULL; + char buf[4096], server_conf_flags; + unsigned long buf_size; + + // Always clear out the old response + if(state->response != NULL) { + free(state->response); + state->response = NULL; + } + + if(challenge && *challenge) { + int len; + input_token.value = base64_decode(challenge, &len); + input_token.length = len; + } + + if(user) { + // get bufsize + server_conf_flags = ((char*) input_token.value)[0]; + ((char*) input_token.value)[0] = 0; + buf_size = ntohl(*((long *) input_token.value)); + free(input_token.value); +#ifdef PRINTFS + printf("User: %s, %c%c%c\n", user, + server_conf_flags & GSS_AUTH_P_NONE ? 'N' : '-', + server_conf_flags & GSS_AUTH_P_INTEGRITY ? 'I' : '-', + server_conf_flags & GSS_AUTH_P_PRIVACY ? 'P' : '-'); + printf("Maximum GSS token size is %ld\n", buf_size); +#endif + + // agree to terms (hack!) + buf_size = htonl(buf_size); // not relevant without integrity/privacy + memcpy(buf, &buf_size, 4); + buf[0] = GSS_AUTH_P_NONE; + // server decides if principal can log in as user + strncpy(buf + 4, user, sizeof(buf) - 4); + input_token.value = buf; + input_token.length = 4 + strlen(user); + } + + // Do GSSAPI wrap + maj_stat = gss_wrap(&min_stat, + state->context, + 0, + GSS_C_QOP_DEFAULT, + &input_token, + NULL, + &output_token); + + if (maj_stat != GSS_S_COMPLETE) { + response = gss_error(maj_stat, min_stat); + response->return_code = AUTH_GSS_ERROR; + goto end; + } else + ret = AUTH_GSS_COMPLETE; + // Grab the client response to send back to the server + if (output_token.length) { + state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);; + maj_stat = gss_release_buffer(&min_stat, &output_token); + } +end: + if (output_token.value) + gss_release_buffer(&min_stat, &output_token); + + if(response == NULL) { + response = calloc(1, sizeof(gss_client_response)); + response->return_code = ret; + } + + // Return the response + return response; +} + +int authenticate_gss_server_init(const char *service, gss_server_state *state) +{ + OM_uint32 maj_stat; + OM_uint32 min_stat; + gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER; + int ret = AUTH_GSS_COMPLETE; + + state->context = GSS_C_NO_CONTEXT; + state->server_name = GSS_C_NO_NAME; + state->client_name = GSS_C_NO_NAME; + state->server_creds = GSS_C_NO_CREDENTIAL; + state->client_creds = GSS_C_NO_CREDENTIAL; + state->username = NULL; + state->targetname = NULL; + state->response = NULL; + + // Server name may be empty which means we aren't going to create our own creds + size_t service_len = strlen(service); + if (service_len != 0) + { + // Import server name first + name_token.length = strlen(service); + name_token.value = (char *)service; + + maj_stat = gss_import_name(&min_stat, &name_token, GSS_C_NT_HOSTBASED_SERVICE, &state->server_name); + + if (GSS_ERROR(maj_stat)) + { + set_gss_error(maj_stat, min_stat); + ret = AUTH_GSS_ERROR; + goto end; + } + + // Get credentials + maj_stat = gss_acquire_cred(&min_stat, state->server_name, GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, GSS_C_ACCEPT, &state->server_creds, NULL, NULL); + + if (GSS_ERROR(maj_stat)) + { + set_gss_error(maj_stat, min_stat); + ret = AUTH_GSS_ERROR; + goto end; + } + } + +end: + return ret; +} + +int authenticate_gss_server_clean(gss_server_state *state) +{ + OM_uint32 min_stat; + int ret = AUTH_GSS_COMPLETE; + + if (state->context != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&min_stat, &state->context, GSS_C_NO_BUFFER); + if (state->server_name != GSS_C_NO_NAME) + gss_release_name(&min_stat, &state->server_name); + if (state->client_name != GSS_C_NO_NAME) + gss_release_name(&min_stat, &state->client_name); + if (state->server_creds != GSS_C_NO_CREDENTIAL) + gss_release_cred(&min_stat, &state->server_creds); + if (state->client_creds != GSS_C_NO_CREDENTIAL) + gss_release_cred(&min_stat, &state->client_creds); + if (state->username != NULL) + { + free(state->username); + state->username = NULL; + } + if (state->targetname != NULL) + { + free(state->targetname); + state->targetname = NULL; + } + if (state->response != NULL) + { + free(state->response); + state->response = NULL; + } + + return ret; +} + +/*int authenticate_gss_server_step(gss_server_state *state, const char *challenge) +{ + OM_uint32 maj_stat; + OM_uint32 min_stat; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + int ret = AUTH_GSS_CONTINUE; + + // Always clear out the old response + if (state->response != NULL) + { + free(state->response); + state->response = NULL; + } + + // If there is a challenge (data from the server) we need to give it to GSS + if (challenge && *challenge) + { + int len; + input_token.value = base64_decode(challenge, &len); + input_token.length = len; + } + else + { + PyErr_SetString(KrbException_class, "No challenge parameter in request from client"); + ret = AUTH_GSS_ERROR; + goto end; + } + + maj_stat = gss_accept_sec_context(&min_stat, + &state->context, + state->server_creds, + &input_token, + GSS_C_NO_CHANNEL_BINDINGS, + &state->client_name, + NULL, + &output_token, + NULL, + NULL, + &state->client_creds); + + if (GSS_ERROR(maj_stat)) + { + set_gss_error(maj_stat, min_stat); + ret = AUTH_GSS_ERROR; + goto end; + } + + // Grab the server response to send back to the client + if (output_token.length) + { + state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);; + maj_stat = gss_release_buffer(&min_stat, &output_token); + } + + // Get the user name + maj_stat = gss_display_name(&min_stat, state->client_name, &output_token, NULL); + if (GSS_ERROR(maj_stat)) + { + set_gss_error(maj_stat, min_stat); + ret = AUTH_GSS_ERROR; + goto end; + } + state->username = (char *)malloc(output_token.length + 1); + strncpy(state->username, (char*) output_token.value, output_token.length); + state->username[output_token.length] = 0; + + // Get the target name if no server creds were supplied + if (state->server_creds == GSS_C_NO_CREDENTIAL) + { + gss_name_t target_name = GSS_C_NO_NAME; + maj_stat = gss_inquire_context(&min_stat, state->context, NULL, &target_name, NULL, NULL, NULL, NULL, NULL); + if (GSS_ERROR(maj_stat)) + { + set_gss_error(maj_stat, min_stat); + ret = AUTH_GSS_ERROR; + goto end; + } + maj_stat = gss_display_name(&min_stat, target_name, &output_token, NULL); + if (GSS_ERROR(maj_stat)) + { + set_gss_error(maj_stat, min_stat); + ret = AUTH_GSS_ERROR; + goto end; + } + state->targetname = (char *)malloc(output_token.length + 1); + strncpy(state->targetname, (char*) output_token.value, output_token.length); + state->targetname[output_token.length] = 0; + } + + ret = AUTH_GSS_COMPLETE; + +end: + if (output_token.length) + gss_release_buffer(&min_stat, &output_token); + if (input_token.value) + free(input_token.value); + return ret; +} +*/ + +static void set_gss_error(OM_uint32 err_maj, OM_uint32 err_min) { + OM_uint32 maj_stat, min_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc status_string; + char buf_maj[512]; + char buf_min[512]; + + do { + maj_stat = gss_display_status (&min_stat, + err_maj, + GSS_C_GSS_CODE, + GSS_C_NO_OID, + &msg_ctx, + &status_string); + if(GSS_ERROR(maj_stat)) + break; + + strncpy(buf_maj, (char*) status_string.value, sizeof(buf_maj)); + gss_release_buffer(&min_stat, &status_string); + + maj_stat = gss_display_status (&min_stat, + err_min, + GSS_C_MECH_CODE, + GSS_C_NULL_OID, + &msg_ctx, + &status_string); + if (!GSS_ERROR(maj_stat)) { + + strncpy(buf_min, (char*) status_string.value , sizeof(buf_min)); + gss_release_buffer(&min_stat, &status_string); + } + } while (!GSS_ERROR(maj_stat) && msg_ctx != 0); +} + +gss_client_response *gss_error(OM_uint32 err_maj, OM_uint32 err_min) { + OM_uint32 maj_stat, min_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc status_string; + char *buf_maj = calloc(512, sizeof(char)); + char *buf_min = calloc(512, sizeof(char)); + char *message = NULL; + gss_client_response *response = calloc(1, sizeof(gss_client_response)); + + do { + maj_stat = gss_display_status (&min_stat, + err_maj, + GSS_C_GSS_CODE, + GSS_C_NO_OID, + &msg_ctx, + &status_string); + if(GSS_ERROR(maj_stat)) + break; + + strncpy(buf_maj, (char*) status_string.value, 512); + gss_release_buffer(&min_stat, &status_string); + + maj_stat = gss_display_status (&min_stat, + err_min, + GSS_C_MECH_CODE, + GSS_C_NULL_OID, + &msg_ctx, + &status_string); + if(!GSS_ERROR(maj_stat)) { + strncpy(buf_min, (char*) status_string.value , 512); + gss_release_buffer(&min_stat, &status_string); + } + } while (!GSS_ERROR(maj_stat) && msg_ctx != 0); + + // Join the strings + message = calloc(1026, 1); + // Join the two messages + sprintf(message, "%s, %s", buf_maj, buf_min); + // Free data + free(buf_min); + free(buf_maj); + // Set the message + response->message = message; + // Return the message + return response; +} diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberosgss.h b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberosgss.h new file mode 100644 index 0000000..58ac0b7 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/kerberosgss.h @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2006-2009 Apple Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ +#ifndef KERBEROS_GSS_H +#define KERBEROS_GSS_H + +#include +#include +#include + +#define krb5_get_err_text(context,code) error_message(code) + +#define AUTH_GSS_ERROR -1 +#define AUTH_GSS_COMPLETE 1 +#define AUTH_GSS_CONTINUE 0 + +#define GSS_AUTH_P_NONE 1 +#define GSS_AUTH_P_INTEGRITY 2 +#define GSS_AUTH_P_PRIVACY 4 + +typedef struct { + int return_code; + char *message; +} gss_client_response; + +typedef struct { + gss_ctx_id_t context; + gss_name_t server_name; + long int gss_flags; + char* username; + char* response; +} gss_client_state; + +typedef struct { + gss_ctx_id_t context; + gss_name_t server_name; + gss_name_t client_name; + gss_cred_id_t server_creds; + gss_cred_id_t client_creds; + char* username; + char* targetname; + char* response; +} gss_server_state; + +// char* server_principal_details(const char* service, const char* hostname); + +gss_client_response *authenticate_gss_client_init(const char* service, long int gss_flags, gss_client_state* state); +gss_client_response *authenticate_gss_client_clean(gss_client_state *state); +gss_client_response *authenticate_gss_client_step(gss_client_state *state, const char *challenge); +gss_client_response *authenticate_gss_client_unwrap(gss_client_state* state, const char* challenge); +gss_client_response *authenticate_gss_client_wrap(gss_client_state* state, const char* challenge, const char* user); + +int authenticate_gss_server_init(const char* service, gss_server_state* state); +int authenticate_gss_server_clean(gss_server_state *state); +// int authenticate_gss_server_step(gss_server_state *state, const char *challenge); + +gss_client_response *gss_error(OM_uint32 err_maj, OM_uint32 err_min); +#endif diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/sspi.js b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/sspi.js new file mode 100644 index 0000000..d9120fb --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/sspi.js @@ -0,0 +1,15 @@ +// Load the native SSPI classes +var kerberos = require('../build/Release/kerberos') + , Kerberos = kerberos.Kerberos + , SecurityBuffer = require('./win32/wrappers/security_buffer').SecurityBuffer + , SecurityBufferDescriptor = require('./win32/wrappers/security_buffer_descriptor').SecurityBufferDescriptor + , SecurityCredentials = require('./win32/wrappers/security_credentials').SecurityCredentials + , SecurityContext = require('./win32/wrappers/security_context').SecurityContext; +var SSPI = function() { +} + +exports.SSPI = SSPI; +exports.SecurityBuffer = SecurityBuffer; +exports.SecurityBufferDescriptor = SecurityBufferDescriptor; +exports.SecurityCredentials = SecurityCredentials; +exports.SecurityContext = SecurityContext; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/base64.c b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/base64.c new file mode 100644 index 0000000..502a021 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/base64.c @@ -0,0 +1,121 @@ +/** + * Copyright (c) 2006-2008 Apple Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +#include "base64.h" + +#include +#include + +// base64 tables +static char basis_64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static signed char index_64[128] = +{ + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 +}; +#define CHAR64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)]) + +// base64_encode : base64 encode +// +// value : data to encode +// vlen : length of data +// (result) : new char[] - c-str of result +char *base64_encode(const unsigned char *value, int vlen) +{ + char *result = (char *)malloc((vlen * 4) / 3 + 5); + char *out = result; + unsigned char oval; + + while (vlen >= 3) + { + *out++ = basis_64[value[0] >> 2]; + *out++ = basis_64[((value[0] << 4) & 0x30) | (value[1] >> 4)]; + *out++ = basis_64[((value[1] << 2) & 0x3C) | (value[2] >> 6)]; + *out++ = basis_64[value[2] & 0x3F]; + value += 3; + vlen -= 3; + } + if (vlen > 0) + { + *out++ = basis_64[value[0] >> 2]; + oval = (value[0] << 4) & 0x30; + if (vlen > 1) oval |= value[1] >> 4; + *out++ = basis_64[oval]; + *out++ = (vlen < 2) ? '=' : basis_64[(value[1] << 2) & 0x3C]; + *out++ = '='; + } + *out = '\0'; + + return result; +} + +// base64_decode : base64 decode +// +// value : c-str to decode +// rlen : length of decoded result +// (result) : new unsigned char[] - decoded result +unsigned char *base64_decode(const char *value, int *rlen) +{ + int c1, c2, c3, c4; + int vlen = (int)strlen(value); + unsigned char *result =(unsigned char *)malloc((vlen * 3) / 4 + 1); + unsigned char *out = result; + *rlen = 0; + + while (1) + { + if (value[0]==0) + return result; + c1 = value[0]; + if (CHAR64(c1) == -1) + goto base64_decode_error;; + c2 = value[1]; + if (CHAR64(c2) == -1) + goto base64_decode_error;; + c3 = value[2]; + if ((c3 != '=') && (CHAR64(c3) == -1)) + goto base64_decode_error;; + c4 = value[3]; + if ((c4 != '=') && (CHAR64(c4) == -1)) + goto base64_decode_error;; + + value += 4; + *out++ = (CHAR64(c1) << 2) | (CHAR64(c2) >> 4); + *rlen += 1; + if (c3 != '=') + { + *out++ = ((CHAR64(c2) << 4) & 0xf0) | (CHAR64(c3) >> 2); + *rlen += 1; + if (c4 != '=') + { + *out++ = ((CHAR64(c3) << 6) & 0xc0) | CHAR64(c4); + *rlen += 1; + } + } + } + +base64_decode_error: + *result = 0; + *rlen = 0; + return result; +} diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/base64.h b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/base64.h new file mode 100644 index 0000000..f0e1f06 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/base64.h @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2006-2008 Apple Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +char *base64_encode(const unsigned char *value, int vlen); +unsigned char *base64_decode(const char *value, int *rlen); diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/kerberos.cc b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/kerberos.cc new file mode 100644 index 0000000..7fd521b --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/kerberos.cc @@ -0,0 +1,53 @@ +#include "kerberos.h" +#include +#include +#include "base64.h" +#include "wrappers/security_buffer.h" +#include "wrappers/security_buffer_descriptor.h" +#include "wrappers/security_context.h" +#include "wrappers/security_credentials.h" + +Persistent Kerberos::constructor_template; + +// VException object (causes throw in calling code) +static Handle VException(const char *msg) { + HandleScope scope; + return ThrowException(Exception::Error(String::New(msg))); +} + +Kerberos::Kerberos() : ObjectWrap() { +} + +void Kerberos::Initialize(v8::Handle target) { + // Grab the scope of the call from Node + HandleScope scope; + // Define a new function template + Local t = FunctionTemplate::New(Kerberos::New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("Kerberos")); + // Set the symbol + target->ForceSet(String::NewSymbol("Kerberos"), constructor_template->GetFunction()); +} + +Handle Kerberos::New(const Arguments &args) { + // Load the security.dll library + load_library(); + // Create a Kerberos instance + Kerberos *kerberos = new Kerberos(); + // Return the kerberos object + kerberos->Wrap(args.This()); + return args.This(); +} + +// Exporting function +extern "C" void init(Handle target) { + HandleScope scope; + Kerberos::Initialize(target); + SecurityContext::Initialize(target); + SecurityBuffer::Initialize(target); + SecurityBufferDescriptor::Initialize(target); + SecurityCredentials::Initialize(target); +} + +NODE_MODULE(kerberos, init); diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/kerberos.h b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/kerberos.h new file mode 100644 index 0000000..8443e78 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/kerberos.h @@ -0,0 +1,59 @@ +#ifndef KERBEROS_H +#define KERBEROS_H + +#include +#include +#include + +extern "C" { + #include "kerberos_sspi.h" + #include "base64.h" +} + +using namespace v8; +using namespace node; + +class Kerberos : public ObjectWrap { + +public: + Kerberos(); + ~Kerberos() {}; + + // Constructor used for creating new Kerberos objects from C++ + static Persistent constructor_template; + + // Initialize function for the object + static void Initialize(Handle target); + + // Method available + static Handle AcquireAlternateCredentials(const Arguments &args); + static Handle PrepareOutboundPackage(const Arguments &args); + static Handle DecryptMessage(const Arguments &args); + static Handle EncryptMessage(const Arguments &args); + static Handle QueryContextAttributes(const Arguments &args); + +private: + static Handle New(const Arguments &args); + + // Pointer to context object + SEC_WINNT_AUTH_IDENTITY m_Identity; + // credentials + CredHandle m_Credentials; + // Expiry time for ticket + TimeStamp Expiration; + // package info + SecPkgInfo m_PkgInfo; + // context + CtxtHandle m_Context; + // Do we have a context + bool m_HaveContext; + // Attributes + DWORD CtxtAttr; + + // Handles the uv calls + static void Process(uv_work_t* work_req); + // Called after work is done + static void After(uv_work_t* work_req); +}; + +#endif \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/kerberos_sspi.c b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/kerberos_sspi.c new file mode 100644 index 0000000..d75c9ab --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/kerberos_sspi.c @@ -0,0 +1,244 @@ +#include "kerberos_sspi.h" +#include +#include + +static HINSTANCE _sspi_security_dll = NULL; +static HINSTANCE _sspi_secur32_dll = NULL; + +/** + * Encrypt A Message + */ +SECURITY_STATUS SEC_ENTRY _sspi_EncryptMessage(PCtxtHandle phContext, unsigned long fQOP, PSecBufferDesc pMessage, unsigned long MessageSeqNo) { + // Create function pointer instance + encryptMessage_fn pfn_encryptMessage = NULL; + + // Return error if library not loaded + if(_sspi_security_dll == NULL) return -1; + + // Map function to library method + pfn_encryptMessage = (encryptMessage_fn)GetProcAddress(_sspi_security_dll, "EncryptMessage"); + // Check if the we managed to map function pointer + if(!pfn_encryptMessage) { + printf("GetProcAddress failed.\n"); + return -2; + } + + // Call the function + return (*pfn_encryptMessage)(phContext, fQOP, pMessage, MessageSeqNo); +} + +/** + * Acquire Credentials + */ +SECURITY_STATUS SEC_ENTRY _sspi_AcquireCredentialsHandle( + LPSTR pszPrincipal, LPSTR pszPackage, unsigned long fCredentialUse, + void * pvLogonId, void * pAuthData, SEC_GET_KEY_FN pGetKeyFn, void * pvGetKeyArgument, + PCredHandle phCredential, PTimeStamp ptsExpiry +) { + SECURITY_STATUS status; + // Create function pointer instance + acquireCredentialsHandle_fn pfn_acquireCredentialsHandle = NULL; + + // Return error if library not loaded + if(_sspi_security_dll == NULL) return -1; + + // Map function + #ifdef _UNICODE + pfn_acquireCredentialsHandle = (acquireCredentialsHandle_fn)GetProcAddress(_sspi_security_dll, "AcquireCredentialsHandleW"); + #else + pfn_acquireCredentialsHandle = (acquireCredentialsHandle_fn)GetProcAddress(_sspi_security_dll, "AcquireCredentialsHandleA"); + #endif + + // Check if the we managed to map function pointer + if(!pfn_acquireCredentialsHandle) { + printf("GetProcAddress failed.\n"); + return -2; + } + + // Status + status = (*pfn_acquireCredentialsHandle)(pszPrincipal, pszPackage, fCredentialUse, + pvLogonId, pAuthData, pGetKeyFn, pvGetKeyArgument, phCredential, ptsExpiry + ); + + // Call the function + return status; +} + +/** + * Delete Security Context + */ +SECURITY_STATUS SEC_ENTRY _sspi_DeleteSecurityContext(PCtxtHandle phContext) { + // Create function pointer instance + deleteSecurityContext_fn pfn_deleteSecurityContext = NULL; + + // Return error if library not loaded + if(_sspi_security_dll == NULL) return -1; + // Map function + pfn_deleteSecurityContext = (deleteSecurityContext_fn)GetProcAddress(_sspi_security_dll, "DeleteSecurityContext"); + + // Check if the we managed to map function pointer + if(!pfn_deleteSecurityContext) { + printf("GetProcAddress failed.\n"); + return -2; + } + + // Call the function + return (*pfn_deleteSecurityContext)(phContext); +} + +/** + * Decrypt Message + */ +SECURITY_STATUS SEC_ENTRY _sspi_DecryptMessage(PCtxtHandle phContext, PSecBufferDesc pMessage, unsigned long MessageSeqNo, unsigned long pfQOP) { + // Create function pointer instance + decryptMessage_fn pfn_decryptMessage = NULL; + + // Return error if library not loaded + if(_sspi_security_dll == NULL) return -1; + // Map function + pfn_decryptMessage = (decryptMessage_fn)GetProcAddress(_sspi_security_dll, "DecryptMessage"); + + // Check if the we managed to map function pointer + if(!pfn_decryptMessage) { + printf("GetProcAddress failed.\n"); + return -2; + } + + // Call the function + return (*pfn_decryptMessage)(phContext, pMessage, MessageSeqNo, pfQOP); +} + +/** + * Initialize Security Context + */ +SECURITY_STATUS SEC_ENTRY _sspi_initializeSecurityContext( + PCredHandle phCredential, PCtxtHandle phContext, + LPSTR pszTargetName, unsigned long fContextReq, + unsigned long Reserved1, unsigned long TargetDataRep, + PSecBufferDesc pInput, unsigned long Reserved2, + PCtxtHandle phNewContext, PSecBufferDesc pOutput, + unsigned long * pfContextAttr, PTimeStamp ptsExpiry +) { + SECURITY_STATUS status; + // Create function pointer instance + initializeSecurityContext_fn pfn_initializeSecurityContext = NULL; + + // Return error if library not loaded + if(_sspi_security_dll == NULL) return -1; + + // Map function + #ifdef _UNICODE + pfn_initializeSecurityContext = (initializeSecurityContext_fn)GetProcAddress(_sspi_security_dll, "InitializeSecurityContextW"); + #else + pfn_initializeSecurityContext = (initializeSecurityContext_fn)GetProcAddress(_sspi_security_dll, "InitializeSecurityContextA"); + #endif + + // Check if the we managed to map function pointer + if(!pfn_initializeSecurityContext) { + printf("GetProcAddress failed.\n"); + return -2; + } + + // Execute intialize context + status = (*pfn_initializeSecurityContext)( + phCredential, phContext, pszTargetName, fContextReq, + Reserved1, TargetDataRep, pInput, Reserved2, + phNewContext, pOutput, pfContextAttr, ptsExpiry + ); + + // Call the function + return status; +} +/** + * Query Context Attributes + */ +SECURITY_STATUS SEC_ENTRY _sspi_QueryContextAttributes( + PCtxtHandle phContext, unsigned long ulAttribute, void * pBuffer +) { + // Create function pointer instance + queryContextAttributes_fn pfn_queryContextAttributes = NULL; + + // Return error if library not loaded + if(_sspi_security_dll == NULL) return -1; + + #ifdef _UNICODE + pfn_queryContextAttributes = (queryContextAttributes_fn)GetProcAddress(_sspi_security_dll, "QueryContextAttributesW"); + #else + pfn_queryContextAttributes = (queryContextAttributes_fn)GetProcAddress(_sspi_security_dll, "QueryContextAttributesA"); + #endif + + // Check if the we managed to map function pointer + if(!pfn_queryContextAttributes) { + printf("GetProcAddress failed.\n"); + return -2; + } + + // Call the function + return (*pfn_queryContextAttributes)( + phContext, ulAttribute, pBuffer + ); +} + +/** + * InitSecurityInterface + */ +PSecurityFunctionTable _ssip_InitSecurityInterface() { + INIT_SECURITY_INTERFACE InitSecurityInterface; + PSecurityFunctionTable pSecurityInterface = NULL; + + // Return error if library not loaded + if(_sspi_security_dll == NULL) return NULL; + + #ifdef _UNICODE + // Get the address of the InitSecurityInterface function. + InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress ( + _sspi_secur32_dll, + TEXT("InitSecurityInterfaceW")); + #else + // Get the address of the InitSecurityInterface function. + InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress ( + _sspi_secur32_dll, + TEXT("InitSecurityInterfaceA")); + #endif + + if(!InitSecurityInterface) { + printf (TEXT("Failed in getting the function address, Error: %x"), GetLastError ()); + return NULL; + } + + // Use InitSecurityInterface to get the function table. + pSecurityInterface = (*InitSecurityInterface)(); + + if(!pSecurityInterface) { + printf (TEXT("Failed in getting the function table, Error: %x"), GetLastError ()); + return NULL; + } + + return pSecurityInterface; +} + +/** + * Load security.dll dynamically + */ +int load_library() { + DWORD err; + // Load the library + _sspi_security_dll = LoadLibrary("security.dll"); + + // Check if the library loaded + if(_sspi_security_dll == NULL) { + err = GetLastError(); + return err; + } + + // Load the library + _sspi_secur32_dll = LoadLibrary("secur32.dll"); + + // Check if the library loaded + if(_sspi_secur32_dll == NULL) { + err = GetLastError(); + return err; + } + + return 0; +} \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/kerberos_sspi.h b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/kerberos_sspi.h new file mode 100644 index 0000000..a3008dc --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/kerberos_sspi.h @@ -0,0 +1,106 @@ +#ifndef SSPI_C_H +#define SSPI_C_H + +#define SECURITY_WIN32 1 + +#include +#include + +/** + * Encrypt A Message + */ +SECURITY_STATUS SEC_ENTRY _sspi_EncryptMessage(PCtxtHandle phContext, unsigned long fQOP, PSecBufferDesc pMessage, unsigned long MessageSeqNo); + +typedef DWORD (WINAPI *encryptMessage_fn)(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo); + +/** + * Acquire Credentials + */ +SECURITY_STATUS SEC_ENTRY _sspi_AcquireCredentialsHandle( + LPSTR pszPrincipal, // Name of principal + LPSTR pszPackage, // Name of package + unsigned long fCredentialUse, // Flags indicating use + void * pvLogonId, // Pointer to logon ID + void * pAuthData, // Package specific data + SEC_GET_KEY_FN pGetKeyFn, // Pointer to GetKey() func + void * pvGetKeyArgument, // Value to pass to GetKey() + PCredHandle phCredential, // (out) Cred Handle + PTimeStamp ptsExpiry // (out) Lifetime (optional) +); + +typedef DWORD (WINAPI *acquireCredentialsHandle_fn)( + LPSTR pszPrincipal, LPSTR pszPackage, unsigned long fCredentialUse, + void * pvLogonId, void * pAuthData, SEC_GET_KEY_FN pGetKeyFn, void * pvGetKeyArgument, + PCredHandle phCredential, PTimeStamp ptsExpiry + ); + +/** + * Delete Security Context + */ +SECURITY_STATUS SEC_ENTRY _sspi_DeleteSecurityContext( + PCtxtHandle phContext // Context to delete +); + +typedef DWORD (WINAPI *deleteSecurityContext_fn)(PCtxtHandle phContext); + +/** + * Decrypt Message + */ +SECURITY_STATUS SEC_ENTRY _sspi_DecryptMessage( + PCtxtHandle phContext, + PSecBufferDesc pMessage, + unsigned long MessageSeqNo, + unsigned long pfQOP +); + +typedef DWORD (WINAPI *decryptMessage_fn)( + PCtxtHandle phContext, PSecBufferDesc pMessage, unsigned long MessageSeqNo, unsigned long pfQOP); + +/** + * Initialize Security Context + */ +SECURITY_STATUS SEC_ENTRY _sspi_initializeSecurityContext( + PCredHandle phCredential, // Cred to base context + PCtxtHandle phContext, // Existing context (OPT) + LPSTR pszTargetName, // Name of target + unsigned long fContextReq, // Context Requirements + unsigned long Reserved1, // Reserved, MBZ + unsigned long TargetDataRep, // Data rep of target + PSecBufferDesc pInput, // Input Buffers + unsigned long Reserved2, // Reserved, MBZ + PCtxtHandle phNewContext, // (out) New Context handle + PSecBufferDesc pOutput, // (inout) Output Buffers + unsigned long * pfContextAttr, // (out) Context attrs + PTimeStamp ptsExpiry // (out) Life span (OPT) +); + +typedef DWORD (WINAPI *initializeSecurityContext_fn)( + PCredHandle phCredential, PCtxtHandle phContext, LPSTR pszTargetName, unsigned long fContextReq, + unsigned long Reserved1, unsigned long TargetDataRep, PSecBufferDesc pInput, unsigned long Reserved2, + PCtxtHandle phNewContext, PSecBufferDesc pOutput, unsigned long * pfContextAttr, PTimeStamp ptsExpiry); + +/** + * Query Context Attributes + */ +SECURITY_STATUS SEC_ENTRY _sspi_QueryContextAttributes( + PCtxtHandle phContext, // Context to query + unsigned long ulAttribute, // Attribute to query + void * pBuffer // Buffer for attributes +); + +typedef DWORD (WINAPI *queryContextAttributes_fn)( + PCtxtHandle phContext, unsigned long ulAttribute, void * pBuffer); + +/** + * InitSecurityInterface + */ +PSecurityFunctionTable _ssip_InitSecurityInterface(); + +typedef DWORD (WINAPI *initSecurityInterface_fn) (); + +/** + * Load security.dll dynamically + */ +int load_library(); + +#endif \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/worker.cc b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/worker.cc new file mode 100644 index 0000000..e7a472f --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/worker.cc @@ -0,0 +1,7 @@ +#include "worker.h" + +Worker::Worker() { +} + +Worker::~Worker() { +} \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/worker.h b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/worker.h new file mode 100644 index 0000000..f73a4a7 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/worker.h @@ -0,0 +1,37 @@ +#ifndef WORKER_H_ +#define WORKER_H_ + +#include +#include +#include + +using namespace node; +using namespace v8; + +class Worker { + public: + Worker(); + virtual ~Worker(); + + // libuv's request struct. + uv_work_t request; + // Callback + v8::Persistent callback; + // Parameters + void *parameters; + // Results + void *return_value; + // Did we raise an error + bool error; + // The error message + char *error_message; + // Error code if not message + int error_code; + // Any return code + int return_code; + // Method we are going to fire + void (*execute)(Worker *worker); + Handle (*mapper)(Worker *worker); +}; + +#endif // WORKER_H_ diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer.cc b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer.cc new file mode 100644 index 0000000..dd38b59 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer.cc @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "security_buffer.h" + +using namespace node; + +static Handle VException(const char *msg) { + HandleScope scope; + return ThrowException(Exception::Error(String::New(msg))); +}; + +Persistent SecurityBuffer::constructor_template; + +SecurityBuffer::SecurityBuffer(uint32_t security_type, size_t size) : ObjectWrap() { + this->size = size; + this->data = calloc(size, sizeof(char)); + this->security_type = security_type; + // Set up the data in the sec_buffer + this->sec_buffer.BufferType = security_type; + this->sec_buffer.cbBuffer = (unsigned long)size; + this->sec_buffer.pvBuffer = this->data; +} + +SecurityBuffer::SecurityBuffer(uint32_t security_type, size_t size, void *data) : ObjectWrap() { + this->size = size; + this->data = data; + this->security_type = security_type; + // Set up the data in the sec_buffer + this->sec_buffer.BufferType = security_type; + this->sec_buffer.cbBuffer = (unsigned long)size; + this->sec_buffer.pvBuffer = this->data; +} + +SecurityBuffer::~SecurityBuffer() { + free(this->data); +} + +Handle SecurityBuffer::New(const Arguments &args) { + HandleScope scope; + SecurityBuffer *security_obj; + + if(args.Length() != 2) + return VException("Two parameters needed integer buffer type and [32 bit integer/Buffer] required"); + + if(!args[0]->IsInt32()) + return VException("Two parameters needed integer buffer type and [32 bit integer/Buffer] required"); + + if(!args[1]->IsInt32() && !Buffer::HasInstance(args[1])) + return VException("Two parameters needed integer buffer type and [32 bit integer/Buffer] required"); + + // Unpack buffer type + uint32_t buffer_type = args[0]->ToUint32()->Value(); + + // If we have an integer + if(args[1]->IsInt32()) { + security_obj = new SecurityBuffer(buffer_type, args[1]->ToUint32()->Value()); + } else { + // Get the length of the Buffer + size_t length = Buffer::Length(args[1]->ToObject()); + // Allocate space for the internal void data pointer + void *data = calloc(length, sizeof(char)); + // Write the data to out of V8 heap space + memcpy(data, Buffer::Data(args[1]->ToObject()), length); + // Create new SecurityBuffer + security_obj = new SecurityBuffer(buffer_type, length, data); + } + + // Wrap it + security_obj->Wrap(args.This()); + // Return the object + return args.This(); +} + +Handle SecurityBuffer::ToBuffer(const Arguments &args) { + HandleScope scope; + + // Unpack the Security Buffer object + SecurityBuffer *security_obj = ObjectWrap::Unwrap(args.This()); + // Create a Buffer + Buffer *buffer = Buffer::New((char *)security_obj->data, (size_t)security_obj->size); + + // Return the buffer + return scope.Close(buffer->handle_); +} + +void SecurityBuffer::Initialize(Handle target) { + // Grab the scope of the call from Node + HandleScope scope; + // Define a new function template + Local t = FunctionTemplate::New(New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("SecurityBuffer")); + + // Set up method for the Kerberos instance + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toBuffer", ToBuffer); + + // Set up class + target->Set(String::NewSymbol("SecurityBuffer"), constructor_template->GetFunction()); +} diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer.h b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer.h new file mode 100644 index 0000000..d6a5675 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer.h @@ -0,0 +1,46 @@ +#ifndef SECURITY_BUFFER_H +#define SECURITY_BUFFER_H + +#include +#include +#include + +#define SECURITY_WIN32 1 + +#include +#include + +using namespace v8; +using namespace node; + +class SecurityBuffer : public ObjectWrap { + public: + SecurityBuffer(uint32_t security_type, size_t size); + SecurityBuffer(uint32_t security_type, size_t size, void *data); + ~SecurityBuffer(); + + // Internal values + void *data; + size_t size; + uint32_t security_type; + SecBuffer sec_buffer; + + // Has instance check + static inline bool HasInstance(Handle val) { + if (!val->IsObject()) return false; + Local obj = val->ToObject(); + return constructor_template->HasInstance(obj); + }; + + // Functions available from V8 + static void Initialize(Handle target); + static Handle ToBuffer(const Arguments &args); + + // Constructor used for creating new Long objects from C++ + static Persistent constructor_template; + + private: + static Handle New(const Arguments &args); +}; + +#endif \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer.js b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer.js new file mode 100644 index 0000000..4996163 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer.js @@ -0,0 +1,12 @@ +var SecurityBufferNative = require('../../../build/Release/kerberos').SecurityBuffer; + +// Add some attributes +SecurityBufferNative.VERSION = 0; +SecurityBufferNative.EMPTY = 0; +SecurityBufferNative.DATA = 1; +SecurityBufferNative.TOKEN = 2; +SecurityBufferNative.PADDING = 9; +SecurityBufferNative.STREAM = 10; + +// Export the modified class +exports.SecurityBuffer = SecurityBufferNative; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer_descriptor.cc b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer_descriptor.cc new file mode 100644 index 0000000..560ef50 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer_descriptor.cc @@ -0,0 +1,177 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SECURITY_WIN32 1 + +#include "security_buffer_descriptor.h" +#include "security_buffer.h" + +static Handle VException(const char *msg) { + HandleScope scope; + return ThrowException(Exception::Error(String::New(msg))); +}; + +Persistent SecurityBufferDescriptor::constructor_template; + +SecurityBufferDescriptor::SecurityBufferDescriptor() : ObjectWrap() { +} + +SecurityBufferDescriptor::SecurityBufferDescriptor(Persistent arrayObject) : ObjectWrap() { + SecurityBuffer *security_obj = NULL; + // Safe reference to array + this->arrayObject = arrayObject; + + // Unpack the array and ensure we have a valid descriptor + this->secBufferDesc.cBuffers = arrayObject->Length(); + this->secBufferDesc.ulVersion = SECBUFFER_VERSION; + + if(arrayObject->Length() == 1) { + // Unwrap the buffer + security_obj = ObjectWrap::Unwrap(arrayObject->Get(0)->ToObject()); + // Assign the buffer + this->secBufferDesc.pBuffers = &security_obj->sec_buffer; + } else { + this->secBufferDesc.pBuffers = new SecBuffer[arrayObject->Length()]; + this->secBufferDesc.cBuffers = arrayObject->Length(); + + // Assign the buffers + for(uint32_t i = 0; i < arrayObject->Length(); i++) { + security_obj = ObjectWrap::Unwrap(arrayObject->Get(i)->ToObject()); + this->secBufferDesc.pBuffers[i].BufferType = security_obj->sec_buffer.BufferType; + this->secBufferDesc.pBuffers[i].pvBuffer = security_obj->sec_buffer.pvBuffer; + this->secBufferDesc.pBuffers[i].cbBuffer = security_obj->sec_buffer.cbBuffer; + } + } +} + +SecurityBufferDescriptor::~SecurityBufferDescriptor() { +} + +size_t SecurityBufferDescriptor::bufferSize() { + SecurityBuffer *security_obj = NULL; + + if(this->secBufferDesc.cBuffers == 1) { + security_obj = ObjectWrap::Unwrap(arrayObject->Get(0)->ToObject()); + return security_obj->size; + } else { + int bytesToAllocate = 0; + + for(unsigned int i = 0; i < this->secBufferDesc.cBuffers; i++) { + bytesToAllocate += this->secBufferDesc.pBuffers[i].cbBuffer; + } + + // Return total size + return bytesToAllocate; + } +} + +char *SecurityBufferDescriptor::toBuffer() { + SecurityBuffer *security_obj = NULL; + char *data = NULL; + + if(this->secBufferDesc.cBuffers == 1) { + security_obj = ObjectWrap::Unwrap(arrayObject->Get(0)->ToObject()); + data = (char *)malloc(security_obj->size * sizeof(char)); + memcpy(data, security_obj->data, security_obj->size); + } else { + size_t bytesToAllocate = this->bufferSize(); + char *data = (char *)calloc(bytesToAllocate, sizeof(char)); + int offset = 0; + + for(unsigned int i = 0; i < this->secBufferDesc.cBuffers; i++) { + memcpy((data + offset), this->secBufferDesc.pBuffers[i].pvBuffer, this->secBufferDesc.pBuffers[i].cbBuffer); + offset +=this->secBufferDesc.pBuffers[i].cbBuffer; + } + + // Return the data + return data; + } + + return data; +} + +Handle SecurityBufferDescriptor::New(const Arguments &args) { + HandleScope scope; + SecurityBufferDescriptor *security_obj; + Persistent arrayObject; + + if(args.Length() != 1) + return VException("There must be 1 argument passed in where the first argument is a [int32 or an Array of SecurityBuffers]"); + + if(!args[0]->IsInt32() && !args[0]->IsArray()) + return VException("There must be 1 argument passed in where the first argument is a [int32 or an Array of SecurityBuffers]"); + + if(args[0]->IsArray()) { + Handle array = Handle::Cast(args[0]); + // Iterate over all items and ensure we the right type + for(uint32_t i = 0; i < array->Length(); i++) { + if(!SecurityBuffer::HasInstance(array->Get(i))) { + return VException("There must be 1 argument passed in where the first argument is a [int32 or an Array of SecurityBuffers]"); + } + } + } + + // We have a single integer + if(args[0]->IsInt32()) { + // Create new SecurityBuffer instance + Local argv[] = {Int32::New(0x02), args[0]}; + Handle security_buffer = SecurityBuffer::constructor_template->GetFunction()->NewInstance(2, argv); + // Create a new array + Local array = Array::New(1); + // Set the first value + array->Set(0, security_buffer); + // Create persistent handle + arrayObject = Persistent::New(array); + // Create descriptor + security_obj = new SecurityBufferDescriptor(arrayObject); + } else { + arrayObject = Persistent::New(Handle::Cast(args[0])); + security_obj = new SecurityBufferDescriptor(arrayObject); + } + + // Wrap it + security_obj->Wrap(args.This()); + // Return the object + return args.This(); +} + +Handle SecurityBufferDescriptor::ToBuffer(const Arguments &args) { + HandleScope scope; + + // Unpack the Security Buffer object + SecurityBufferDescriptor *security_obj = ObjectWrap::Unwrap(args.This()); + + // Get the buffer + char *buffer_data = security_obj->toBuffer(); + size_t buffer_size = security_obj->bufferSize(); + + // Create a Buffer + Buffer *buffer = Buffer::New(buffer_data, buffer_size); + + // Return the buffer + return scope.Close(buffer->handle_); +} + +void SecurityBufferDescriptor::Initialize(Handle target) { + // Grab the scope of the call from Node + HandleScope scope; + // Define a new function template + Local t = FunctionTemplate::New(New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("SecurityBufferDescriptor")); + + // Set up method for the Kerberos instance + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toBuffer", ToBuffer); + + target->Set(String::NewSymbol("SecurityBufferDescriptor"), constructor_template->GetFunction()); +} diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer_descriptor.h b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer_descriptor.h new file mode 100644 index 0000000..8588632 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer_descriptor.h @@ -0,0 +1,44 @@ +#ifndef SECURITY_BUFFER_DESCRIPTOR_H +#define SECURITY_BUFFER_DESCRIPTOR_H + +#include +#include +#include + +#include +#include + +using namespace v8; +using namespace node; + +class SecurityBufferDescriptor : public ObjectWrap { + public: + Persistent arrayObject; + SecBufferDesc secBufferDesc; + + SecurityBufferDescriptor(); + SecurityBufferDescriptor(Persistent arrayObject); + ~SecurityBufferDescriptor(); + + // Has instance check + static inline bool HasInstance(Handle val) { + if (!val->IsObject()) return false; + Local obj = val->ToObject(); + return constructor_template->HasInstance(obj); + }; + + char *toBuffer(); + size_t bufferSize(); + + // Functions available from V8 + static void Initialize(Handle target); + static Handle ToBuffer(const Arguments &args); + + // Constructor used for creating new Long objects from C++ + static Persistent constructor_template; + + private: + static Handle New(const Arguments &args); +}; + +#endif \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer_descriptor.js b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer_descriptor.js new file mode 100644 index 0000000..9421392 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_buffer_descriptor.js @@ -0,0 +1,3 @@ +var SecurityBufferDescriptorNative = require('../../../build/Release/kerberos').SecurityBufferDescriptor; +// Export the modified class +exports.SecurityBufferDescriptor = SecurityBufferDescriptorNative; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_context.cc b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_context.cc new file mode 100644 index 0000000..8c3691a --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_context.cc @@ -0,0 +1,1211 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "security_context.h" +#include "security_buffer_descriptor.h" + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0])) +#endif + +static LPSTR DisplaySECError(DWORD ErrCode); + +static Handle VException(const char *msg) { + HandleScope scope; + return ThrowException(Exception::Error(String::New(msg))); +}; + +static Handle VExceptionErrNo(const char *msg, const int errorNumber) { + HandleScope scope; + + Local err = Exception::Error(String::New(msg)); + Local obj = err->ToObject(); + obj->Set(NODE_PSYMBOL("code"), Int32::New(errorNumber)); + return ThrowException(err); +}; + +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// UV Lib callbacks +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +static void Process(uv_work_t* work_req) { + // Grab the worker + Worker *worker = static_cast(work_req->data); + // Execute the worker code + worker->execute(worker); +} + +static void After(uv_work_t* work_req) { + // Grab the scope of the call from Node + v8::HandleScope scope; + + // Get the worker reference + Worker *worker = static_cast(work_req->data); + + // If we have an error + if(worker->error) { + v8::Local err = v8::Exception::Error(v8::String::New(worker->error_message)); + Local obj = err->ToObject(); + obj->Set(NODE_PSYMBOL("code"), Int32::New(worker->error_code)); + v8::Local args[2] = { err, v8::Local::New(v8::Null()) }; + // Execute the error + v8::TryCatch try_catch; + // Call the callback + worker->callback->Call(v8::Context::GetCurrent()->Global(), ARRAY_SIZE(args), args); + // If we have an exception handle it as a fatalexception + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } else { + // // Map the data + v8::Handle result = worker->mapper(worker); + // Set up the callback with a null first + v8::Handle args[2] = { v8::Local::New(v8::Null()), result}; + // Wrap the callback function call in a TryCatch so that we can call + // node's FatalException afterwards. This makes it possible to catch + // the exception from JavaScript land using the + // process.on('uncaughtException') event. + v8::TryCatch try_catch; + // Call the callback + worker->callback->Call(v8::Context::GetCurrent()->Global(), ARRAY_SIZE(args), args); + // If we have an exception handle it as a fatalexception + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } + + // Clean up the memory + worker->callback.Dispose(); + free(worker->parameters); + delete worker; +} + +Persistent SecurityContext::constructor_template; + +SecurityContext::SecurityContext() : ObjectWrap() { +} + +SecurityContext::~SecurityContext() { + if(this->hasContext) { + _sspi_DeleteSecurityContext(&this->m_Context); + } +} + +Handle SecurityContext::New(const Arguments &args) { + HandleScope scope; + + PSecurityFunctionTable pSecurityInterface = NULL; + DWORD dwNumOfPkgs; + SECURITY_STATUS status; + + // Create code object + SecurityContext *security_obj = new SecurityContext(); + // Get security table interface + pSecurityInterface = _ssip_InitSecurityInterface(); + // Call the security interface + status = (*pSecurityInterface->EnumerateSecurityPackages)( + &dwNumOfPkgs, + &security_obj->m_PkgInfo); + if(status != SEC_E_OK) { + printf(TEXT("Failed in retrieving security packages, Error: %x"), GetLastError()); + return VException("Failed in retrieving security packages"); + } + + // Wrap it + security_obj->Wrap(args.This()); + // Return the object + return args.This(); +} + +Handle SecurityContext::InitializeContextSync(const Arguments &args) { + HandleScope scope; + char *service_principal_name_str = NULL, *input_str = NULL, *decoded_input_str = NULL; + BYTE *out_bound_data_str = NULL; + int decoded_input_str_length = NULL; + // Store reference to security credentials + SecurityCredentials *security_credentials = NULL; + // Status of operation + SECURITY_STATUS status; + + // We need 3 parameters + if(args.Length() != 3) + return VException("Initialize must be called with either [credential:SecurityCredential, servicePrincipalName:string, input:string]"); + + // First parameter must be an instance of SecurityCredentials + if(!SecurityCredentials::HasInstance(args[0])) + return VException("First parameter for Initialize must be an instance of SecurityCredentials"); + + // Second parameter must be a string + if(!args[1]->IsString()) + return VException("Second parameter for Initialize must be a string"); + + // Third parameter must be a base64 encoded string + if(!args[2]->IsString()) + return VException("Second parameter for Initialize must be a string"); + + // Let's unpack the values + Local service_principal_name = args[1]->ToString(); + service_principal_name_str = (char *)calloc(service_principal_name->Utf8Length() + 1, sizeof(char)); + service_principal_name->WriteUtf8(service_principal_name_str); + + // Unpack the user name + Local input = args[2]->ToString(); + + if(input->Utf8Length() > 0) { + input_str = (char *)calloc(input->Utf8Length() + 1, sizeof(char)); + input->WriteUtf8(input_str); + + // Now let's get the base64 decoded string + decoded_input_str = (char *)base64_decode(input_str, &decoded_input_str_length); + } + + // Unpack the Security credentials + security_credentials = ObjectWrap::Unwrap(args[0]->ToObject()); + + // Create Security context instance + Local security_context_value = constructor_template->GetFunction()->NewInstance(); + // Unwrap the security context + SecurityContext *security_context = ObjectWrap::Unwrap(security_context_value); + // Add a reference to the security_credentials + security_context->security_credentials = security_credentials; + + // Structures used for c calls + SecBufferDesc ibd, obd; + SecBuffer ib, ob; + + // + // Prepare data structure for returned data from SSPI + ob.BufferType = SECBUFFER_TOKEN; + ob.cbBuffer = security_context->m_PkgInfo->cbMaxToken; + // Allocate space for return data + out_bound_data_str = new BYTE[ob.cbBuffer + sizeof(DWORD)]; + ob.pvBuffer = out_bound_data_str; + // prepare buffer description + obd.cBuffers = 1; + obd.ulVersion = SECBUFFER_VERSION; + obd.pBuffers = &ob; + + // + // Prepare the data we are passing to the SSPI method + if(input->Utf8Length() > 0) { + ib.BufferType = SECBUFFER_TOKEN; + ib.cbBuffer = decoded_input_str_length; + ib.pvBuffer = decoded_input_str; + // prepare buffer description + ibd.cBuffers = 1; + ibd.ulVersion = SECBUFFER_VERSION; + ibd.pBuffers = &ib; + } + + // Perform initialization step + status = _sspi_initializeSecurityContext( + &security_credentials->m_Credentials + , NULL + , const_cast(service_principal_name_str) + , 0x02 // MUTUAL + , 0 + , 0 // Network + , input->Utf8Length() > 0 ? &ibd : NULL + , 0 + , &security_context->m_Context + , &obd + , &security_context->CtxtAttr + , &security_context->Expiration + ); + + // If we have a ok or continue let's prepare the result + if(status == SEC_E_OK + || status == SEC_I_COMPLETE_NEEDED + || status == SEC_I_CONTINUE_NEEDED + || status == SEC_I_COMPLETE_AND_CONTINUE + ) { + security_context->hasContext = true; + security_context->payload = base64_encode((const unsigned char *)ob.pvBuffer, ob.cbBuffer); + } else { + LPSTR err_message = DisplaySECError(status); + + if(err_message != NULL) { + return VExceptionErrNo(err_message, status); + } else { + return VExceptionErrNo("Unknown error", status); + } + } + + // Return security context + return scope.Close(security_context_value); +} + +// +// Async InitializeContext +// +typedef struct SecurityContextStaticInitializeCall { + char *service_principal_name_str; + char *decoded_input_str; + int decoded_input_str_length; + SecurityContext *context; +} SecurityContextStaticInitializeCall; + +static void _initializeContext(Worker *worker) { + // Status of operation + SECURITY_STATUS status; + BYTE *out_bound_data_str = NULL; + SecurityContextStaticInitializeCall *call = (SecurityContextStaticInitializeCall *)worker->parameters; + + // Structures used for c calls + SecBufferDesc ibd, obd; + SecBuffer ib, ob; + + // + // Prepare data structure for returned data from SSPI + ob.BufferType = SECBUFFER_TOKEN; + ob.cbBuffer = call->context->m_PkgInfo->cbMaxToken; + // Allocate space for return data + out_bound_data_str = new BYTE[ob.cbBuffer + sizeof(DWORD)]; + ob.pvBuffer = out_bound_data_str; + // prepare buffer description + obd.cBuffers = 1; + obd.ulVersion = SECBUFFER_VERSION; + obd.pBuffers = &ob; + + // + // Prepare the data we are passing to the SSPI method + if(call->decoded_input_str_length > 0) { + ib.BufferType = SECBUFFER_TOKEN; + ib.cbBuffer = call->decoded_input_str_length; + ib.pvBuffer = call->decoded_input_str; + // prepare buffer description + ibd.cBuffers = 1; + ibd.ulVersion = SECBUFFER_VERSION; + ibd.pBuffers = &ib; + } + + // Perform initialization step + status = _sspi_initializeSecurityContext( + &call->context->security_credentials->m_Credentials + , NULL + , const_cast(call->service_principal_name_str) + , 0x02 // MUTUAL + , 0 + , 0 // Network + , call->decoded_input_str_length > 0 ? &ibd : NULL + , 0 + , &call->context->m_Context + , &obd + , &call->context->CtxtAttr + , &call->context->Expiration + ); + + // If we have a ok or continue let's prepare the result + if(status == SEC_E_OK + || status == SEC_I_COMPLETE_NEEDED + || status == SEC_I_CONTINUE_NEEDED + || status == SEC_I_COMPLETE_AND_CONTINUE + ) { + call->context->hasContext = true; + call->context->payload = base64_encode((const unsigned char *)ob.pvBuffer, ob.cbBuffer); + + // Set the context + worker->return_code = status; + worker->return_value = call->context; + } else { + worker->error = TRUE; + worker->error_code = status; + worker->error_message = DisplaySECError(status); + } + + // Clean up data + if(call->decoded_input_str != NULL) free(call->decoded_input_str); + if(call->service_principal_name_str != NULL) free(call->service_principal_name_str); +} + +static Handle _map_initializeContext(Worker *worker) { + HandleScope scope; + + // Unwrap the security context + SecurityContext *context = (SecurityContext *)worker->return_value; + // Return the value + return scope.Close(context->handle_); +} + +Handle SecurityContext::InitializeContext(const Arguments &args) { + HandleScope scope; + char *service_principal_name_str = NULL, *input_str = NULL, *decoded_input_str = NULL; + int decoded_input_str_length = NULL; + // Store reference to security credentials + SecurityCredentials *security_credentials = NULL; + + // We need 3 parameters + if(args.Length() != 4) + return VException("Initialize must be called with [credential:SecurityCredential, servicePrincipalName:string, input:string, callback:function]"); + + // First parameter must be an instance of SecurityCredentials + if(!SecurityCredentials::HasInstance(args[0])) + return VException("First parameter for Initialize must be an instance of SecurityCredentials"); + + // Second parameter must be a string + if(!args[1]->IsString()) + return VException("Second parameter for Initialize must be a string"); + + // Third parameter must be a base64 encoded string + if(!args[2]->IsString()) + return VException("Second parameter for Initialize must be a string"); + + // Third parameter must be a callback + if(!args[3]->IsFunction()) + return VException("Third parameter for Initialize must be a callback function"); + + // Let's unpack the values + Local service_principal_name = args[1]->ToString(); + service_principal_name_str = (char *)calloc(service_principal_name->Utf8Length() + 1, sizeof(char)); + service_principal_name->WriteUtf8(service_principal_name_str); + + // Unpack the user name + Local input = args[2]->ToString(); + + if(input->Utf8Length() > 0) { + input_str = (char *)calloc(input->Utf8Length() + 1, sizeof(char)); + input->WriteUtf8(input_str); + + // Now let's get the base64 decoded string + decoded_input_str = (char *)base64_decode(input_str, &decoded_input_str_length); + // Free original allocation + free(input_str); + } + + // Unpack the Security credentials + security_credentials = ObjectWrap::Unwrap(args[0]->ToObject()); + // Create Security context instance + Local security_context_value = constructor_template->GetFunction()->NewInstance(); + // Unwrap the security context + SecurityContext *security_context = ObjectWrap::Unwrap(security_context_value); + // Add a reference to the security_credentials + security_context->security_credentials = security_credentials; + + // Build the call function + SecurityContextStaticInitializeCall *call = (SecurityContextStaticInitializeCall *)calloc(1, sizeof(SecurityContextStaticInitializeCall)); + call->context = security_context; + call->decoded_input_str = decoded_input_str; + call->decoded_input_str_length = decoded_input_str_length; + call->service_principal_name_str = service_principal_name_str; + + // Callback + Local callback = Local::Cast(args[3]); + + // Let's allocate some space + Worker *worker = new Worker(); + worker->error = false; + worker->request.data = worker; + worker->callback = Persistent::New(callback); + worker->parameters = call; + worker->execute = _initializeContext; + worker->mapper = _map_initializeContext; + + // Schedule the worker with lib_uv + uv_queue_work(uv_default_loop(), &worker->request, Process, (uv_after_work_cb)After); + + // Return no value + return scope.Close(Undefined()); +} + +Handle SecurityContext::PayloadGetter(Local property, const AccessorInfo& info) { + HandleScope scope; + // Unpack the context object + SecurityContext *context = ObjectWrap::Unwrap(info.Holder()); + // Return the low bits + return scope.Close(String::New(context->payload)); +} + +Handle SecurityContext::HasContextGetter(Local property, const AccessorInfo& info) { + HandleScope scope; + // Unpack the context object + SecurityContext *context = ObjectWrap::Unwrap(info.Holder()); + // Return the low bits + return scope.Close(Boolean::New(context->hasContext)); +} + +// +// Async InitializeContextStep +// +typedef struct SecurityContextStepStaticInitializeCall { + char *service_principal_name_str; + char *decoded_input_str; + int decoded_input_str_length; + SecurityContext *context; +} SecurityContextStepStaticInitializeCall; + +static void _initializeContextStep(Worker *worker) { + // Outbound data array + BYTE *out_bound_data_str = NULL; + // Status of operation + SECURITY_STATUS status; + // Unpack data + SecurityContextStepStaticInitializeCall *call = (SecurityContextStepStaticInitializeCall *)worker->parameters; + SecurityContext *context = call->context; + // Structures used for c calls + SecBufferDesc ibd, obd; + SecBuffer ib, ob; + + // + // Prepare data structure for returned data from SSPI + ob.BufferType = SECBUFFER_TOKEN; + ob.cbBuffer = context->m_PkgInfo->cbMaxToken; + // Allocate space for return data + out_bound_data_str = new BYTE[ob.cbBuffer + sizeof(DWORD)]; + ob.pvBuffer = out_bound_data_str; + // prepare buffer description + obd.cBuffers = 1; + obd.ulVersion = SECBUFFER_VERSION; + obd.pBuffers = &ob; + + // + // Prepare the data we are passing to the SSPI method + if(call->decoded_input_str_length > 0) { + ib.BufferType = SECBUFFER_TOKEN; + ib.cbBuffer = call->decoded_input_str_length; + ib.pvBuffer = call->decoded_input_str; + // prepare buffer description + ibd.cBuffers = 1; + ibd.ulVersion = SECBUFFER_VERSION; + ibd.pBuffers = &ib; + } + + // Perform initialization step + status = _sspi_initializeSecurityContext( + &context->security_credentials->m_Credentials + , context->hasContext == true ? &context->m_Context : NULL + , const_cast(call->service_principal_name_str) + , 0x02 // MUTUAL + , 0 + , 0 // Network + , call->decoded_input_str_length ? &ibd : NULL + , 0 + , &context->m_Context + , &obd + , &context->CtxtAttr + , &context->Expiration + ); + + // If we have a ok or continue let's prepare the result + if(status == SEC_E_OK + || status == SEC_I_COMPLETE_NEEDED + || status == SEC_I_CONTINUE_NEEDED + || status == SEC_I_COMPLETE_AND_CONTINUE + ) { + // Set the new payload + if(context->payload != NULL) free(context->payload); + context->payload = base64_encode((const unsigned char *)ob.pvBuffer, ob.cbBuffer); + worker->return_code = status; + worker->return_value = context; + } else { + worker->error = TRUE; + worker->error_code = status; + worker->error_message = DisplaySECError(status); + } + + // Clean up data + if(call->decoded_input_str != NULL) free(call->decoded_input_str); + if(call->service_principal_name_str != NULL) free(call->service_principal_name_str); +} + +static Handle _map_initializeContextStep(Worker *worker) { + HandleScope scope; + // Unwrap the security context + SecurityContext *context = (SecurityContext *)worker->return_value; + // Return the value + return scope.Close(context->handle_); +} + +Handle SecurityContext::InitalizeStep(const Arguments &args) { + HandleScope scope; + + char *service_principal_name_str = NULL, *input_str = NULL, *decoded_input_str = NULL; + int decoded_input_str_length = NULL; + + // We need 3 parameters + if(args.Length() != 3) + return VException("Initialize must be called with [servicePrincipalName:string, input:string, callback:function]"); + + // Second parameter must be a string + if(!args[0]->IsString()) + return VException("First parameter for Initialize must be a string"); + + // Third parameter must be a base64 encoded string + if(!args[1]->IsString()) + return VException("Second parameter for Initialize must be a string"); + + // Third parameter must be a base64 encoded string + if(!args[2]->IsFunction()) + return VException("Third parameter for Initialize must be a callback function"); + + // Let's unpack the values + Local service_principal_name = args[0]->ToString(); + service_principal_name_str = (char *)calloc(service_principal_name->Utf8Length() + 1, sizeof(char)); + service_principal_name->WriteUtf8(service_principal_name_str); + + // Unpack the user name + Local input = args[1]->ToString(); + + if(input->Utf8Length() > 0) { + input_str = (char *)calloc(input->Utf8Length() + 1, sizeof(char)); + input->WriteUtf8(input_str); + // Now let's get the base64 decoded string + decoded_input_str = (char *)base64_decode(input_str, &decoded_input_str_length); + // Free input string + free(input_str); + } + + // Unwrap the security context + SecurityContext *security_context = ObjectWrap::Unwrap(args.This()); + + // Create call structure + SecurityContextStepStaticInitializeCall *call = (SecurityContextStepStaticInitializeCall *)calloc(1, sizeof(SecurityContextStepStaticInitializeCall)); + call->context = security_context; + call->decoded_input_str = decoded_input_str; + call->decoded_input_str_length = decoded_input_str_length; + call->service_principal_name_str = service_principal_name_str; + + // Callback + Local callback = Local::Cast(args[2]); + + // Let's allocate some space + Worker *worker = new Worker(); + worker->error = false; + worker->request.data = worker; + worker->callback = Persistent::New(callback); + worker->parameters = call; + worker->execute = _initializeContextStep; + worker->mapper = _map_initializeContextStep; + + // Schedule the worker with lib_uv + uv_queue_work(uv_default_loop(), &worker->request, Process, (uv_after_work_cb)After); + + // Return undefined + return scope.Close(Undefined()); +} + +Handle SecurityContext::InitalizeStepSync(const Arguments &args) { + HandleScope scope; + + char *service_principal_name_str = NULL, *input_str = NULL, *decoded_input_str = NULL; + BYTE *out_bound_data_str = NULL; + int decoded_input_str_length = NULL; + // Status of operation + SECURITY_STATUS status; + + // We need 3 parameters + if(args.Length() != 2) + return VException("Initialize must be called with [servicePrincipalName:string, input:string]"); + + // Second parameter must be a string + if(!args[0]->IsString()) + return VException("First parameter for Initialize must be a string"); + + // Third parameter must be a base64 encoded string + if(!args[1]->IsString()) + return VException("Second parameter for Initialize must be a string"); + + // Let's unpack the values + Local service_principal_name = args[0]->ToString(); + service_principal_name_str = (char *)calloc(service_principal_name->Utf8Length() + 1, sizeof(char)); + service_principal_name->WriteUtf8(service_principal_name_str); + + // Unpack the user name + Local input = args[1]->ToString(); + + if(input->Utf8Length() > 0) { + input_str = (char *)calloc(input->Utf8Length() + 1, sizeof(char)); + input->WriteUtf8(input_str); + // Now let's get the base64 decoded string + decoded_input_str = (char *)base64_decode(input_str, &decoded_input_str_length); + } + + // Unpack the long object + SecurityContext *security_context = ObjectWrap::Unwrap(args.This()); + SecurityCredentials *security_credentials = security_context->security_credentials; + + // Structures used for c calls + SecBufferDesc ibd, obd; + SecBuffer ib, ob; + + // + // Prepare data structure for returned data from SSPI + ob.BufferType = SECBUFFER_TOKEN; + ob.cbBuffer = security_context->m_PkgInfo->cbMaxToken; + // Allocate space for return data + out_bound_data_str = new BYTE[ob.cbBuffer + sizeof(DWORD)]; + ob.pvBuffer = out_bound_data_str; + // prepare buffer description + obd.cBuffers = 1; + obd.ulVersion = SECBUFFER_VERSION; + obd.pBuffers = &ob; + + // + // Prepare the data we are passing to the SSPI method + if(input->Utf8Length() > 0) { + ib.BufferType = SECBUFFER_TOKEN; + ib.cbBuffer = decoded_input_str_length; + ib.pvBuffer = decoded_input_str; + // prepare buffer description + ibd.cBuffers = 1; + ibd.ulVersion = SECBUFFER_VERSION; + ibd.pBuffers = &ib; + } + + // Perform initialization step + status = _sspi_initializeSecurityContext( + &security_credentials->m_Credentials + , security_context->hasContext == true ? &security_context->m_Context : NULL + , const_cast(service_principal_name_str) + , 0x02 // MUTUAL + , 0 + , 0 // Network + , input->Utf8Length() > 0 ? &ibd : NULL + , 0 + , &security_context->m_Context + , &obd + , &security_context->CtxtAttr + , &security_context->Expiration + ); + + // If we have a ok or continue let's prepare the result + if(status == SEC_E_OK + || status == SEC_I_COMPLETE_NEEDED + || status == SEC_I_CONTINUE_NEEDED + || status == SEC_I_COMPLETE_AND_CONTINUE + ) { + // Set the new payload + if(security_context->payload != NULL) free(security_context->payload); + security_context->payload = base64_encode((const unsigned char *)ob.pvBuffer, ob.cbBuffer); + } else { + LPSTR err_message = DisplaySECError(status); + + if(err_message != NULL) { + return VExceptionErrNo(err_message, status); + } else { + return VExceptionErrNo("Unknown error", status); + } + } + + return scope.Close(Null()); +} + +// +// Async EncryptMessage +// +typedef struct SecurityContextEncryptMessageCall { + SecurityContext *context; + SecurityBufferDescriptor *descriptor; + unsigned long flags; +} SecurityContextEncryptMessageCall; + +static void _encryptMessage(Worker *worker) { + SECURITY_STATUS status; + // Unpack call + SecurityContextEncryptMessageCall *call = (SecurityContextEncryptMessageCall *)worker->parameters; + // Unpack the security context + SecurityContext *context = call->context; + SecurityBufferDescriptor *descriptor = call->descriptor; + + // Let's execute encryption + status = _sspi_EncryptMessage( + &context->m_Context + , call->flags + , &descriptor->secBufferDesc + , 0 + ); + + // We've got ok + if(status == SEC_E_OK) { + int bytesToAllocate = (int)descriptor->bufferSize(); + // Free up existing payload + if(context->payload != NULL) free(context->payload); + // Save the payload + context->payload = base64_encode((unsigned char *)descriptor->toBuffer(), bytesToAllocate); + // Set result + worker->return_code = status; + worker->return_value = context; + } else { + worker->error = TRUE; + worker->error_code = status; + worker->error_message = DisplaySECError(status); + } +} + +static Handle _map_encryptMessage(Worker *worker) { + HandleScope scope; + // Unwrap the security context + SecurityContext *context = (SecurityContext *)worker->return_value; + // Return the value + return scope.Close(context->handle_); +} + +Handle SecurityContext::EncryptMessage(const Arguments &args) { + HandleScope scope; + + if(args.Length() != 3) + return VException("EncryptMessage takes an instance of SecurityBufferDescriptor, an integer flag and a callback function"); + if(!SecurityBufferDescriptor::HasInstance(args[0])) + return VException("EncryptMessage takes an instance of SecurityBufferDescriptor, an integer flag and a callback function"); + if(!args[1]->IsUint32()) + return VException("EncryptMessage takes an instance of SecurityBufferDescriptor, an integer flag and a callback function"); + if(!args[2]->IsFunction()) + return VException("EncryptMessage takes an instance of SecurityBufferDescriptor, an integer flag and a callback function"); + + // Unpack the security context + SecurityContext *security_context = ObjectWrap::Unwrap(args.This()); + + // Unpack the descriptor + SecurityBufferDescriptor *descriptor = ObjectWrap::Unwrap(args[0]->ToObject()); + + // Create call structure + SecurityContextEncryptMessageCall *call = (SecurityContextEncryptMessageCall *)calloc(1, sizeof(SecurityContextEncryptMessageCall)); + call->context = security_context; + call->descriptor = descriptor; + call->flags = (unsigned long)args[1]->ToInteger()->Value(); + + // Callback + Local callback = Local::Cast(args[2]); + + // Let's allocate some space + Worker *worker = new Worker(); + worker->error = false; + worker->request.data = worker; + worker->callback = Persistent::New(callback); + worker->parameters = call; + worker->execute = _encryptMessage; + worker->mapper = _map_encryptMessage; + + // Schedule the worker with lib_uv + uv_queue_work(uv_default_loop(), &worker->request, Process, (uv_after_work_cb)After); + + // Return undefined + return scope.Close(Undefined()); +} + +Handle SecurityContext::EncryptMessageSync(const Arguments &args) { + HandleScope scope; + SECURITY_STATUS status; + + if(args.Length() != 2) + return VException("EncryptMessageSync takes an instance of SecurityBufferDescriptor and an integer flag"); + if(!SecurityBufferDescriptor::HasInstance(args[0])) + return VException("EncryptMessageSync takes an instance of SecurityBufferDescriptor and an integer flag"); + if(!args[1]->IsUint32()) + return VException("EncryptMessageSync takes an instance of SecurityBufferDescriptor and an integer flag"); + + // Unpack the security context + SecurityContext *security_context = ObjectWrap::Unwrap(args.This()); + + // Unpack the descriptor + SecurityBufferDescriptor *descriptor = ObjectWrap::Unwrap(args[0]->ToObject()); + + // Let's execute encryption + status = _sspi_EncryptMessage( + &security_context->m_Context + , (unsigned long)args[1]->ToInteger()->Value() + , &descriptor->secBufferDesc + , 0 + ); + + // We've got ok + if(status == SEC_E_OK) { + int bytesToAllocate = (int)descriptor->bufferSize(); + // Free up existing payload + if(security_context->payload != NULL) free(security_context->payload); + // Save the payload + security_context->payload = base64_encode((unsigned char *)descriptor->toBuffer(), bytesToAllocate); + } else { + LPSTR err_message = DisplaySECError(status); + + if(err_message != NULL) { + return VExceptionErrNo(err_message, status); + } else { + return VExceptionErrNo("Unknown error", status); + } + } + + return scope.Close(Null()); +} + +// +// Async DecryptMessage +// +typedef struct SecurityContextDecryptMessageCall { + SecurityContext *context; + SecurityBufferDescriptor *descriptor; +} SecurityContextDecryptMessageCall; + +static void _decryptMessage(Worker *worker) { + unsigned long quality = 0; + SECURITY_STATUS status; + + // Unpack parameters + SecurityContextDecryptMessageCall *call = (SecurityContextDecryptMessageCall *)worker->parameters; + SecurityContext *context = call->context; + SecurityBufferDescriptor *descriptor = call->descriptor; + + // Let's execute encryption + status = _sspi_DecryptMessage( + &context->m_Context + , &descriptor->secBufferDesc + , 0 + , (unsigned long)&quality + ); + + // We've got ok + if(status == SEC_E_OK) { + int bytesToAllocate = (int)descriptor->bufferSize(); + // Free up existing payload + if(context->payload != NULL) free(context->payload); + // Save the payload + context->payload = base64_encode((unsigned char *)descriptor->toBuffer(), bytesToAllocate); + // Set return values + worker->return_code = status; + worker->return_value = context; + } else { + worker->error = TRUE; + worker->error_code = status; + worker->error_message = DisplaySECError(status); + } +} + +static Handle _map_decryptMessage(Worker *worker) { + HandleScope scope; + // Unwrap the security context + SecurityContext *context = (SecurityContext *)worker->return_value; + // Return the value + return scope.Close(context->handle_); +} + +Handle SecurityContext::DecryptMessage(const Arguments &args) { + HandleScope scope; + + if(args.Length() != 2) + return VException("DecryptMessage takes an instance of SecurityBufferDescriptor and a callback function"); + if(!SecurityBufferDescriptor::HasInstance(args[0])) + return VException("DecryptMessage takes an instance of SecurityBufferDescriptor and a callback function"); + if(!args[1]->IsFunction()) + return VException("DecryptMessage takes an instance of SecurityBufferDescriptor and a callback function"); + + // Unpack the security context + SecurityContext *security_context = ObjectWrap::Unwrap(args.This()); + // Unpack the descriptor + SecurityBufferDescriptor *descriptor = ObjectWrap::Unwrap(args[0]->ToObject()); + // Create call structure + SecurityContextDecryptMessageCall *call = (SecurityContextDecryptMessageCall *)calloc(1, sizeof(SecurityContextDecryptMessageCall)); + call->context = security_context; + call->descriptor = descriptor; + + // Callback + Local callback = Local::Cast(args[1]); + + // Let's allocate some space + Worker *worker = new Worker(); + worker->error = false; + worker->request.data = worker; + worker->callback = Persistent::New(callback); + worker->parameters = call; + worker->execute = _decryptMessage; + worker->mapper = _map_decryptMessage; + + // Schedule the worker with lib_uv + uv_queue_work(uv_default_loop(), &worker->request, Process, (uv_after_work_cb)After); + + // Return undefined + return scope.Close(Undefined()); +} + +Handle SecurityContext::DecryptMessageSync(const Arguments &args) { + HandleScope scope; + unsigned long quality = 0; + SECURITY_STATUS status; + + if(args.Length() != 1) + return VException("DecryptMessageSync takes an instance of SecurityBufferDescriptor"); + if(!SecurityBufferDescriptor::HasInstance(args[0])) + return VException("DecryptMessageSync takes an instance of SecurityBufferDescriptor"); + + // Unpack the security context + SecurityContext *security_context = ObjectWrap::Unwrap(args.This()); + + // Unpack the descriptor + SecurityBufferDescriptor *descriptor = ObjectWrap::Unwrap(args[0]->ToObject()); + + // Let's execute encryption + status = _sspi_DecryptMessage( + &security_context->m_Context + , &descriptor->secBufferDesc + , 0 + , (unsigned long)&quality + ); + + // We've got ok + if(status == SEC_E_OK) { + int bytesToAllocate = (int)descriptor->bufferSize(); + // Free up existing payload + if(security_context->payload != NULL) free(security_context->payload); + // Save the payload + security_context->payload = base64_encode((unsigned char *)descriptor->toBuffer(), bytesToAllocate); + } else { + LPSTR err_message = DisplaySECError(status); + + if(err_message != NULL) { + return VExceptionErrNo(err_message, status); + } else { + return VExceptionErrNo("Unknown error", status); + } + } + + return scope.Close(Null()); +} + +// +// Async QueryContextAttributes +// +typedef struct SecurityContextQueryContextAttributesCall { + SecurityContext *context; + uint32_t attribute; +} SecurityContextQueryContextAttributesCall; + +static void _queryContextAttributes(Worker *worker) { + SECURITY_STATUS status; + + // Cast to data structure + SecurityContextQueryContextAttributesCall *call = (SecurityContextQueryContextAttributesCall *)worker->parameters; + + // Allocate some space + SecPkgContext_Sizes *sizes = (SecPkgContext_Sizes *)calloc(1, sizeof(SecPkgContext_Sizes)); + // Let's grab the query context attribute + status = _sspi_QueryContextAttributes( + &call->context->m_Context, + call->attribute, + sizes + ); + + if(status == SEC_E_OK) { + worker->return_code = status; + worker->return_value = sizes; + } else { + worker->error = TRUE; + worker->error_code = status; + worker->error_message = DisplaySECError(status); + } +} + +static Handle _map_queryContextAttributes(Worker *worker) { + HandleScope scope; + + // Cast to data structure + SecurityContextQueryContextAttributesCall *call = (SecurityContextQueryContextAttributesCall *)worker->parameters; + // Unpack the attribute + uint32_t attribute = call->attribute; + + // Convert data + if(attribute == SECPKG_ATTR_SIZES) { + SecPkgContext_Sizes *sizes = (SecPkgContext_Sizes *)worker->return_value; + // Create object + Local value = Object::New(); + value->Set(String::New("maxToken"), Integer::New(sizes->cbMaxToken)); + value->Set(String::New("maxSignature"), Integer::New(sizes->cbMaxSignature)); + value->Set(String::New("blockSize"), Integer::New(sizes->cbBlockSize)); + value->Set(String::New("securityTrailer"), Integer::New(sizes->cbSecurityTrailer)); + return scope.Close(value); + } + + // Return the value + return scope.Close(Null()); +} + +Handle SecurityContext::QueryContextAttributes(const Arguments &args) { + HandleScope scope; + + if(args.Length() != 2) + return VException("QueryContextAttributesSync method takes a an integer Attribute specifier and a callback function"); + if(!args[0]->IsInt32()) + return VException("QueryContextAttributes method takes a an integer Attribute specifier and a callback function"); + if(!args[1]->IsFunction()) + return VException("QueryContextAttributes method takes a an integer Attribute specifier and a callback function"); + + // Unpack the security context + SecurityContext *security_context = ObjectWrap::Unwrap(args.This()); + + // Unpack the int value + uint32_t attribute = args[0]->ToInt32()->Value(); + + // Check that we have a supported attribute + if(attribute != SECPKG_ATTR_SIZES) + return VException("QueryContextAttributes only supports the SECPKG_ATTR_SIZES attribute"); + + // Create call structure + SecurityContextQueryContextAttributesCall *call = (SecurityContextQueryContextAttributesCall *)calloc(1, sizeof(SecurityContextQueryContextAttributesCall)); + call->attribute = attribute; + call->context = security_context; + + // Callback + Local callback = Local::Cast(args[1]); + + // Let's allocate some space + Worker *worker = new Worker(); + worker->error = false; + worker->request.data = worker; + worker->callback = Persistent::New(callback); + worker->parameters = call; + worker->execute = _queryContextAttributes; + worker->mapper = _map_queryContextAttributes; + + // Schedule the worker with lib_uv + uv_queue_work(uv_default_loop(), &worker->request, Process, (uv_after_work_cb)After); + + // Return undefined + return scope.Close(Undefined()); +} + +Handle SecurityContext::QueryContextAttributesSync(const Arguments &args) { + HandleScope scope; + SECURITY_STATUS status; + + if(args.Length() != 1) + return VException("QueryContextAttributesSync method takes a an integer Attribute specifier"); + if(!args[0]->IsInt32()) + return VException("QueryContextAttributesSync method takes a an integer Attribute specifier"); + + // Unpack the security context + SecurityContext *security_context = ObjectWrap::Unwrap(args.This()); + uint32_t attribute = args[0]->ToInt32()->Value(); + + if(attribute != SECPKG_ATTR_SIZES) + return VException("QueryContextAttributes only supports the SECPKG_ATTR_SIZES attribute"); + + // Check what attribute we are asking for + if(attribute == SECPKG_ATTR_SIZES) { + SecPkgContext_Sizes sizes; + + // Let's grab the query context attribute + status = _sspi_QueryContextAttributes( + &security_context->m_Context, + attribute, + &sizes + ); + + if(status == SEC_E_OK) { + Local value = Object::New(); + value->Set(String::New("maxToken"), Integer::New(sizes.cbMaxToken)); + value->Set(String::New("maxSignature"), Integer::New(sizes.cbMaxSignature)); + value->Set(String::New("blockSize"), Integer::New(sizes.cbBlockSize)); + value->Set(String::New("securityTrailer"), Integer::New(sizes.cbSecurityTrailer)); + return scope.Close(value); + } else { + LPSTR err_message = DisplaySECError(status); + + if(err_message != NULL) { + return VExceptionErrNo(err_message, status); + } else { + return VExceptionErrNo("Unknown error", status); + } + } + } + + return scope.Close(Null()); +} + +void SecurityContext::Initialize(Handle target) { + // Grab the scope of the call from Node + HandleScope scope; + // Define a new function template + Local t = FunctionTemplate::New(New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("SecurityContext")); + + // Class methods + NODE_SET_METHOD(constructor_template, "initializeSync", InitializeContextSync); + NODE_SET_METHOD(constructor_template, "initialize", InitializeContext); + + // Set up method for the instance + NODE_SET_PROTOTYPE_METHOD(constructor_template, "initializeSync", InitalizeStepSync); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "initialize", InitalizeStep); + + NODE_SET_PROTOTYPE_METHOD(constructor_template, "decryptMessageSync", DecryptMessageSync); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "decryptMessage", DecryptMessage); + + NODE_SET_PROTOTYPE_METHOD(constructor_template, "queryContextAttributesSync", QueryContextAttributesSync); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "queryContextAttributes", QueryContextAttributes); + + NODE_SET_PROTOTYPE_METHOD(constructor_template, "encryptMessageSync", EncryptMessageSync); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "encryptMessage", EncryptMessage); + + // Getters for correct serialization of the object + constructor_template->InstanceTemplate()->SetAccessor(String::NewSymbol("payload"), PayloadGetter); + // Getters for correct serialization of the object + constructor_template->InstanceTemplate()->SetAccessor(String::NewSymbol("hasContext"), HasContextGetter); + + // Set template class name + target->Set(String::NewSymbol("SecurityContext"), constructor_template->GetFunction()); +} + +static LPSTR DisplaySECError(DWORD ErrCode) { + LPSTR pszName = NULL; // WinError.h + + switch(ErrCode) { + case SEC_E_BUFFER_TOO_SMALL: + pszName = "SEC_E_BUFFER_TOO_SMALL - The message buffer is too small. Used with the Digest SSP."; + break; + + case SEC_E_CRYPTO_SYSTEM_INVALID: + pszName = "SEC_E_CRYPTO_SYSTEM_INVALID - The cipher chosen for the security context is not supported. Used with the Digest SSP."; + break; + case SEC_E_INCOMPLETE_MESSAGE: + pszName = "SEC_E_INCOMPLETE_MESSAGE - The data in the input buffer is incomplete. The application needs to read more data from the server and call DecryptMessageSync (General) again."; + break; + + case SEC_E_INVALID_HANDLE: + pszName = "SEC_E_INVALID_HANDLE - A context handle that is not valid was specified in the phContext parameter. Used with the Digest and Schannel SSPs."; + break; + + case SEC_E_INVALID_TOKEN: + pszName = "SEC_E_INVALID_TOKEN - The buffers are of the wrong type or no buffer of type SECBUFFER_DATA was found. Used with the Schannel SSP."; + break; + + case SEC_E_MESSAGE_ALTERED: + pszName = "SEC_E_MESSAGE_ALTERED - The message has been altered. Used with the Digest and Schannel SSPs."; + break; + + case SEC_E_OUT_OF_SEQUENCE: + pszName = "SEC_E_OUT_OF_SEQUENCE - The message was not received in the correct sequence."; + break; + + case SEC_E_QOP_NOT_SUPPORTED: + pszName = "SEC_E_QOP_NOT_SUPPORTED - Neither confidentiality nor integrity are supported by the security context. Used with the Digest SSP."; + break; + + case SEC_I_CONTEXT_EXPIRED: + pszName = "SEC_I_CONTEXT_EXPIRED - The message sender has finished using the connection and has initiated a shutdown."; + break; + + case SEC_I_RENEGOTIATE: + pszName = "SEC_I_RENEGOTIATE - The remote party requires a new handshake sequence or the application has just initiated a shutdown."; + break; + + case SEC_E_ENCRYPT_FAILURE: + pszName = "SEC_E_ENCRYPT_FAILURE - The specified data could not be encrypted."; + break; + + case SEC_E_DECRYPT_FAILURE: + pszName = "SEC_E_DECRYPT_FAILURE - The specified data could not be decrypted."; + break; + case -1: + pszName = "Failed to load security.dll library"; + break; + } + + return pszName; +} + diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_context.h b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_context.h new file mode 100644 index 0000000..b0059e3 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_context.h @@ -0,0 +1,85 @@ +#ifndef SECURITY_CONTEXT_H +#define SECURITY_CONTEXT_H + +#include +#include +#include + +#define SECURITY_WIN32 1 + +#include +#include +#include "security_credentials.h" +#include "../worker.h" + +extern "C" { + #include "../kerberos_sspi.h" + #include "../base64.h" +} + +using namespace v8; +using namespace node; + +class SecurityContext : public ObjectWrap { + public: + SecurityContext(); + ~SecurityContext(); + + // Security info package + PSecPkgInfo m_PkgInfo; + // Do we have a context + bool hasContext; + // Reference to security credentials + SecurityCredentials *security_credentials; + // Security context + CtxtHandle m_Context; + // Attributes + DWORD CtxtAttr; + // Expiry time for ticket + TimeStamp Expiration; + // Payload + char *payload; + + // Has instance check + static inline bool HasInstance(Handle val) { + if (!val->IsObject()) return false; + Local obj = val->ToObject(); + return constructor_template->HasInstance(obj); + }; + + // Functions available from V8 + static void Initialize(Handle target); + + static Handle InitializeContext(const Arguments &args); + static Handle InitializeContextSync(const Arguments &args); + + static Handle InitalizeStep(const Arguments &args); + static Handle InitalizeStepSync(const Arguments &args); + + static Handle DecryptMessage(const Arguments &args); + static Handle DecryptMessageSync(const Arguments &args); + + static Handle QueryContextAttributesSync(const Arguments &args); + static Handle QueryContextAttributes(const Arguments &args); + + static Handle EncryptMessageSync(const Arguments &args); + static Handle EncryptMessage(const Arguments &args); + + // Payload getter + static Handle PayloadGetter(Local property, const AccessorInfo& info); + // hasContext getter + static Handle HasContextGetter(Local property, const AccessorInfo& info); + + // Constructor used for creating new Long objects from C++ + static Persistent constructor_template; + + private: + // Create a new instance + static Handle New(const Arguments &args); + // // Handles the uv calls + // static void Process(uv_work_t* work_req); + // // Called after work is done + // static void After(uv_work_t* work_req); +}; + +#endif diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_context.js b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_context.js new file mode 100644 index 0000000..ef04e92 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_context.js @@ -0,0 +1,3 @@ +var SecurityContextNative = require('../../../build/Release/kerberos').SecurityContext; +// Export the modified class +exports.SecurityContext = SecurityContextNative; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_credentials.cc b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_credentials.cc new file mode 100644 index 0000000..025238b --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_credentials.cc @@ -0,0 +1,468 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "security_credentials.h" + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0])) +#endif + +static LPSTR DisplaySECError(DWORD ErrCode); + +static Handle VException(const char *msg) { + HandleScope scope; + return ThrowException(Exception::Error(String::New(msg))); +}; + +static Handle VExceptionErrNo(const char *msg, const int errorNumber) { + HandleScope scope; + + Local err = Exception::Error(String::New(msg)); + Local obj = err->ToObject(); + obj->Set(NODE_PSYMBOL("code"), Int32::New(errorNumber)); + return ThrowException(err); +}; + +Persistent SecurityCredentials::constructor_template; + +SecurityCredentials::SecurityCredentials() : ObjectWrap() { +} + +SecurityCredentials::~SecurityCredentials() { +} + +Handle SecurityCredentials::New(const Arguments &args) { + HandleScope scope; + + // Create security credentials instance + SecurityCredentials *security_credentials = new SecurityCredentials(); + // Wrap it + security_credentials->Wrap(args.This()); + // Return the object + return args.This(); +} + +Handle SecurityCredentials::AquireSync(const Arguments &args) { + HandleScope scope; + char *package_str = NULL, *username_str = NULL, *password_str = NULL, *domain_str = NULL; + // Status of operation + SECURITY_STATUS status; + + // Unpack the variables + if(args.Length() != 2 && args.Length() != 3 && args.Length() != 4) + return VException("Aquire must be called with either [package:string, username:string, [password:string, domain:string]]"); + + if(!args[0]->IsString()) + return VException("Aquire must be called with either [package:string, username:string, [password:string, domain:string]]"); + + if(!args[1]->IsString()) + return VException("Aquire must be called with either [package:string, username:string, [password:string, domain:string]]"); + + if(args.Length() == 3 && !args[2]->IsString()) + return VException("Aquire must be called with either [package:string, username:string, [password:string, domain:string]]"); + + if(args.Length() == 4 && (!args[3]->IsString() && !args[3]->IsUndefined() && !args[3]->IsNull())) + return VException("Aquire must be called with either [package:string, username:string, [password:string, domain:string]]"); + + // Unpack the package + Local package = args[0]->ToString(); + package_str = (char *)calloc(package->Utf8Length() + 1, sizeof(char)); + package->WriteUtf8(package_str); + + // Unpack the user name + Local username = args[1]->ToString(); + username_str = (char *)calloc(username->Utf8Length() + 1, sizeof(char)); + username->WriteUtf8(username_str); + + // If we have a password + if(args.Length() == 3 || args.Length() == 4) { + Local password = args[2]->ToString(); + password_str = (char *)calloc(password->Utf8Length() + 1, sizeof(char)); + password->WriteUtf8(password_str); + } + + // If we have a domain + if(args.Length() == 4 && args[3]->IsString()) { + Local domain = args[3]->ToString(); + domain_str = (char *)calloc(domain->Utf8Length() + 1, sizeof(char)); + domain->WriteUtf8(domain_str); + } + + // Create Security instance + Local security_credentials_value = constructor_template->GetFunction()->NewInstance(); + + // Unwrap the credentials + SecurityCredentials *security_credentials = ObjectWrap::Unwrap(security_credentials_value); + + // If we have domain string + if(domain_str != NULL) { + security_credentials->m_Identity.Domain = USTR(_tcsdup(domain_str)); + security_credentials->m_Identity.DomainLength = (unsigned long)_tcslen(domain_str); + } else { + security_credentials->m_Identity.Domain = NULL; + security_credentials->m_Identity.DomainLength = 0; + } + + // Set up the user + security_credentials->m_Identity.User = USTR(_tcsdup(username_str)); + security_credentials->m_Identity.UserLength = (unsigned long)_tcslen(username_str); + + // If we have a password string + if(password_str != NULL) { + // Set up the password + security_credentials->m_Identity.Password = USTR(_tcsdup(password_str)); + security_credentials->m_Identity.PasswordLength = (unsigned long)_tcslen(password_str); + } + + #ifdef _UNICODE + security_credentials->m_Identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; + #else + security_credentials->m_Identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; + #endif + + // Attempt to acquire credentials + status = _sspi_AcquireCredentialsHandle( + NULL, + package_str, + SECPKG_CRED_OUTBOUND, + NULL, + password_str != NULL ? &security_credentials->m_Identity : NULL, + NULL, NULL, + &security_credentials->m_Credentials, + &security_credentials->Expiration + ); + + // We have an error + if(status != SEC_E_OK) { + LPSTR err_message = DisplaySECError(status); + + if(err_message != NULL) { + return VExceptionErrNo(err_message, status); + } else { + return VExceptionErrNo("Unknown error", status); + } + } + + // Make object persistent + Persistent persistent = Persistent::New(security_credentials_value); + // Return the object + return scope.Close(persistent); +} + +// Call structs +typedef struct SecurityCredentialCall { + char *package_str; + char *username_str; + char *password_str; + char *domain_str; + SecurityCredentials *credentials; +} SecurityCredentialCall; + +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// authGSSClientInit +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +static void _authSSPIAquire(Worker *worker) { + // Status of operation + SECURITY_STATUS status; + + // Unpack data + SecurityCredentialCall *call = (SecurityCredentialCall *)worker->parameters; + + // Unwrap the credentials + SecurityCredentials *security_credentials = (SecurityCredentials *)call->credentials; + + // If we have domain string + if(call->domain_str != NULL) { + security_credentials->m_Identity.Domain = USTR(_tcsdup(call->domain_str)); + security_credentials->m_Identity.DomainLength = (unsigned long)_tcslen(call->domain_str); + } else { + security_credentials->m_Identity.Domain = NULL; + security_credentials->m_Identity.DomainLength = 0; + } + + // Set up the user + security_credentials->m_Identity.User = USTR(_tcsdup(call->username_str)); + security_credentials->m_Identity.UserLength = (unsigned long)_tcslen(call->username_str); + + // If we have a password string + if(call->password_str != NULL) { + // Set up the password + security_credentials->m_Identity.Password = USTR(_tcsdup(call->password_str)); + security_credentials->m_Identity.PasswordLength = (unsigned long)_tcslen(call->password_str); + } + + #ifdef _UNICODE + security_credentials->m_Identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; + #else + security_credentials->m_Identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; + #endif + + // Attempt to acquire credentials + status = _sspi_AcquireCredentialsHandle( + NULL, + call->package_str, + SECPKG_CRED_OUTBOUND, + NULL, + call->password_str != NULL ? &security_credentials->m_Identity : NULL, + NULL, NULL, + &security_credentials->m_Credentials, + &security_credentials->Expiration + ); + + // We have an error + if(status != SEC_E_OK) { + worker->error = TRUE; + worker->error_code = status; + worker->error_message = DisplaySECError(status); + } else { + worker->return_code = status; + worker->return_value = security_credentials; + } + + // Free up parameter structure + if(call->package_str != NULL) free(call->package_str); + if(call->domain_str != NULL) free(call->domain_str); + if(call->password_str != NULL) free(call->password_str); + if(call->username_str != NULL) free(call->username_str); + free(call); +} + +static Handle _map_authSSPIAquire(Worker *worker) { + HandleScope scope; + + // Unpack the credentials + SecurityCredentials *security_credentials = (SecurityCredentials *)worker->return_value; + // Make object persistent + Persistent persistent = Persistent::New(security_credentials->handle_); + // Return the object + return scope.Close(persistent); +} + +Handle SecurityCredentials::Aquire(const Arguments &args) { + HandleScope scope; + char *package_str = NULL, *username_str = NULL, *password_str = NULL, *domain_str = NULL; + // Unpack the variables + if(args.Length() != 2 && args.Length() != 3 && args.Length() != 4 && args.Length() != 5) + return VException("Aquire must be called with either [package:string, username:string, [password:string, domain:string], callback:function]"); + + if(!args[0]->IsString()) + return VException("Aquire must be called with either [package:string, username:string, [password:string, domain:string], callback:function]"); + + if(!args[1]->IsString()) + return VException("Aquire must be called with either [package:string, username:string, [password:string, domain:string], callback:function]"); + + if(args.Length() == 3 && (!args[2]->IsString() && !args[2]->IsFunction())) + return VException("Aquire must be called with either [package:string, username:string, [password:string, domain:string], callback:function]"); + + if(args.Length() == 4 && (!args[3]->IsString() && !args[3]->IsUndefined() && !args[3]->IsNull()) && !args[3]->IsFunction()) + return VException("Aquire must be called with either [package:string, username:string, [password:string, domain:string], callback:function]"); + + if(args.Length() == 5 && !args[4]->IsFunction()) + return VException("Aquire must be called with either [package:string, username:string, [password:string, domain:string], callback:function]"); + + Local callback; + + // Figure out which parameter is the callback + if(args.Length() == 5) { + callback = Local::Cast(args[4]); + } else if(args.Length() == 4) { + callback = Local::Cast(args[3]); + } else if(args.Length() == 3) { + callback = Local::Cast(args[2]); + } + + // Unpack the package + Local package = args[0]->ToString(); + package_str = (char *)calloc(package->Utf8Length() + 1, sizeof(char)); + package->WriteUtf8(package_str); + + // Unpack the user name + Local username = args[1]->ToString(); + username_str = (char *)calloc(username->Utf8Length() + 1, sizeof(char)); + username->WriteUtf8(username_str); + + // If we have a password + if(args.Length() == 3 || args.Length() == 4 || args.Length() == 5) { + Local password = args[2]->ToString(); + password_str = (char *)calloc(password->Utf8Length() + 1, sizeof(char)); + password->WriteUtf8(password_str); + } + + // If we have a domain + if((args.Length() == 4 || args.Length() == 5) && args[3]->IsString()) { + Local domain = args[3]->ToString(); + domain_str = (char *)calloc(domain->Utf8Length() + 1, sizeof(char)); + domain->WriteUtf8(domain_str); + } + + // Create reference object + Local security_credentials_value = constructor_template->GetFunction()->NewInstance(); + // Unwrap object + SecurityCredentials *security_credentials = ObjectWrap::Unwrap(security_credentials_value); + + // Allocate call structure + SecurityCredentialCall *call = (SecurityCredentialCall *)calloc(1, sizeof(SecurityCredentialCall)); + call->domain_str = domain_str; + call->package_str = package_str; + call->password_str = password_str; + call->username_str = username_str; + call->credentials = security_credentials; + + // Let's allocate some space + Worker *worker = new Worker(); + worker->error = false; + worker->request.data = worker; + worker->callback = Persistent::New(callback); + worker->parameters = call; + worker->execute = _authSSPIAquire; + worker->mapper = _map_authSSPIAquire; + + // Schedule the worker with lib_uv + uv_queue_work(uv_default_loop(), &worker->request, SecurityCredentials::Process, (uv_after_work_cb)SecurityCredentials::After); + + // Return the undefined value + return scope.Close(Undefined()); +} + +void SecurityCredentials::Initialize(Handle target) { + // Grab the scope of the call from Node + HandleScope scope; + // Define a new function template + Local t = FunctionTemplate::New(New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("SecurityCredentials")); + + // Class methods + NODE_SET_METHOD(constructor_template, "aquireSync", AquireSync); + NODE_SET_METHOD(constructor_template, "aquire", Aquire); + + // Set the class on the target module + target->Set(String::NewSymbol("SecurityCredentials"), constructor_template->GetFunction()); + + // Attempt to load the security.dll library + load_library(); +} + +static LPSTR DisplaySECError(DWORD ErrCode) { + LPSTR pszName = NULL; // WinError.h + + switch(ErrCode) { + case SEC_E_BUFFER_TOO_SMALL: + pszName = "SEC_E_BUFFER_TOO_SMALL - The message buffer is too small. Used with the Digest SSP."; + break; + + case SEC_E_CRYPTO_SYSTEM_INVALID: + pszName = "SEC_E_CRYPTO_SYSTEM_INVALID - The cipher chosen for the security context is not supported. Used with the Digest SSP."; + break; + case SEC_E_INCOMPLETE_MESSAGE: + pszName = "SEC_E_INCOMPLETE_MESSAGE - The data in the input buffer is incomplete. The application needs to read more data from the server and call DecryptMessage (General) again."; + break; + + case SEC_E_INVALID_HANDLE: + pszName = "SEC_E_INVALID_HANDLE - A context handle that is not valid was specified in the phContext parameter. Used with the Digest and Schannel SSPs."; + break; + + case SEC_E_INVALID_TOKEN: + pszName = "SEC_E_INVALID_TOKEN - The buffers are of the wrong type or no buffer of type SECBUFFER_DATA was found. Used with the Schannel SSP."; + break; + + case SEC_E_MESSAGE_ALTERED: + pszName = "SEC_E_MESSAGE_ALTERED - The message has been altered. Used with the Digest and Schannel SSPs."; + break; + + case SEC_E_OUT_OF_SEQUENCE: + pszName = "SEC_E_OUT_OF_SEQUENCE - The message was not received in the correct sequence."; + break; + + case SEC_E_QOP_NOT_SUPPORTED: + pszName = "SEC_E_QOP_NOT_SUPPORTED - Neither confidentiality nor integrity are supported by the security context. Used with the Digest SSP."; + break; + + case SEC_I_CONTEXT_EXPIRED: + pszName = "SEC_I_CONTEXT_EXPIRED - The message sender has finished using the connection and has initiated a shutdown."; + break; + + case SEC_I_RENEGOTIATE: + pszName = "SEC_I_RENEGOTIATE - The remote party requires a new handshake sequence or the application has just initiated a shutdown."; + break; + + case SEC_E_ENCRYPT_FAILURE: + pszName = "SEC_E_ENCRYPT_FAILURE - The specified data could not be encrypted."; + break; + + case SEC_E_DECRYPT_FAILURE: + pszName = "SEC_E_DECRYPT_FAILURE - The specified data could not be decrypted."; + break; + case -1: + pszName = "Failed to load security.dll library"; + break; + + } + + return pszName; +} + +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// UV Lib callbacks +// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +void SecurityCredentials::Process(uv_work_t* work_req) { + // Grab the worker + Worker *worker = static_cast(work_req->data); + // Execute the worker code + worker->execute(worker); +} + +void SecurityCredentials::After(uv_work_t* work_req) { + // Grab the scope of the call from Node + v8::HandleScope scope; + + // Get the worker reference + Worker *worker = static_cast(work_req->data); + + // If we have an error + if(worker->error) { + v8::Local err = v8::Exception::Error(v8::String::New(worker->error_message)); + Local obj = err->ToObject(); + obj->Set(NODE_PSYMBOL("code"), Int32::New(worker->error_code)); + v8::Local args[2] = { err, v8::Local::New(v8::Null()) }; + // Execute the error + v8::TryCatch try_catch; + // Call the callback + worker->callback->Call(v8::Context::GetCurrent()->Global(), ARRAY_SIZE(args), args); + // If we have an exception handle it as a fatalexception + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } else { + // // Map the data + v8::Handle result = worker->mapper(worker); + // Set up the callback with a null first + v8::Handle args[2] = { v8::Local::New(v8::Null()), result}; + // Wrap the callback function call in a TryCatch so that we can call + // node's FatalException afterwards. This makes it possible to catch + // the exception from JavaScript land using the + // process.on('uncaughtException') event. + v8::TryCatch try_catch; + // Call the callback + worker->callback->Call(v8::Context::GetCurrent()->Global(), ARRAY_SIZE(args), args); + // If we have an exception handle it as a fatalexception + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } + + // Clean up the memory + worker->callback.Dispose(); + delete worker; +} + diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_credentials.h b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_credentials.h new file mode 100644 index 0000000..10b3eda --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_credentials.h @@ -0,0 +1,67 @@ +#ifndef SECURITY_CREDENTIALS_H +#define SECURITY_CREDENTIALS_H + +#include +#include +#include + +#define SECURITY_WIN32 1 + +#include +#include +#include +#include "../worker.h" +#include + +extern "C" { + #include "../kerberos_sspi.h" +} + +// SEC_WINNT_AUTH_IDENTITY makes it unusually hard +// to compile for both Unicode and ansi, so I use this macro: +#ifdef _UNICODE +#define USTR(str) (str) +#else +#define USTR(str) ((unsigned char*)(str)) +#endif + +using namespace v8; +using namespace node; + +class SecurityCredentials : public ObjectWrap { + public: + SecurityCredentials(); + ~SecurityCredentials(); + + // Pointer to context object + SEC_WINNT_AUTH_IDENTITY m_Identity; + // credentials + CredHandle m_Credentials; + // Expiry time for ticket + TimeStamp Expiration; + + // Has instance check + static inline bool HasInstance(Handle val) { + if (!val->IsObject()) return false; + Local obj = val->ToObject(); + return constructor_template->HasInstance(obj); + }; + + // Functions available from V8 + static void Initialize(Handle target); + static Handle AquireSync(const Arguments &args); + static Handle Aquire(const Arguments &args); + + // Constructor used for creating new Long objects from C++ + static Persistent constructor_template; + + private: + // Create a new instance + static Handle New(const Arguments &args); + // Handles the uv calls + static void Process(uv_work_t* work_req); + // Called after work is done + static void After(uv_work_t* work_req); +}; + +#endif \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_credentials.js b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_credentials.js new file mode 100644 index 0000000..4215c92 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/win32/wrappers/security_credentials.js @@ -0,0 +1,22 @@ +var SecurityCredentialsNative = require('../../../build/Release/kerberos').SecurityCredentials; + +// Add simple kebros helper +SecurityCredentialsNative.aquire_kerberos = function(username, password, domain, callback) { + if(typeof password == 'function') { + callback = password; + password = null; + } else if(typeof domain == 'function') { + callback = domain; + domain = null; + } + + // We are going to use the async version + if(typeof callback == 'function') { + return SecurityCredentialsNative.aquire('Kerberos', username, password, domain, callback); + } else { + return SecurityCredentialsNative.aquireSync('Kerberos', username, password, domain); + } +} + +// Export the modified class +exports.SecurityCredentials = SecurityCredentialsNative; \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/worker.cc b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/worker.cc new file mode 100644 index 0000000..e7a472f --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/worker.cc @@ -0,0 +1,7 @@ +#include "worker.h" + +Worker::Worker() { +} + +Worker::~Worker() { +} \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/worker.h b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/worker.h new file mode 100644 index 0000000..c5f86f5 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/lib/worker.h @@ -0,0 +1,39 @@ +#ifndef WORKER_H_ +#define WORKER_H_ + +#include +#include +#include + +using namespace node; +using namespace v8; + +class Worker { + public: + Worker(); + virtual ~Worker(); + + // libuv's request struct. + uv_work_t request; + // Callback + v8::Persistent callback; + // // Arguments + // v8::Persistent arguments; + // Parameters + void *parameters; + // Results + void *return_value; + // Did we raise an error + bool error; + // The error message + char *error_message; + // Error code if not message + int error_code; + // Any return code + int return_code; + // Method we are going to fire + void (*execute)(Worker *worker); + Handle (*mapper)(Worker *worker); +}; + +#endif // WORKER_H_ diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/package.json b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/package.json new file mode 100644 index 0000000..1832446 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/package.json @@ -0,0 +1,38 @@ +{ + "name": "kerberos", + "version": "0.0.3", + "description": "Kerberos library for Node.js", + "main": "index.js", + "scripts": { + "install": "(node-gyp rebuild 2> builderror.log) || (exit 0)", + "test": "nodeunit ./test" + }, + "repository": { + "type": "git", + "url": "https://github.com/christkv/kerberos.git" + }, + "keywords": [ + "kerberos", + "security", + "authentication" + ], + "devDependencies": { + "nodeunit": "latest" + }, + "author": { + "name": "Christian Amor Kvalheim" + }, + "license": "Apache 2.0", + "readmeFilename": "README.md", + "gitHead": "bb01d4fe322e022999aca19da564e7d9db59a8ed", + "readme": "kerberos\n========\n\nKerberos library for node.js", + "bugs": { + "url": "https://github.com/christkv/kerberos/issues" + }, + "_id": "kerberos@0.0.3", + "dist": { + "shasum": "04d6151e556551d5ee9c0a28ff92e91dcb8caf73" + }, + "_from": "kerberos@0.0.3", + "_resolved": "https://registry.npmjs.org/kerberos/-/kerberos-0.0.3.tgz" +} diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/test/kerberos_tests.js b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/test/kerberos_tests.js new file mode 100644 index 0000000..a06c5fd --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/test/kerberos_tests.js @@ -0,0 +1,34 @@ +exports.setUp = function(callback) { + callback(); +} + +exports.tearDown = function(callback) { + callback(); +} + +exports['Simple initialize of Kerberos object'] = function(test) { + var Kerberos = require('../lib/kerberos.js').Kerberos; + var kerberos = new Kerberos(); + // console.dir(kerberos) + + // Initiate kerberos client + kerberos.authGSSClientInit('mongodb@kdc.10gen.me', Kerberos.GSS_C_MUTUAL_FLAG, function(err, context) { + console.log("===================================== authGSSClientInit") + test.equal(null, err); + test.ok(context != null && typeof context == 'object'); + // console.log("===================================== authGSSClientInit") + console.dir(err) + console.dir(context) + // console.dir(typeof result) + + // Perform the first step + kerberos.authGSSClientStep(context, function(err, result) { + console.log("===================================== authGSSClientStep") + console.dir(err) + console.dir(result) + console.dir(context) + + test.done(); + }); + }); +} \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/test/kerberos_win32_test.js b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/test/kerberos_win32_test.js new file mode 100644 index 0000000..d2f7046 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/test/kerberos_win32_test.js @@ -0,0 +1,19 @@ +exports.setUp = function(callback) { + callback(); +} + +exports.tearDown = function(callback) { + callback(); +} + +exports['Simple initialize of Kerberos win32 object'] = function(test) { + var KerberosNative = require('../build/Release/kerberos').Kerberos; + // console.dir(KerberosNative) + var kerberos = new KerberosNative(); + console.log("=========================================== 0") + console.dir(kerberos.acquireAlternateCredentials("dev1@10GEN.ME", "a")); + console.log("=========================================== 1") + console.dir(kerberos.prepareOutboundPackage("mongodb/kdc.10gen.com")); + console.log("=========================================== 2") + test.done(); +} diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/test/win32/security_buffer_descriptor_tests.js b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/test/win32/security_buffer_descriptor_tests.js new file mode 100644 index 0000000..3531b6b --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/test/win32/security_buffer_descriptor_tests.js @@ -0,0 +1,41 @@ +exports.setUp = function(callback) { + callback(); +} + +exports.tearDown = function(callback) { + callback(); +} + +exports['Initialize a security Buffer Descriptor'] = function(test) { + var SecurityBufferDescriptor = require('../../lib/sspi.js').SecurityBufferDescriptor + SecurityBuffer = require('../../lib/sspi.js').SecurityBuffer; + + // Create descriptor with single Buffer + var securityDescriptor = new SecurityBufferDescriptor(100); + try { + // Fail to work due to no valid Security Buffer + securityDescriptor = new SecurityBufferDescriptor(["hello"]); + test.ok(false); + } catch(err){} + + // Should Correctly construct SecurityBuffer + var buffer = new SecurityBuffer(SecurityBuffer.DATA, 100); + securityDescriptor = new SecurityBufferDescriptor([buffer]); + // Should correctly return a buffer + var result = securityDescriptor.toBuffer(); + test.equal(100, result.length); + + // Should Correctly construct SecurityBuffer + var buffer = new SecurityBuffer(SecurityBuffer.DATA, new Buffer("hello world")); + securityDescriptor = new SecurityBufferDescriptor([buffer]); + var result = securityDescriptor.toBuffer(); + test.equal("hello world", result.toString()); + + // Test passing in more than one Buffer + var buffer = new SecurityBuffer(SecurityBuffer.DATA, new Buffer("hello world")); + var buffer2 = new SecurityBuffer(SecurityBuffer.STREAM, new Buffer("adam and eve")); + securityDescriptor = new SecurityBufferDescriptor([buffer, buffer2]); + var result = securityDescriptor.toBuffer(); + test.equal("hello worldadam and eve", result.toString()); + test.done(); +} \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/test/win32/security_buffer_tests.js b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/test/win32/security_buffer_tests.js new file mode 100644 index 0000000..b52b959 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/test/win32/security_buffer_tests.js @@ -0,0 +1,22 @@ +exports.setUp = function(callback) { + callback(); +} + +exports.tearDown = function(callback) { + callback(); +} + +exports['Initialize a security Buffer'] = function(test) { + var SecurityBuffer = require('../../lib/sspi.js').SecurityBuffer; + // Create empty buffer + var securityBuffer = new SecurityBuffer(SecurityBuffer.DATA, 100); + var buffer = securityBuffer.toBuffer(); + test.equal(100, buffer.length); + + // Access data passed in + var allocated_buffer = new Buffer(256); + securityBuffer = new SecurityBuffer(SecurityBuffer.DATA, allocated_buffer); + buffer = securityBuffer.toBuffer(); + test.deepEqual(allocated_buffer, buffer); + test.done(); +} \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/test/win32/security_credentials_tests.js b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/test/win32/security_credentials_tests.js new file mode 100644 index 0000000..7758180 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/node_modules/kerberos/test/win32/security_credentials_tests.js @@ -0,0 +1,55 @@ +exports.setUp = function(callback) { + callback(); +} + +exports.tearDown = function(callback) { + callback(); +} + +exports['Initialize a set of security credentials'] = function(test) { + var SecurityCredentials = require('../../lib/sspi.js').SecurityCredentials; + + // Aquire some credentials + try { + var credentials = SecurityCredentials.aquire('Kerberos', 'dev1@10GEN.ME', 'a'); + } catch(err) { + console.dir(err) + test.ok(false); + } + + + + // console.dir(SecurityCredentials); + + // var SecurityBufferDescriptor = require('../../lib/sspi.js').SecurityBufferDescriptor + // SecurityBuffer = require('../../lib/sspi.js').SecurityBuffer; + + // // Create descriptor with single Buffer + // var securityDescriptor = new SecurityBufferDescriptor(100); + // try { + // // Fail to work due to no valid Security Buffer + // securityDescriptor = new SecurityBufferDescriptor(["hello"]); + // test.ok(false); + // } catch(err){} + + // // Should Correctly construct SecurityBuffer + // var buffer = new SecurityBuffer(SecurityBuffer.DATA, 100); + // securityDescriptor = new SecurityBufferDescriptor([buffer]); + // // Should correctly return a buffer + // var result = securityDescriptor.toBuffer(); + // test.equal(100, result.length); + + // // Should Correctly construct SecurityBuffer + // var buffer = new SecurityBuffer(SecurityBuffer.DATA, new Buffer("hello world")); + // securityDescriptor = new SecurityBufferDescriptor([buffer]); + // var result = securityDescriptor.toBuffer(); + // test.equal("hello world", result.toString()); + + // // Test passing in more than one Buffer + // var buffer = new SecurityBuffer(SecurityBuffer.DATA, new Buffer("hello world")); + // var buffer2 = new SecurityBuffer(SecurityBuffer.STREAM, new Buffer("adam and eve")); + // securityDescriptor = new SecurityBufferDescriptor([buffer, buffer2]); + // var result = securityDescriptor.toBuffer(); + // test.equal("hello worldadam and eve", result.toString()); + test.done(); +} \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mongodb/package.json b/node_modules/mongoose/node_modules/mongodb/package.json new file mode 100755 index 0000000..91b4488 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/package.json @@ -0,0 +1,228 @@ +{ + "name": "mongodb", + "description": "A node.js driver for MongoDB", + "keywords": [ + "mongodb", + "mongo", + "driver", + "db" + ], + "version": "1.3.19", + "author": { + "name": "Christian Amor Kvalheim", + "email": "christkv@gmail.com" + }, + "contributors": [ + { + "name": "Aaron Heckmann" + }, + { + "name": "Christoph Pojer" + }, + { + "name": "Pau Ramon Revilla" + }, + { + "name": "Nathan White" + }, + { + "name": "Emmerman" + }, + { + "name": "Seth LaForge" + }, + { + "name": "Boris Filipov" + }, + { + "name": "Stefan Schärmeli" + }, + { + "name": "Tedde Lundgren" + }, + { + "name": "renctan" + }, + { + "name": "Sergey Ukustov" + }, + { + "name": "Ciaran Jessup" + }, + { + "name": "kuno" + }, + { + "name": "srimonti" + }, + { + "name": "Erik Abele" + }, + { + "name": "Pratik Daga" + }, + { + "name": "Slobodan Utvic" + }, + { + "name": "Kristina Chodorow" + }, + { + "name": "Yonathan Randolph" + }, + { + "name": "Brian Noguchi" + }, + { + "name": "Sam Epstein" + }, + { + "name": "James Harrison Fisher" + }, + { + "name": "Vladimir Dronnikov" + }, + { + "name": "Ben Hockey" + }, + { + "name": "Henrik Johansson" + }, + { + "name": "Simon Weare" + }, + { + "name": "Alex Gorbatchev" + }, + { + "name": "Shimon Doodkin" + }, + { + "name": "Kyle Mueller" + }, + { + "name": "Eran Hammer-Lahav" + }, + { + "name": "Marcin Ciszak" + }, + { + "name": "François de Metz" + }, + { + "name": "Vinay Pulim" + }, + { + "name": "nstielau" + }, + { + "name": "Adam Wiggins" + }, + { + "name": "entrinzikyl" + }, + { + "name": "Jeremy Selier" + }, + { + "name": "Ian Millington" + }, + { + "name": "Public Keating" + }, + { + "name": "andrewjstone" + }, + { + "name": "Christopher Stott" + }, + { + "name": "Corey Jewett" + }, + { + "name": "brettkiefer" + }, + { + "name": "Rob Holland" + }, + { + "name": "Senmiao Liu" + }, + { + "name": "heroic" + }, + { + "name": "gitfy" + }, + { + "name": "Andrew Stone" + }, + { + "name": "John Le Drew" + }, + { + "name": "Lucasfilm Singapore" + }, + { + "name": "Roman Shtylman" + }, + { + "name": "Matt Self" + } + ], + "repository": { + "type": "git", + "url": "http://github.com/mongodb/node-mongodb-native.git" + }, + "bugs": { + "url": "http://github.com/mongodb/node-mongodb-native/issues" + }, + "dependencies": { + "bson": "0.2.2", + "kerberos": "0.0.3" + }, + "devDependencies": { + "dox": "0.2.0", + "uglify-js": "1.2.5", + "ejs": "0.6.1", + "request": "2.12.0", + "nodeunit": "0.7.4", + "markdown": "0.3.1", + "gleak": "0.2.3", + "step": "0.0.5", + "async": "0.1.22", + "integra": "latest", + "optimist": "latest" + }, + "optionalDependencies": { + "kerberos": "0.0.3" + }, + "config": { + "native": false + }, + "main": "./lib/mongodb/index", + "homepage": "http://mongodb.github.com/node-mongodb-native/", + "directories": { + "lib": "./lib/mongodb" + }, + "engines": { + "node": ">=0.6.19" + }, + "scripts": { + "test": "make test_functional" + }, + "licenses": [ + { + "type": "Apache License, Version 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0" + } + ], + "readme": "Up to date documentation\n========================\n\n[Documentation](http://mongodb.github.com/node-mongodb-native/)\n\nInstall\n=======\n\nTo install the most recent release from npm, run:\n\n npm install mongodb\n\nThat may give you a warning telling you that bugs['web'] should be bugs['url'], it would be safe to ignore it (this has been fixed in the development version)\n\nTo install the latest from the repository, run::\n\n npm install path/to/node-mongodb-native\n\nCommunity\n=========\nCheck out the google group [node-mongodb-native](http://groups.google.com/group/node-mongodb-native) for questions/answers from users of the driver.\n\nLive Examples\n============\n\n\nIntroduction\n============\n\nThis is a node.js driver for MongoDB. It's a port (or close to a port) of the library for ruby at http://github.com/mongodb/mongo-ruby-driver/.\n\nA simple example of inserting a document.\n\n```javascript\n var MongoClient = require('mongodb').MongoClient\n , format = require('util').format; \n\n MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {\n if(err) throw err;\n\n var collection = db.collection('test_insert');\n collection.insert({a:2}, function(err, docs) {\n \n collection.count(function(err, count) {\n console.log(format(\"count = %s\", count));\n });\n\n // Locate all the entries using find\n collection.find().toArray(function(err, results) {\n console.dir(results);\n // Let's close the db\n db.close();\n }); \n });\n })\n```\n\nData types\n==========\n\nTo store and retrieve the non-JSON MongoDb primitives ([ObjectID](http://www.mongodb.org/display/DOCS/Object+IDs), Long, Binary, [Timestamp](http://www.mongodb.org/display/DOCS/Timestamp+data+type), [DBRef](http://www.mongodb.org/display/DOCS/Database+References#DatabaseReferences-DBRef), Code).\n\nIn particular, every document has a unique `_id` which can be almost any type, and by default a 12-byte ObjectID is created. ObjectIDs can be represented as 24-digit hexadecimal strings, but you must convert the string back into an ObjectID before you can use it in the database. For example:\n\n```javascript\n // Get the objectID type\n var ObjectID = require('mongodb').ObjectID;\n\n var idString = '4e4e1638c85e808431000003';\n collection.findOne({_id: new ObjectID(idString)}, console.log) // ok\n collection.findOne({_id: idString}, console.log) // wrong! callback gets undefined\n```\n\nHere are the constructors the non-Javascript BSON primitive types:\n\n```javascript\n // Fetch the library\n var mongo = require('mongodb');\n // Create new instances of BSON types\n new mongo.Long(numberString)\n new mongo.ObjectID(hexString)\n new mongo.Timestamp() // the actual unique number is generated on insert.\n new mongo.DBRef(collectionName, id, dbName)\n new mongo.Binary(buffer) // takes a string or Buffer\n new mongo.Code(code, [context])\n new mongo.Symbol(string)\n new mongo.MinKey()\n new mongo.MaxKey()\n new mongo.Double(number)\t// Force double storage\n```\n\nThe C/C++ bson parser/serializer\n--------------------------------\n\nIf you are running a version of this library has the C/C++ parser compiled, to enable the driver to use the C/C++ bson parser pass it the option native_parser:true like below\n\n```javascript\n // using native_parser:\n MongoClient.connect('mongodb://127.0.0.1:27017/test'\n , {db: {native_parser: true}}, function(err, db) {})\n```\n\nThe C++ parser uses the js objects both for serialization and deserialization.\n\nGitHub information\n==================\n\nThe source code is available at http://github.com/mongodb/node-mongodb-native.\nYou can either clone the repository or download a tarball of the latest release.\n\nOnce you have the source you can test the driver by running\n\n $ make test\n\nin the main directory. You will need to have a mongo instance running on localhost for the integration tests to pass.\n\nExamples\n========\n\nFor examples look in the examples/ directory. You can execute the examples using node.\n\n $ cd examples\n $ node queries.js\n\nGridStore\n=========\n\nThe GridStore class allows for storage of binary files in mongoDB using the mongoDB defined files and chunks collection definition.\n\nFor more information have a look at [Gridstore](https://github.com/mongodb/node-mongodb-native/blob/master/docs/gridfs.md)\n\nReplicasets\n===========\nFor more information about how to connect to a replicaset have a look at the extensive documentation [Documentation](http://mongodb.github.com/node-mongodb-native/)\n\nPrimary Key Factories\n---------------------\n\nDefining your own primary key factory allows you to generate your own series of id's\n(this could f.ex be to use something like ISBN numbers). The generated the id needs to be a 12 byte long \"string\".\n\nSimple example below\n\n```javascript\n var MongoClient = require('mongodb').MongoClient\n , format = require('util').format; \n\n // Custom factory (need to provide a 12 byte array);\n CustomPKFactory = function() {}\n CustomPKFactory.prototype = new Object();\n CustomPKFactory.createPk = function() {\n return new ObjectID(\"aaaaaaaaaaaa\");\n }\n\n MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {\n if(err) throw err;\n\n db.dropDatabase(function(err, done) {\n \n db.createCollection('test_custom_key', function(err, collection) {\n \n collection.insert({'a':1}, function(err, docs) {\n \n collection.find({'_id':new ObjectID(\"aaaaaaaaaaaa\")}).toArray(function(err, items) {\n console.dir(items);\n // Let's close the db\n db.close();\n });\n });\n });\n });\n });\n```\n\nDocumentation\n=============\n\nIf this document doesn't answer your questions, see the source of\n[Collection](https://github.com/mongodb/node-mongodb-native/blob/master/lib/mongodb/collection.js)\nor [Cursor](https://github.com/mongodb/node-mongodb-native/blob/master/lib/mongodb/cursor.js),\nor the documentation at MongoDB for query and update formats.\n\nFind\n----\n\nThe find method is actually a factory method to create\nCursor objects. A Cursor lazily uses the connection the first time\nyou call `nextObject`, `each`, or `toArray`.\n\nThe basic operation on a cursor is the `nextObject` method\nthat fetches the next matching document from the database. The convenience\nmethods `each` and `toArray` call `nextObject` until the cursor is exhausted.\n\nSignatures:\n\n```javascript\n var cursor = collection.find(query, [fields], options);\n cursor.sort(fields).limit(n).skip(m).\n\n cursor.nextObject(function(err, doc) {});\n cursor.each(function(err, doc) {});\n cursor.toArray(function(err, docs) {});\n\n cursor.rewind() // reset the cursor to its initial state.\n```\n\nUseful chainable methods of cursor. These can optionally be options of `find` instead of method calls:\n\n * `.limit(n).skip(m)` to control paging.\n * `.sort(fields)` Order by the given fields. There are several equivalent syntaxes:\n * `.sort({field1: -1, field2: 1})` descending by field1, then ascending by field2.\n * `.sort([['field1', 'desc'], ['field2', 'asc']])` same as above\n * `.sort([['field1', 'desc'], 'field2'])` same as above\n * `.sort('field1')` ascending by field1\n\nOther options of `find`:\n\n* `fields` the fields to fetch (to avoid transferring the entire document)\n* `tailable` if true, makes the cursor [tailable](http://www.mongodb.org/display/DOCS/Tailable+Cursors).\n* `batchSize` The number of the subset of results to request the database\nto return for every request. This should initially be greater than 1 otherwise\nthe database will automatically close the cursor. The batch size can be set to 1\nwith `batchSize(n, function(err){})` after performing the initial query to the database.\n* `hint` See [Optimization: hint](http://www.mongodb.org/display/DOCS/Optimization#Optimization-Hint).\n* `explain` turns this into an explain query. You can also call\n`explain()` on any cursor to fetch the explanation.\n* `snapshot` prevents documents that are updated while the query is active\nfrom being returned multiple times. See more\n[details about query snapshots](http://www.mongodb.org/display/DOCS/How+to+do+Snapshotted+Queries+in+the+Mongo+Database).\n* `timeout` if false, asks MongoDb not to time out this cursor after an\ninactivity period.\n\n\nFor information on how to create queries, see the\n[MongoDB section on querying](http://www.mongodb.org/display/DOCS/Querying).\n\n```javascript\n var MongoClient = require('mongodb').MongoClient\n , format = require('util').format; \n\n MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {\n if(err) throw err;\n\n var collection = db\n .collection('test')\n .find({})\n .limit(10)\n .toArray(function(err, docs) {\n console.dir(docs);\n });\n });\n```\n\nInsert\n------\n\nSignature:\n\n```javascript\n collection.insert(docs, options, [callback]);\n```\n\nwhere `docs` can be a single document or an array of documents.\n\nUseful options:\n\n* `safe:true` Should always set if you have a callback.\n\nSee also: [MongoDB docs for insert](http://www.mongodb.org/display/DOCS/Inserting).\n\n```javascript\n var MongoClient = require('mongodb').MongoClient\n , format = require('util').format; \n\n MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {\n if(err) throw err;\n \n db.collection('test').insert({hello: 'world'}, {w:1}, function(err, objects) {\n if (err) console.warn(err.message);\n if (err && err.message.indexOf('E11000 ') !== -1) {\n // this _id was already inserted in the database\n }\n });\n });\n```\n\nNote that there's no reason to pass a callback to the insert or update commands\nunless you use the `safe:true` option. If you don't specify `safe:true`, then\nyour callback will be called immediately.\n\nUpdate; update and insert (upsert)\n----------------------------------\n\nThe update operation will update the first document that matches your query\n(or all documents that match if you use `multi:true`).\nIf `safe:true`, `upsert` is not set, and no documents match, your callback will return 0 documents updated.\n\nSee the [MongoDB docs](http://www.mongodb.org/display/DOCS/Updating) for\nthe modifier (`$inc`, `$set`, `$push`, etc.) formats.\n\nSignature:\n\n```javascript\n collection.update(criteria, objNew, options, [callback]);\n```\n\nUseful options:\n\n* `safe:true` Should always set if you have a callback.\n* `multi:true` If set, all matching documents are updated, not just the first.\n* `upsert:true` Atomically inserts the document if no documents matched.\n\nExample for `update`:\n\n```javascript\n var MongoClient = require('mongodb').MongoClient\n , format = require('util').format; \n\n MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {\n if(err) throw err;\n\n db.collection('test').update({hi: 'here'}, {$set: {hi: 'there'}}, {w:1}, function(err) {\n if (err) console.warn(err.message);\n else console.log('successfully updated');\n });\n });\n```\n\nFind and modify\n---------------\n\n`findAndModify` is like `update`, but it also gives the updated document to\nyour callback. But there are a few key differences between findAndModify and\nupdate:\n\n 1. The signatures differ.\n 2. You can only findAndModify a single item, not multiple items.\n\nSignature:\n\n```javascript\n collection.findAndModify(query, sort, update, options, callback)\n```\n\nThe sort parameter is used to specify which object to operate on, if more than\none document matches. It takes the same format as the cursor sort (see\nConnection.find above).\n\nSee the\n[MongoDB docs for findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command)\nfor more details.\n\nUseful options:\n\n* `remove:true` set to a true to remove the object before returning\n* `new:true` set to true if you want to return the modified object rather than the original. Ignored for remove.\n* `upsert:true` Atomically inserts the document if no documents matched.\n\nExample for `findAndModify`:\n\n```javascript\n var MongoClient = require('mongodb').MongoClient\n , format = require('util').format; \n\n MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {\n if(err) throw err;\n db.collection('test').findAndModify({hello: 'world'}, [['_id','asc']], {$set: {hi: 'there'}}, {}, function(err, object) {\n if (err) console.warn(err.message);\n else console.dir(object); // undefined if no matching object exists.\n });\n });\n```\n\nSave\n----\n\nThe `save` method is a shorthand for upsert if the document contains an\n`_id`, or an insert if there is no `_id`.\n\nSponsors\n========\nJust as Felix Geisendörfer I'm also working on the driver for my own startup and this driver is a big project that also benefits other companies who are using MongoDB.\n\nIf your company could benefit from a even better-engineered node.js mongodb driver I would appreciate any type of sponsorship you may be able to provide. All the sponsors will get a lifetime display in this readme, priority support and help on problems and votes on the roadmap decisions for the driver. If you are interested contact me on [christkv AT g m a i l.com](mailto:christkv@gmail.com) for details.\n\nAnd I'm very thankful for code contributions. If you are interested in working on features please contact me so we can discuss API design and testing.\n\nRelease Notes\n=============\n\nSee HISTORY\n\nCredits\n=======\n\n1. [10gen](http://github.com/mongodb/mongo-ruby-driver/)\n2. [Google Closure Library](http://code.google.com/closure/library/)\n3. [Jonas Raoni Soares Silva](http://jsfromhell.com/classes/binary-parser)\n\nContributors\n============\n\nAaron Heckmann, Christoph Pojer, Pau Ramon Revilla, Nathan White, Emmerman, Seth LaForge, Boris Filipov, Stefan Schärmeli, Tedde Lundgren, renctan, Sergey Ukustov, Ciaran Jessup, kuno, srimonti, Erik Abele, Pratik Daga, Slobodan Utvic, Kristina Chodorow, Yonathan Randolph, Brian Noguchi, Sam Epstein, James Harrison Fisher, Vladimir Dronnikov, Ben Hockey, Henrik Johansson, Simon Weare, Alex Gorbatchev, Shimon Doodkin, Kyle Mueller, Eran Hammer-Lahav, Marcin Ciszak, François de Metz, Vinay Pulim, nstielau, Adam Wiggins, entrinzikyl, Jeremy Selier, Ian Millington, Public Keating, andrewjstone, Christopher Stott, Corey Jewett, brettkiefer, Rob Holland, Senmiao Liu, heroic, gitfy\n\nLicense\n=======\n\n Copyright 2009 - 2012 Christian Amor Kvalheim.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n", + "readmeFilename": "Readme.md", + "_id": "mongodb@1.3.19", + "dist": { + "shasum": "4fb60e8c55e90675835d61e5d1e1ffa269458958" + }, + "_from": "mongodb@1.3.19", + "_resolved": "https://registry.npmjs.org/mongodb/-/mongodb-1.3.19.tgz" +} diff --git a/node_modules/mongoose/node_modules/mongodb/t.js b/node_modules/mongoose/node_modules/mongodb/t.js new file mode 100644 index 0000000..77b48b6 --- /dev/null +++ b/node_modules/mongoose/node_modules/mongodb/t.js @@ -0,0 +1,147 @@ +var mongodb = require('./lib/mongodb'); + +var mongoserver = new mongodb.Server('localhost', 27017, {}); +var db_conn = new mongodb.Db('test1', mongoserver, { w : 1 }); + +db_conn.on('open', function () { + console.log("this is an open event"); +}); + +db_conn.on('close', function () { + console.log("this is a close event"); +}); + +db_conn.on('reconnect', function () { + console.log("this is a reconnect event"); +}); + +db_conn.open(function (err) { + if (err) throw err; + + var col = db_conn.collection('test'); + + var count = 0; + // Run a simple 'find' query every second + setInterval(function() { + col.findOne(function(err, item) { + if (err) { + return console.log("mongodb query not ok %d", count) + } + console.log("mongodb query ok %d", count); + count++; + }) + if (count == 40) { + db_conn.close(); + } + }, 1000) + console.log('hi'); +}); + +// var MongoClient = require('./lib/mongodb').MongoClient +// , Server = require('./lib/mongodb').Server +// , ReplSet = require('./lib/mongodb').ReplSet +// , Db = require('./lib/mongodb').Db; +// var format = require('util').format; + +// var host = process.env['MONGO_NODE_DRIVER_HOST'] || 'localhost'; +// var port = process.env['MONGO_NODE_DRIVER_PORT'] || 27017; +// var url = format("mongodb://%s:%s,%s:%s,%s:%s/node-mongo-examples" +// , host, port, host, 27018, host, 27019); +// var url = "mongodb://localhost:27017/node-mongo-examples" +// // console.dir(url) + +// // MongoClient.connect(url, function(err, db) { +// // new Db("node-mongo-examples", new Server("localhost", 27017), {w:1}).open(function(err, db) { +// var replSet = new ReplSet([new Server("localhost", 31000) +// , new Server("localhost", 31001) +// , new Server("localhost", 31002)]) +// new Db("node-mongo-examples", replSet, {safe:true}).open(function(err, db) { +// if(err) throw err; +// console.log("=========================== 0") +// db.close(); +// }); + +// // console.log("------------------------- 0") + +// // db.on('error', function(err, db) { +// // console.log("---------------------- GOT ERROR") +// // console.dir(err) +// // db.close(function() { +// // console.log("----------------- error") +// // process.exit(1); +// // }) +// // }); +// // // throw new Error("3") + +// // console.log('connected'); + +// // db.collection('t').findOne(function(err, result) { +// // console.log("33333") +// // throw new Error("3") +// // }) + +// // thisMethodDoesNotExists('foo', 'bar', 123); + +// process.on("uncaughtException", function(err) { +// console.log("######################") +// }) + +// // var now; +// // var obj, i; +// // var count = 10000000; +// // var key = 'key'; + +// // obj = {}; +// // now = Date.now(); +// // for (i = 0; i < count; i++) { +// // obj[key] = 1; +// // obj[key] = null; +// // } +// // console.log('null assignment(`obj[key] = null`):\n %d ms', Date.now() - now); + +// // obj = {}; +// // now = Date.now(); +// // for (i = 0; i < count; i++) { +// // obj[key] = 1; +// // delete obj[key]; +// // } +// // console.log('deleting property(`delete obj[key]`):\n %d ms', Date.now() - now); + +// // // var mongodb = require('./lib/mongodb'); + +// // // // var url = 'mongodb://user:pass@host1,host2,host3/db'; +// // // var url = 'mongodb://127.0.0.1:31000,192.168.2.173:31001,127.0.0.1:31002/test'; +// // // var options = {db: {safe: true}, server: {auto_reconnect: true}}; + +// // // mongodb.connect(url, options, function (err, db) { +// // // if (err) { +// // // console.log(err); +// // // process.exit(1); +// // // } + +// // // db.collection('test', function (err, c) { +// // // if (err) { +// // // console.log(err); +// // // process.exit(2); +// // // } + +// // // var successCount = 0; +// // // var errCount = 0; +// // // var lastErr = null; +// // // setInterval(function () { +// // // c.find({}).limit(100).toArray(function (err, results) { +// // // if (err) { +// // // lastErr = err; +// // // errCount++; +// // // } else { +// // // successCount++; +// // // } +// // // }); +// // // }, 100); + +// // // setInterval(function () { +// // // console.log("STATUS", successCount, errCount); +// // // }, 1000); + +// // // }); +// // // }); \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mpath/.npmignore b/node_modules/mongoose/node_modules/mpath/.npmignore new file mode 100644 index 0000000..be106ca --- /dev/null +++ b/node_modules/mongoose/node_modules/mpath/.npmignore @@ -0,0 +1,2 @@ +*.sw* +node_modules/ diff --git a/node_modules/mongoose/node_modules/mpath/.travis.yml b/node_modules/mongoose/node_modules/mpath/.travis.yml new file mode 100644 index 0000000..09c230f --- /dev/null +++ b/node_modules/mongoose/node_modules/mpath/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.6 + - 0.8 diff --git a/node_modules/mongoose/node_modules/mpath/History.md b/node_modules/mongoose/node_modules/mpath/History.md new file mode 100644 index 0000000..4fbf338 --- /dev/null +++ b/node_modules/mongoose/node_modules/mpath/History.md @@ -0,0 +1,16 @@ + +0.1.1 / 2012-12-21 +================== + + * added; map support + +0.1.0 / 2012-12-13 +================== + + * added; set('array.property', val, object) support + * added; get('array.property', object) support + +0.0.1 / 2012-11-03 +================== + + * initial release diff --git a/node_modules/mongoose/node_modules/mpath/LICENSE b/node_modules/mongoose/node_modules/mpath/LICENSE new file mode 100644 index 0000000..38c529d --- /dev/null +++ b/node_modules/mongoose/node_modules/mpath/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2012 [Aaron Heckmann](aaron.heckmann+github@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/mongoose/node_modules/mpath/Makefile b/node_modules/mongoose/node_modules/mpath/Makefile new file mode 100644 index 0000000..b0bb081 --- /dev/null +++ b/node_modules/mongoose/node_modules/mpath/Makefile @@ -0,0 +1,5 @@ + +test: + @node_modules/mocha/bin/mocha -A $(T) + +.PHONY: test diff --git a/node_modules/mongoose/node_modules/mpath/README.md b/node_modules/mongoose/node_modules/mpath/README.md new file mode 100644 index 0000000..9831dd0 --- /dev/null +++ b/node_modules/mongoose/node_modules/mpath/README.md @@ -0,0 +1,278 @@ +#mpath + +{G,S}et javascript object values using MongoDB-like path notation. + +###Getting + +```js +var mpath = require('mpath'); + +var obj = { + comments: [ + { title: 'funny' }, + { title: 'exciting!' } + ] +} + +mpath.get('comments.1.title', obj) // 'exciting!' +``` + +`mpath.get` supports array property notation as well. + +```js +var obj = { + comments: [ + { title: 'funny' }, + { title: 'exciting!' } + ] +} + +mpath.get('comments.title', obj) // ['funny', 'exciting!'] +``` + +Array property and indexing syntax, when used together, are very powerful. + +```js +var obj = { + array: [ + { o: { array: [{x: {b: [4,6,8]}}, { y: 10} ] }} + , { o: { array: [{x: {b: [1,2,3]}}, { x: {z: 10 }}, { x: 'Turkey Day' }] }} + , { o: { array: [{x: {b: null }}, { x: { b: [null, 1]}}] }} + , { o: { array: [{x: null }] }} + , { o: { array: [{y: 3 }] }} + , { o: { array: [3, 0, null] }} + , { o: { name: 'ha' }} + ]; +} + +var found = mpath.get('array.o.array.x.b.1', obj); + +console.log(found); // prints.. + + [ [6, undefined] + , [2, undefined, undefined] + , [null, 1] + , [null] + , [undefined] + , [undefined, undefined, undefined] + , undefined + ] + +``` + +#####Field selection rules: + +The following rules are iteratively applied to each `segment` in the passed `path`. For example: + +```js +var path = 'one.two.14'; // path +'one' // segment 0 +'two' // segment 1 +14 // segment 2 +``` + +- 1) when value of the segment parent is not an array, return the value of `parent.segment` +- 2) when value of the segment parent is an array + - a) if the segment is an integer, replace the parent array with the value at `parent[segment]` + - b) if not an integer, keep the array but replace each array `item` with the value returned from calling `get(remainingSegments, item)` or undefined if falsey. + +#####Maps + +`mpath.get` also accepts an optional `map` argument which receives each individual found value. The value returned from the `map` function will be used in the original found values place. + +```js +var obj = { + comments: [ + { title: 'funny' }, + { title: 'exciting!' } + ] +} + +mpath.get('comments.title', obj, function (val) { + return 'funny' == val + ? 'amusing' + : val; +}); +// ['amusing', 'exciting!'] +``` + +###Setting + +```js +var obj = { + comments: [ + { title: 'funny' }, + { title: 'exciting!' } + ] +} + +mpath.set('comments.1.title', 'hilarious', obj) +console.log(obj.comments[1].title) // 'hilarious' +``` + +`mpath.set` supports the same array property notation as `mpath.get`. + +```js +var obj = { + comments: [ + { title: 'funny' }, + { title: 'exciting!' } + ] +} + +mpath.set('comments.title', ['hilarious', 'fruity'], obj); + +console.log(obj); // prints.. + + { comments: [ + { title: 'hilarious' }, + { title: 'fruity' } + ]} +``` + +Array property and indexing syntax can be used together also when setting. + +```js +var obj = { + array: [ + { o: { array: [{x: {b: [4,6,8]}}, { y: 10} ] }} + , { o: { array: [{x: {b: [1,2,3]}}, { x: {z: 10 }}, { x: 'Turkey Day' }] }} + , { o: { array: [{x: {b: null }}, { x: { b: [null, 1]}}] }} + , { o: { array: [{x: null }] }} + , { o: { array: [{y: 3 }] }} + , { o: { array: [3, 0, null] }} + , { o: { name: 'ha' }} + ] +} + +mpath.set('array.1.o', 'this was changed', obj); + +console.log(require('util').inspect(obj, false, 1000)); // prints.. + +{ + array: [ + { o: { array: [{x: {b: [4,6,8]}}, { y: 10} ] }} + , { o: 'this was changed' } + , { o: { array: [{x: {b: null }}, { x: { b: [null, 1]}}] }} + , { o: { array: [{x: null }] }} + , { o: { array: [{y: 3 }] }} + , { o: { array: [3, 0, null] }} + , { o: { name: 'ha' }} + ]; +} + +mpath.set('array.o.array.x', 'this was changed too', obj); + +console.log(require('util').inspect(obj, false, 1000)); // prints.. + +{ + array: [ + { o: { array: [{x: 'this was changed too'}, { y: 10, x: 'this was changed too'} ] }} + , { o: 'this was changed' } + , { o: { array: [{x: 'this was changed too'}, { x: 'this was changed too'}] }} + , { o: { array: [{x: 'this was changed too'}] }} + , { o: { array: [{x: 'this was changed too', y: 3 }] }} + , { o: { array: [3, 0, null] }} + , { o: { name: 'ha' }} + ]; +} +``` + +####Setting arrays + +By default, setting a property within an array to another array results in each element of the new array being set to the item in the destination array at the matching index. An example is helpful. + +```js +var obj = { + comments: [ + { title: 'funny' }, + { title: 'exciting!' } + ] +} + +mpath.set('comments.title', ['hilarious', 'fruity'], obj); + +console.log(obj); // prints.. + + { comments: [ + { title: 'hilarious' }, + { title: 'fruity' } + ]} +``` + +If we do not desire this destructuring-like assignment behavior we may instead specify the `$` operator in the path being set to force the array to be copied directly. + +```js +var obj = { + comments: [ + { title: 'funny' }, + { title: 'exciting!' } + ] +} + +mpath.set('comments.$.title', ['hilarious', 'fruity'], obj); + +console.log(obj); // prints.. + + { comments: [ + { title: ['hilarious', 'fruity'] }, + { title: ['hilarious', 'fruity'] } + ]} +``` + +####Field assignment rules + +The rules utilized mirror those used on `mpath.get`, meaning we can take values returned from `mpath.get`, update them, and reassign them using `mpath.set`. Note that setting nested arrays of arrays can get unweildy quickly. Check out the [tests](https://github.com/aheckmann/mpath/blob/master/test/index.js) for more extreme examples. + +#####Maps + +`mpath.set` also accepts an optional `map` argument which receives each individual value being set. The value returned from the `map` function will be used in the original values place. + +```js +var obj = { + comments: [ + { title: 'funny' }, + { title: 'exciting!' } + ] +} + +mpath.set('comments.title', ['hilarious', 'fruity'], obj, function (val) { + return val.length; +}); + +console.log(obj); // prints.. + + { comments: [ + { title: 9 }, + { title: 6 } + ]} +``` + +### Custom object types + +Sometimes you may want to enact the same functionality on custom object types that store all their real data internally, say for an ODM type object. No fear, `mpath` has you covered. Simply pass the name of the property being used to store the internal data and it will be traversed instead: + +```js +var mpath = require('mpath'); + +var obj = { + comments: [ + { title: 'exciting!', _doc: { title: 'great!' }} + ] +} + +mpath.get('comments.0.title', obj, '_doc') // 'great!' +mpath.set('comments.0.title', 'nov 3rd', obj, '_doc') +mpath.get('comments.0.title', obj, '_doc') // 'nov 3rd' +mpath.get('comments.0.title', obj) // 'exciting' +``` + +When used with a `map`, the `map` argument comes last. + +```js +mpath.get(path, obj, '_doc', map); +mpath.set(path, val, obj, '_doc', map); +``` + +[LICENSE](https://github.com/aheckmann/mpath/blob/master/LICENSE) + diff --git a/node_modules/mongoose/node_modules/mpath/index.js b/node_modules/mongoose/node_modules/mpath/index.js new file mode 100644 index 0000000..f7b65dd --- /dev/null +++ b/node_modules/mongoose/node_modules/mpath/index.js @@ -0,0 +1 @@ +module.exports = exports = require('./lib'); diff --git a/node_modules/mongoose/node_modules/mpath/lib/index.js b/node_modules/mongoose/node_modules/mpath/lib/index.js new file mode 100644 index 0000000..24e1e83 --- /dev/null +++ b/node_modules/mongoose/node_modules/mpath/lib/index.js @@ -0,0 +1,183 @@ + +/** + * Returns the value of object `o` at the given `path`. + * + * ####Example: + * + * var obj = { + * comments: [ + * { title: 'exciting!', _doc: { title: 'great!' }} + * , { title: 'number dos' } + * ] + * } + * + * mpath.get('comments.0.title', o) // 'exciting!' + * mpath.get('comments.0.title', o, '_doc') // 'great!' + * mpath.get('comments.title', o) // ['exciting!', 'number dos'] + * + * // summary + * mpath.get(path, o) + * mpath.get(path, o, special) + * mpath.get(path, o, map) + * mpath.get(path, o, special, map) + * + * @param {String} path + * @param {Object} o + * @param {String} [special] When this property name is present on any object in the path, walking will continue on the value of this property. + * @param {Function} [map] Optional function which receives each individual found value. The value returned from `map` is used in the original values place. + */ + +exports.get = function (path, o, special, map) { + if ('function' == typeof special) { + map = special; + special = undefined; + } + + map || (map = K); + + var parts = 'string' == typeof path + ? path.split('.') + : path + + if (!Array.isArray(parts)) { + throw new TypeError('Invalid `path`. Must be either string or array'); + } + + var obj = o + , part; + + for (var i = 0; i < parts.length; ++i) { + part = parts[i]; + + if (Array.isArray(obj) && !/^\d+$/.test(part)) { + // reading a property from the array items + var paths = parts.slice(i); + + return obj.map(function (item) { + return item + ? exports.get(paths, item, special, map) + : map(undefined); + }); + } + + obj = special && obj[special] + ? obj[special][part] + : obj[part]; + + if (!obj) return map(obj); + } + + return map(obj); +} + +/** + * Sets the `val` at the given `path` of object `o`. + * + * @param {String} path + * @param {Anything} val + * @param {Object} o + * @param {String} [special] When this property name is present on any object in the path, walking will continue on the value of this property. + * @param {Function} [map] Optional function which is passed each individual value before setting it. The value returned from `map` is used in the original values place. + + */ + +exports.set = function (path, val, o, special, map, _copying) { + if ('function' == typeof special) { + map = special; + special = undefined; + } + + map || (map = K); + + var parts = 'string' == typeof path + ? path.split('.') + : path + + if (!Array.isArray(parts)) { + throw new TypeError('Invalid `path`. Must be either string or array'); + } + + if (null == o) return; + + // the existance of $ in a path tells us if the user desires + // the copying of an array instead of setting each value of + // the array to the one by one to matching positions of the + // current array. + var copy = _copying || /\$/.test(path) + , obj = o + , part + + for (var i = 0, len = parts.length - 1; i < len; ++i) { + part = parts[i]; + + if ('$' == part) { + if (i == len - 1) { + break; + } else { + continue; + } + } + + if (Array.isArray(obj) && !/^\d+$/.test(part)) { + var paths = parts.slice(i); + if (!copy && Array.isArray(val)) { + for (var j = 0; j < obj.length && j < val.length; ++j) { + // assignment of single values of array + exports.set(paths, val[j], obj[j], special, map, copy); + } + } else { + for (var j = 0; j < obj.length; ++j) { + // assignment of entire value + exports.set(paths, val, obj[j], special, map, copy); + } + } + return; + } + + obj = special && obj[special] + ? obj[special][part] + : obj[part]; + + if (!obj) return; + } + + // process the last property of the path + + part = parts[len]; + + // use the special property if exists + if (special && obj[special]) { + obj = obj[special]; + } + + // set the value on the last branch + if (Array.isArray(obj) && !/^\d+$/.test(part)) { + if (!copy && Array.isArray(val)) { + for (var item, j = 0; j < obj.length && j < val.length; ++j) { + item = obj[j]; + if (item) { + if (item[special]) item = item[special]; + item[part] = map(val[j]); + } + } + } else { + for (var j = 0; j < obj.length; ++j) { + item = obj[j]; + if (item) { + if (item[special]) item = item[special]; + item[part] = map(val); + } + } + } + } else { + obj[part] = map(val); + } +} + +/*! + * Returns the value passed to it. + */ + +function K (v) { + return v; +} diff --git a/node_modules/mongoose/node_modules/mpath/package.json b/node_modules/mongoose/node_modules/mpath/package.json new file mode 100644 index 0000000..5748f81 --- /dev/null +++ b/node_modules/mongoose/node_modules/mpath/package.json @@ -0,0 +1,38 @@ +{ + "name": "mpath", + "version": "0.1.1", + "description": "{G,S}et object values using MongoDB path notation", + "main": "index.js", + "scripts": { + "test": "make test" + }, + "repository": { + "type": "git", + "url": "git://github.com/aheckmann/mpath.git" + }, + "keywords": [ + "mongodb", + "path", + "get", + "set" + ], + "author": { + "name": "Aaron Heckmann", + "email": "aaron.heckmann+github@gmail.com" + }, + "license": "MIT", + "devDependencies": { + "mocha": "1.6.0" + }, + "readme": "#mpath\n\n{G,S}et javascript object values using MongoDB-like path notation.\n\n###Getting\n\n```js\nvar mpath = require('mpath');\n\nvar obj = {\n comments: [\n { title: 'funny' },\n { title: 'exciting!' }\n ]\n}\n\nmpath.get('comments.1.title', obj) // 'exciting!'\n```\n\n`mpath.get` supports array property notation as well.\n\n```js\nvar obj = {\n comments: [\n { title: 'funny' },\n { title: 'exciting!' }\n ]\n}\n\nmpath.get('comments.title', obj) // ['funny', 'exciting!']\n```\n\nArray property and indexing syntax, when used together, are very powerful.\n\n```js\nvar obj = {\n array: [\n { o: { array: [{x: {b: [4,6,8]}}, { y: 10} ] }}\n , { o: { array: [{x: {b: [1,2,3]}}, { x: {z: 10 }}, { x: 'Turkey Day' }] }}\n , { o: { array: [{x: {b: null }}, { x: { b: [null, 1]}}] }}\n , { o: { array: [{x: null }] }}\n , { o: { array: [{y: 3 }] }}\n , { o: { array: [3, 0, null] }}\n , { o: { name: 'ha' }}\n ];\n}\n\nvar found = mpath.get('array.o.array.x.b.1', obj);\n\nconsole.log(found); // prints..\n\n [ [6, undefined]\n , [2, undefined, undefined]\n , [null, 1]\n , [null]\n , [undefined]\n , [undefined, undefined, undefined]\n , undefined\n ]\n\n```\n\n#####Field selection rules:\n\nThe following rules are iteratively applied to each `segment` in the passed `path`. For example:\n\n```js\nvar path = 'one.two.14'; // path\n'one' // segment 0\n'two' // segment 1\n14 // segment 2\n```\n\n- 1) when value of the segment parent is not an array, return the value of `parent.segment`\n- 2) when value of the segment parent is an array\n - a) if the segment is an integer, replace the parent array with the value at `parent[segment]`\n - b) if not an integer, keep the array but replace each array `item` with the value returned from calling `get(remainingSegments, item)` or undefined if falsey.\n\n#####Maps\n\n`mpath.get` also accepts an optional `map` argument which receives each individual found value. The value returned from the `map` function will be used in the original found values place.\n\n```js\nvar obj = {\n comments: [\n { title: 'funny' },\n { title: 'exciting!' }\n ]\n}\n\nmpath.get('comments.title', obj, function (val) {\n return 'funny' == val\n ? 'amusing'\n : val;\n});\n// ['amusing', 'exciting!']\n```\n\n###Setting\n\n```js\nvar obj = {\n comments: [\n { title: 'funny' },\n { title: 'exciting!' }\n ]\n}\n\nmpath.set('comments.1.title', 'hilarious', obj)\nconsole.log(obj.comments[1].title) // 'hilarious'\n```\n\n`mpath.set` supports the same array property notation as `mpath.get`.\n\n```js\nvar obj = {\n comments: [\n { title: 'funny' },\n { title: 'exciting!' }\n ]\n}\n\nmpath.set('comments.title', ['hilarious', 'fruity'], obj);\n\nconsole.log(obj); // prints..\n\n { comments: [\n { title: 'hilarious' },\n { title: 'fruity' }\n ]}\n```\n\nArray property and indexing syntax can be used together also when setting.\n\n```js\nvar obj = {\n array: [\n { o: { array: [{x: {b: [4,6,8]}}, { y: 10} ] }}\n , { o: { array: [{x: {b: [1,2,3]}}, { x: {z: 10 }}, { x: 'Turkey Day' }] }}\n , { o: { array: [{x: {b: null }}, { x: { b: [null, 1]}}] }}\n , { o: { array: [{x: null }] }}\n , { o: { array: [{y: 3 }] }}\n , { o: { array: [3, 0, null] }}\n , { o: { name: 'ha' }}\n ]\n}\n\nmpath.set('array.1.o', 'this was changed', obj);\n\nconsole.log(require('util').inspect(obj, false, 1000)); // prints..\n\n{\n array: [\n { o: { array: [{x: {b: [4,6,8]}}, { y: 10} ] }}\n , { o: 'this was changed' }\n , { o: { array: [{x: {b: null }}, { x: { b: [null, 1]}}] }}\n , { o: { array: [{x: null }] }}\n , { o: { array: [{y: 3 }] }}\n , { o: { array: [3, 0, null] }}\n , { o: { name: 'ha' }}\n ];\n}\n\nmpath.set('array.o.array.x', 'this was changed too', obj);\n\nconsole.log(require('util').inspect(obj, false, 1000)); // prints..\n\n{\n array: [\n { o: { array: [{x: 'this was changed too'}, { y: 10, x: 'this was changed too'} ] }}\n , { o: 'this was changed' }\n , { o: { array: [{x: 'this was changed too'}, { x: 'this was changed too'}] }}\n , { o: { array: [{x: 'this was changed too'}] }}\n , { o: { array: [{x: 'this was changed too', y: 3 }] }}\n , { o: { array: [3, 0, null] }}\n , { o: { name: 'ha' }}\n ];\n}\n```\n\n####Setting arrays\n\nBy default, setting a property within an array to another array results in each element of the new array being set to the item in the destination array at the matching index. An example is helpful.\n\n```js\nvar obj = {\n comments: [\n { title: 'funny' },\n { title: 'exciting!' }\n ]\n}\n\nmpath.set('comments.title', ['hilarious', 'fruity'], obj);\n\nconsole.log(obj); // prints..\n\n { comments: [\n { title: 'hilarious' },\n { title: 'fruity' }\n ]}\n```\n\nIf we do not desire this destructuring-like assignment behavior we may instead specify the `$` operator in the path being set to force the array to be copied directly.\n\n```js\nvar obj = {\n comments: [\n { title: 'funny' },\n { title: 'exciting!' }\n ]\n}\n\nmpath.set('comments.$.title', ['hilarious', 'fruity'], obj);\n\nconsole.log(obj); // prints..\n\n { comments: [\n { title: ['hilarious', 'fruity'] },\n { title: ['hilarious', 'fruity'] }\n ]}\n```\n\n####Field assignment rules\n\nThe rules utilized mirror those used on `mpath.get`, meaning we can take values returned from `mpath.get`, update them, and reassign them using `mpath.set`. Note that setting nested arrays of arrays can get unweildy quickly. Check out the [tests](https://github.com/aheckmann/mpath/blob/master/test/index.js) for more extreme examples.\n\n#####Maps\n\n`mpath.set` also accepts an optional `map` argument which receives each individual value being set. The value returned from the `map` function will be used in the original values place.\n\n```js\nvar obj = {\n comments: [\n { title: 'funny' },\n { title: 'exciting!' }\n ]\n}\n\nmpath.set('comments.title', ['hilarious', 'fruity'], obj, function (val) {\n return val.length;\n});\n\nconsole.log(obj); // prints..\n\n { comments: [\n { title: 9 },\n { title: 6 }\n ]}\n```\n\n### Custom object types\n\nSometimes you may want to enact the same functionality on custom object types that store all their real data internally, say for an ODM type object. No fear, `mpath` has you covered. Simply pass the name of the property being used to store the internal data and it will be traversed instead:\n\n```js\nvar mpath = require('mpath');\n\nvar obj = {\n comments: [\n { title: 'exciting!', _doc: { title: 'great!' }}\n ]\n}\n\nmpath.get('comments.0.title', obj, '_doc') // 'great!'\nmpath.set('comments.0.title', 'nov 3rd', obj, '_doc')\nmpath.get('comments.0.title', obj, '_doc') // 'nov 3rd'\nmpath.get('comments.0.title', obj) // 'exciting'\n```\n\nWhen used with a `map`, the `map` argument comes last.\n\n```js\nmpath.get(path, obj, '_doc', map);\nmpath.set(path, val, obj, '_doc', map);\n```\n\n[LICENSE](https://github.com/aheckmann/mpath/blob/master/LICENSE)\n\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/aheckmann/mpath/issues" + }, + "_id": "mpath@0.1.1", + "dist": { + "shasum": "0cf795b1f8f3002e22017a6756e8bce3964f8126" + }, + "_from": "mpath@0.1.1", + "_resolved": "https://registry.npmjs.org/mpath/-/mpath-0.1.1.tgz" +} diff --git a/node_modules/mongoose/node_modules/mpath/test/index.js b/node_modules/mongoose/node_modules/mpath/test/index.js new file mode 100644 index 0000000..98e119a --- /dev/null +++ b/node_modules/mongoose/node_modules/mpath/test/index.js @@ -0,0 +1,1630 @@ + +/** + * Test dependencies. + */ + +var mpath = require('../') +var assert = require('assert') + +/** + * logging helper + */ + +function log (o) { + console.log(); + console.log(require('util').inspect(o, false, 1000)); +} + +/** + * special path for override tests + */ + +var special = '_doc'; + +/** + * Tests + */ + +describe('mpath', function(){ + + /** + * test doc creator + */ + + function doc () { + var o = { first: { second: { third: [3,{ name: 'aaron' }, 9] }}}; + o.comments = [ + { name: 'one' } + , { name: 'two', _doc: { name: '2' }} + , { name: 'three' + , comments: [{},{ comments: [{val: 'twoo'}]}] + , _doc: { name: '3', comments: [{},{ _doc: { comments: [{ val: 2 }] }}] }} + ]; + o.name = 'jiro'; + o.array = [ + { o: { array: [{x: {b: [4,6,8]}}, { y: 10} ] }} + , { o: { array: [{x: {b: [1,2,3]}}, { x: {z: 10 }}, { x: {b: 'hi'}}] }} + , { o: { array: [{x: {b: null }}, { x: { b: [null, 1]}}] }} + , { o: { array: [{x: null }] }} + , { o: { array: [{y: 3 }] }} + , { o: { array: [3, 0, null] }} + , { o: { name: 'ha' }} + ]; + o.arr = [ + { arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: true } + ] + return o; + } + + describe('get', function(){ + var o = doc(); + + it('`path` must be a string or array', function(done){ + assert.throws(function () { + mpath.get({}, o); + }, /Must be either string or array/); + assert.throws(function () { + mpath.get(4, o); + }, /Must be either string or array/); + assert.throws(function () { + mpath.get(function(){}, o); + }, /Must be either string or array/); + assert.throws(function () { + mpath.get(/asdf/, o); + }, /Must be either string or array/); + assert.throws(function () { + mpath.get(Math, o); + }, /Must be either string or array/); + assert.throws(function () { + mpath.get(Buffer, o); + }, /Must be either string or array/); + assert.doesNotThrow(function () { + mpath.get('string', o); + }); + assert.doesNotThrow(function () { + mpath.get([], o); + }); + done(); + }) + + describe('without `special`', function(){ + it('works', function(done){ + assert.equal('jiro', mpath.get('name', o)); + + assert.deepEqual( + { second: { third: [3,{ name: 'aaron' }, 9] }} + , mpath.get('first', o) + ); + + assert.deepEqual( + { third: [3,{ name: 'aaron' }, 9] } + , mpath.get('first.second', o) + ); + + assert.deepEqual( + [3,{ name: 'aaron' }, 9] + , mpath.get('first.second.third', o) + ); + + assert.deepEqual( + 3 + , mpath.get('first.second.third.0', o) + ); + + assert.deepEqual( + 9 + , mpath.get('first.second.third.2', o) + ); + + assert.deepEqual( + { name: 'aaron' } + , mpath.get('first.second.third.1', o) + ); + + assert.deepEqual( + 'aaron' + , mpath.get('first.second.third.1.name', o) + ); + + assert.deepEqual([ + { name: 'one' } + , { name: 'two', _doc: { name: '2' }} + , { name: 'three' + , comments: [{},{ comments: [{val: 'twoo'}]}] + , _doc: { name: '3', comments: [{},{ _doc: { comments: [{ val: 2 }] }}]}}], + mpath.get('comments', o)); + + assert.deepEqual({ name: 'one' }, mpath.get('comments.0', o)); + assert.deepEqual('one', mpath.get('comments.0.name', o)); + assert.deepEqual('two', mpath.get('comments.1.name', o)); + assert.deepEqual('three', mpath.get('comments.2.name', o)); + + assert.deepEqual([{},{ comments: [{val: 'twoo'}]}] + , mpath.get('comments.2.comments', o)); + + assert.deepEqual({ comments: [{val: 'twoo'}]} + , mpath.get('comments.2.comments.1', o)); + + assert.deepEqual('twoo', mpath.get('comments.2.comments.1.comments.0.val', o)); + + done(); + }) + + it('handles array.property dot-notation', function(done){ + assert.deepEqual( + ['one', 'two', 'three'] + , mpath.get('comments.name', o) + ); + done(); + }) + + it('handles array.array notation', function(done){ + assert.deepEqual( + [undefined, undefined, [{}, {comments:[{val:'twoo'}]}]] + , mpath.get('comments.comments', o) + ); + done(); + }) + + it('handles prop.prop.prop.arrayProperty notation', function(done){ + assert.deepEqual( + [undefined, 'aaron', undefined] + , mpath.get('first.second.third.name', o) + ); + assert.deepEqual( + [1, 'aaron', 1] + , mpath.get('first.second.third.name', o, function (v) { + return undefined === v ? 1 : v; + }) + ); + done(); + }) + + it('handles array.prop.array', function(done){ + assert.deepEqual( + [ [{x: {b: [4,6,8]}}, { y: 10} ] + , [{x: {b: [1,2,3]}}, { x: {z: 10 }}, { x: {b: 'hi'}}] + , [{x: {b: null }}, { x: { b: [null, 1]}}] + , [{x: null }] + , [{y: 3 }] + , [3, 0, null] + , undefined + ] + , mpath.get('array.o.array', o) + ); + done(); + }) + + it('handles array.prop.array.index', function(done){ + assert.deepEqual( + [ {x: {b: [4,6,8]}} + , {x: {b: [1,2,3]}} + , {x: {b: null }} + , {x: null } + , {y: 3 } + , 3 + , undefined + ] + , mpath.get('array.o.array.0', o) + ); + done(); + }) + + it('handles array.prop.array.index.prop', function(done){ + assert.deepEqual( + [ {b: [4,6,8]} + , {b: [1,2,3]} + , {b: null } + , null + , undefined + , undefined + , undefined + ] + , mpath.get('array.o.array.0.x', o) + ); + done(); + }) + + it('handles array.prop.array.prop', function(done){ + assert.deepEqual( + [ [undefined, 10 ] + , [undefined, undefined, undefined] + , [undefined, undefined] + , [undefined] + , [3] + , [undefined, undefined, undefined] + , undefined + ] + , mpath.get('array.o.array.y', o) + ); + assert.deepEqual( + [ [{b: [4,6,8]}, undefined] + , [{b: [1,2,3]}, {z: 10 }, {b: 'hi'}] + , [{b: null }, { b: [null, 1]}] + , [null] + , [undefined] + , [undefined, undefined, undefined] + , undefined + ] + , mpath.get('array.o.array.x', o) + ); + done(); + }) + + it('handles array.prop.array.prop.prop', function(done){ + assert.deepEqual( + [ [[4,6,8], undefined] + , [[1,2,3], undefined, 'hi'] + , [null, [null, 1]] + , [null] + , [undefined] + , [undefined, undefined, undefined] + , undefined + ] + , mpath.get('array.o.array.x.b', o) + ); + done(); + }) + + it('handles array.prop.array.prop.prop.index', function(done){ + assert.deepEqual( + [ [6, undefined] + , [2, undefined, 'i'] // undocumented feature (string indexing) + , [null, 1] + , [null] + , [undefined] + , [undefined, undefined, undefined] + , undefined + ] + , mpath.get('array.o.array.x.b.1', o) + ); + assert.deepEqual( + [ [6, 0] + , [2, 0, 'i'] // undocumented feature (string indexing) + , [null, 1] + , [null] + , [0] + , [0, 0, 0] + , 0 + ] + , mpath.get('array.o.array.x.b.1', o, function (v) { + return undefined === v ? 0 : v; + }) + ); + done(); + }) + + it('handles array.index.prop.prop', function(done){ + assert.deepEqual( + [{x: {b: [1,2,3]}}, { x: {z: 10 }}, { x: {b: 'hi'}}] + , mpath.get('array.1.o.array', o) + ); + assert.deepEqual( + ['hi','hi','hi'] + , mpath.get('array.1.o.array', o, function (v) { + if (Array.isArray(v)) { + return v.map(function (val) { + return 'hi'; + }) + } + return v; + }) + ); + done(); + }) + + it('handles array.array.index', function(done){ + assert.deepEqual( + [{ a: { c: 48 }}, undefined] + , mpath.get('arr.arr.1', o) + ); + assert.deepEqual( + ['woot', undefined] + , mpath.get('arr.arr.1', o, function (v) { + if (v && v.a && v.a.c) return 'woot'; + return v; + }) + ); + done(); + }) + + it('handles array.array.index.prop', function(done){ + assert.deepEqual( + [{ c: 48 }, 'woot'] + , mpath.get('arr.arr.1.a', o, function (v) { + if (undefined === v) return 'woot'; + return v; + }) + ); + assert.deepEqual( + [{ c: 48 }, undefined] + , mpath.get('arr.arr.1.a', o) + ); + mpath.set('arr.arr.1.a', [{c:49},undefined], o) + assert.deepEqual( + [{ c: 49 }, undefined] + , mpath.get('arr.arr.1.a', o) + ); + mpath.set('arr.arr.1.a', [{c:48},undefined], o) + done(); + }) + + it('handles array.array.index.prop.prop', function(done){ + assert.deepEqual( + [48, undefined] + , mpath.get('arr.arr.1.a.c', o) + ); + assert.deepEqual( + [48, 'woot'] + , mpath.get('arr.arr.1.a.c', o, function (v) { + if (undefined === v) return 'woot'; + return v; + }) + ); + done(); + }) + + }) + + describe('with `special`', function(){ + it('works', function(done){ + assert.equal('jiro', mpath.get('name', o, special)); + + assert.deepEqual( + { second: { third: [3,{ name: 'aaron' }, 9] }} + , mpath.get('first', o, special) + ); + + assert.deepEqual( + { third: [3,{ name: 'aaron' }, 9] } + , mpath.get('first.second', o, special) + ); + + assert.deepEqual( + [3,{ name: 'aaron' }, 9] + , mpath.get('first.second.third', o, special) + ); + + assert.deepEqual( + 3 + , mpath.get('first.second.third.0', o, special) + ); + + assert.deepEqual( + 4 + , mpath.get('first.second.third.0', o, special, function (v) { + return 3 === v ? 4 : v; + }) + ); + + assert.deepEqual( + 9 + , mpath.get('first.second.third.2', o, special) + ); + + assert.deepEqual( + { name: 'aaron' } + , mpath.get('first.second.third.1', o, special) + ); + + assert.deepEqual( + 'aaron' + , mpath.get('first.second.third.1.name', o, special) + ); + + assert.deepEqual([ + { name: 'one' } + , { name: 'two', _doc: { name: '2' }} + , { name: 'three' + , comments: [{},{ comments: [{val: 'twoo'}]}] + , _doc: { name: '3', comments: [{},{ _doc: { comments: [{ val: 2 }] }}]}}], + mpath.get('comments', o, special)); + + assert.deepEqual({ name: 'one' }, mpath.get('comments.0', o, special)); + assert.deepEqual('one', mpath.get('comments.0.name', o, special)); + assert.deepEqual('2', mpath.get('comments.1.name', o, special)); + assert.deepEqual('3', mpath.get('comments.2.name', o, special)); + assert.deepEqual('nice', mpath.get('comments.2.name', o, special, function (v) { + return '3' === v ? 'nice' : v; + })); + + assert.deepEqual([{},{ _doc: { comments: [{ val: 2 }] }}] + , mpath.get('comments.2.comments', o, special)); + + assert.deepEqual({ _doc: { comments: [{val: 2}]}} + , mpath.get('comments.2.comments.1', o, special)); + + assert.deepEqual(2, mpath.get('comments.2.comments.1.comments.0.val', o, special)); + done(); + }) + + it('handles array.property dot-notation', function(done){ + assert.deepEqual( + ['one', '2', '3'] + , mpath.get('comments.name', o, special) + ); + assert.deepEqual( + ['one', 2, '3'] + , mpath.get('comments.name', o, special, function (v) { + return '2' === v ? 2 : v + }) + ); + done(); + }) + + it('handles array.array notation', function(done){ + assert.deepEqual( + [undefined, undefined, [{}, {_doc: { comments:[{val:2}]}}]] + , mpath.get('comments.comments', o, special) + ); + done(); + }) + + it('handles array.array.index.array', function(done){ + assert.deepEqual( + [undefined, undefined, [{val:2}]] + , mpath.get('comments.comments.1.comments', o, special) + ); + done(); + }) + + it('handles array.array.index.array.prop', function(done){ + assert.deepEqual( + [undefined, undefined, [2]] + , mpath.get('comments.comments.1.comments.val', o, special) + ); + assert.deepEqual( + ['nil', 'nil', [2]] + , mpath.get('comments.comments.1.comments.val', o, special, function (v) { + return undefined === v ? 'nil' : v; + }) + ); + done(); + }) + }) + + }) + + describe('set', function(){ + describe('without `special`', function(){ + var o = doc(); + + it('works', function(done){ + mpath.set('name', 'a new val', o, function (v) { + return 'a new val' === v ? 'changed' : v; + }); + assert.deepEqual('changed', o.name); + + mpath.set('name', 'changed', o); + assert.deepEqual('changed', o.name); + + mpath.set('first.second.third', [1,{name:'x'},9], o); + assert.deepEqual([1,{name:'x'},9], o.first.second.third); + + mpath.set('first.second.third.1.name', 'y', o) + assert.deepEqual([1,{name:'y'},9], o.first.second.third); + + mpath.set('comments.1.name', 'ttwwoo', o); + assert.deepEqual({ name: 'ttwwoo', _doc: { name: '2' }}, o.comments[1]); + + mpath.set('comments.2.comments.1.comments.0.expand', 'added', o); + assert.deepEqual( + { val: 'twoo', expand: 'added'} + , o.comments[2].comments[1].comments[0]); + + mpath.set('comments.2.comments.1.comments.2', 'added', o); + assert.equal(3, o.comments[2].comments[1].comments.length); + assert.deepEqual( + { val: 'twoo', expand: 'added'} + , o.comments[2].comments[1].comments[0]); + assert.deepEqual( + undefined + , o.comments[2].comments[1].comments[1]); + assert.deepEqual( + 'added' + , o.comments[2].comments[1].comments[2]); + + done(); + }) + + describe('array.path', function(){ + describe('with single non-array value', function(){ + it('works', function(done){ + mpath.set('arr.yep', false, o, function (v) { + return false === v ? true: v; + }); + assert.deepEqual([ + { yep: true, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: true } + ], o.arr); + + mpath.set('arr.yep', false, o); + + assert.deepEqual([ + { yep: false, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: false } + ], o.arr); + + done(); + }) + }) + describe('with array of values', function(){ + it('that are equal in length', function(done){ + mpath.set('arr.yep', ['one',2], o, function (v) { + return 'one' === v ? 1 : v; + }); + assert.deepEqual([ + { yep: 1, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: 2 } + ], o.arr); + mpath.set('arr.yep', ['one',2], o); + + assert.deepEqual([ + { yep: 'one', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: 2 } + ], o.arr); + + done(); + }) + + it('that is less than length', function(done){ + mpath.set('arr.yep', [47], o, function (v) { + return 47 === v ? 4 : v; + }); + assert.deepEqual([ + { yep: 4, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: 2 } + ], o.arr); + + mpath.set('arr.yep', [47], o); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: 2 } + ], o.arr); + + done(); + }) + + it('that is greater than length', function(done){ + mpath.set('arr.yep', [5,6,7], o, function (v) { + return 5 === v ? 'five' : v; + }); + assert.deepEqual([ + { yep: 'five', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: 6 } + ], o.arr); + + mpath.set('arr.yep', [5,6,7], o); + assert.deepEqual([ + { yep: 5, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: 6 } + ], o.arr); + + done(); + }) + }) + }) + + describe('array.$.path', function(){ + describe('with single non-array value', function(){ + it('copies the value to each item in array', function(done){ + mpath.set('arr.$.yep', {xtra: 'double good'}, o, function (v) { + return v && v.xtra ? 'hi' : v; + }); + assert.deepEqual([ + { yep: 'hi', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: 'hi'} + ], o.arr); + + mpath.set('arr.$.yep', {xtra: 'double good'}, o); + assert.deepEqual([ + { yep: {xtra:'double good'}, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: {xtra:'double good'}} + ], o.arr); + + done(); + }) + }) + describe('with array of values', function(){ + it('copies the value to each item in array', function(done){ + mpath.set('arr.$.yep', [15], o, function (v) { + return v.length === 1 ? [] : v; + }); + assert.deepEqual([ + { yep: [], arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: []} + ], o.arr); + + mpath.set('arr.$.yep', [15], o); + assert.deepEqual([ + { yep: [15], arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: [15]} + ], o.arr); + + done(); + }) + }) + }) + + describe('array.index.path', function(){ + it('works', function(done){ + mpath.set('arr.1.yep', 0, o, function (v) { + return 0 === v ? 'zero' : v; + }); + assert.deepEqual([ + { yep: [15] , arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: 'zero' } + ], o.arr); + + mpath.set('arr.1.yep', 0, o); + assert.deepEqual([ + { yep: [15] , arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: 0 } + ], o.arr); + + done(); + }) + }) + + describe('array.index.array.path', function(){ + it('with single value', function(done){ + mpath.set('arr.0.arr.e', 35, o, function (v) { + return 35 === v ? 3 : v; + }); + assert.deepEqual([ + { yep: [15], arr: [{ a: { b: 47 }, e: 3}, { a: { c: 48 }, e: 3}, { d: 'yep', e: 3 }] } + , { yep: 0 } + ], o.arr); + + mpath.set('arr.0.arr.e', 35, o); + assert.deepEqual([ + { yep: [15], arr: [{ a: { b: 47 }, e: 35}, { a: { c: 48 }, e: 35}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + done(); + }) + it('with array', function(done){ + mpath.set('arr.0.arr.e', ['a','b'], o, function (v) { + return 'a' === v ? 'x' : v; + }); + assert.deepEqual([ + { yep: [15], arr: [{ a: { b: 47 }, e: 'x'}, { a: { c: 48 }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + mpath.set('arr.0.arr.e', ['a','b'], o); + assert.deepEqual([ + { yep: [15], arr: [{ a: { b: 47 }, e: 'a'}, { a: { c: 48 }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + done(); + }) + }) + + describe('array.index.array.path.path', function(){ + it('with single value', function(done){ + mpath.set('arr.0.arr.a.b', 36, o, function (v) { + return 36 === v ? 3 : v; + }); + assert.deepEqual([ + { yep: [15], arr: [{ a: { b: 3 }, e: 'a'}, { a: { c: 48, b: 3 }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + mpath.set('arr.0.arr.a.b', 36, o); + assert.deepEqual([ + { yep: [15], arr: [{ a: { b: 36 }, e: 'a'}, { a: { c: 48, b: 36 }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + done(); + }) + it('with array', function(done){ + mpath.set('arr.0.arr.a.b', [1,2,3,4], o, function (v) { + return 2 === v ? 'two' : v; + }); + assert.deepEqual([ + { yep: [15], arr: [{ a: { b: 1 }, e: 'a'}, { a: { c: 48, b: 'two' }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + mpath.set('arr.0.arr.a.b', [1,2,3,4], o); + assert.deepEqual([ + { yep: [15], arr: [{ a: { b: 1 }, e: 'a'}, { a: { c: 48, b: 2 }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + done(); + }) + }) + + describe('array.index.array.$.path.path', function(){ + it('with single value', function(done){ + mpath.set('arr.0.arr.$.a.b', '$', o, function (v) { + return '$' === v ? 'dolla billz' : v; + }); + assert.deepEqual([ + { yep: [15], arr: [{ a: { b: 'dolla billz' }, e: 'a'}, { a: { c: 48, b: 'dolla billz' }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + mpath.set('arr.0.arr.$.a.b', '$', o); + assert.deepEqual([ + { yep: [15], arr: [{ a: { b: '$' }, e: 'a'}, { a: { c: 48, b: '$' }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + done(); + }) + it('with array', function(done){ + mpath.set('arr.0.arr.$.a.b', [1], o, function (v) { + return Array.isArray(v) ? {} : v; + }); + assert.deepEqual([ + { yep: [15], arr: [{ a: { b: {} }, e: 'a'}, { a: { c: 48, b: {} }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + mpath.set('arr.0.arr.$.a.b', [1], o); + assert.deepEqual([ + { yep: [15], arr: [{ a: { b: [1] }, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + done(); + }) + }) + + describe('array.array.index.path', function(){ + it('with single value', function(done){ + mpath.set('arr.arr.0.a', 'single', o, function (v) { + return 'single' === v ? 'double' : v; + }); + assert.deepEqual([ + { yep: [15], arr: [{ a: 'double', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + mpath.set('arr.arr.0.a', 'single', o); + assert.deepEqual([ + { yep: [15], arr: [{ a: 'single', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + done(); + }) + it('with array', function(done){ + mpath.set('arr.arr.0.a', [4,8,15,16,23,42], o, function (v) { + return 4 === v ? 3 : v; + }); + assert.deepEqual([ + { yep: [15], arr: [{ a: 3, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: false } + ], o.arr); + + mpath.set('arr.arr.0.a', [4,8,15,16,23,42], o); + assert.deepEqual([ + { yep: [15], arr: [{ a: 4, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: false } + ], o.arr); + + done(); + }) + }) + + describe('array.array.$.index.path', function(){ + it('with single value', function(done){ + mpath.set('arr.arr.$.0.a', 'singles', o, function (v) { + return 0; + }); + assert.deepEqual([ + { yep: [15], arr: [{ a: 0, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + mpath.set('arr.arr.$.0.a', 'singles', o); + assert.deepEqual([ + { yep: [15], arr: [{ a: 'singles', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + mpath.set('$.arr.arr.0.a', 'single', o); + assert.deepEqual([ + { yep: [15], arr: [{ a: 'single', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0 } + ], o.arr); + + done(); + }) + it('with array', function(done){ + mpath.set('arr.arr.$.0.a', [4,8,15,16,23,42], o, function (v) { + return 'nope' + }); + assert.deepEqual([ + { yep: [15], arr: [{ a: 'nope', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0} + ], o.arr); + + mpath.set('arr.arr.$.0.a', [4,8,15,16,23,42], o); + assert.deepEqual([ + { yep: [15], arr: [{ a: [4,8,15,16,23,42], e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0} + ], o.arr); + + mpath.set('arr.$.arr.0.a', [4,8,15,16,23,42,108], o); + assert.deepEqual([ + { yep: [15], arr: [{ a: [4,8,15,16,23,42,108], e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0} + ], o.arr); + + done(); + }) + }) + + describe('array.array.path.index', function(){ + it('with single value', function(done){ + mpath.set('arr.arr.a.7', 47, o, function (v) { + return 1 + }); + assert.deepEqual([ + { yep: [15], arr: [{ a: [4,8,15,16,23,42,108,1], e: 'a'}, { a: { c: 48, b: [1], '7': 1 }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0} + ], o.arr); + + mpath.set('arr.arr.a.7', 47, o); + assert.deepEqual([ + { yep: [15], arr: [{ a: [4,8,15,16,23,42,108,47], e: 'a'}, { a: { c: 48, b: [1], '7': 47 }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0} + ], o.arr); + + done(); + }) + it('with array', function(done){ + o.arr[1].arr = [{ a: [] }, { a: [] }, { a: null }]; + mpath.set('arr.arr.a.7', [[null,46], [undefined, 'woot']], o); + + var a1 = []; + var a2 = []; + a1[7] = undefined; + a2[7] = 'woot'; + + assert.deepEqual([ + { yep: [15], arr: [{ a: [4,8,15,16,23,42,108,null], e: 'a'}, { a: { c: 48, b: [1], '7': 46 }, e: 'b'}, { d: 'yep', e: 35 }] } + , { yep: 0, arr: [{a:a1},{a:a2},{a:null}] } + ], o.arr); + + done(); + }) + }) + + describe('handles array.array.path', function(){ + it('with single', function(done){ + o.arr[1].arr = [{},{}]; + assert.deepEqual([{},{}], o.arr[1].arr); + o.arr.push({ arr: 'something else' }); + o.arr.push({ arr: ['something else'] }); + o.arr.push({ arr: [[]] }); + o.arr.push({ arr: [5] }); + + var weird = []; + weird.e = 'xmas'; + + // test + mpath.set('arr.arr.e', 47, o, function (v) { + return 'xmas' + }); + assert.deepEqual([ + { yep: [15], arr: [ + { a: [4,8,15,16,23,42,108,null], e: 'xmas'} + , { a: { c: 48, b: [1], '7': 46 }, e: 'xmas'} + , { d: 'yep', e: 'xmas' } + ] + } + , { yep: 0, arr: [{e: 'xmas'}, {e:'xmas'}] } + , { arr: 'something else' } + , { arr: ['something else'] } + , { arr: [weird] } + , { arr: [5] } + ] + , o.arr); + + weird.e = 47; + + mpath.set('arr.arr.e', 47, o); + assert.deepEqual([ + { yep: [15], arr: [ + { a: [4,8,15,16,23,42,108,null], e: 47} + , { a: { c: 48, b: [1], '7': 46 }, e: 47} + , { d: 'yep', e: 47 } + ] + } + , { yep: 0, arr: [{e: 47}, {e:47}] } + , { arr: 'something else' } + , { arr: ['something else'] } + , { arr: [weird] } + , { arr: [5] } + ] + , o.arr); + + done(); + }) + it('with arrays', function(done){ + mpath.set('arr.arr.e', [[1,2,3],[4,5],null,[],[6], [7,8,9]], o, function (v) { + return 10; + }); + + var weird = []; + weird.e = 10; + + assert.deepEqual([ + { yep: [15], arr: [ + { a: [4,8,15,16,23,42,108,null], e: 10} + , { a: { c: 48, b: [1], '7': 46 }, e: 10} + , { d: 'yep', e: 10 } + ] + } + , { yep: 0, arr: [{e: 10}, {e:10}] } + , { arr: 'something else' } + , { arr: ['something else'] } + , { arr: [weird] } + , { arr: [5] } + ] + , o.arr); + + mpath.set('arr.arr.e', [[1,2,3],[4,5],null,[],[6], [7,8,9]], o); + + weird.e = 6; + + assert.deepEqual([ + { yep: [15], arr: [ + { a: [4,8,15,16,23,42,108,null], e: 1} + , { a: { c: 48, b: [1], '7': 46 }, e: 2} + , { d: 'yep', e: 3 } + ] + } + , { yep: 0, arr: [{e: 4}, {e:5}] } + , { arr: 'something else' } + , { arr: ['something else'] } + , { arr: [weird] } + , { arr: [5] } + ] + , o.arr); + + done(); + }) + }) + }) + + describe('with `special`', function(){ + var o = doc(); + + it('works', function(done){ + mpath.set('name', 'chan', o, special, function (v) { + return 'hi'; + }); + assert.deepEqual('hi', o.name); + + mpath.set('name', 'changer', o, special); + assert.deepEqual('changer', o.name); + + mpath.set('first.second.third', [1,{name:'y'},9], o, special); + assert.deepEqual([1,{name:'y'},9], o.first.second.third); + + mpath.set('first.second.third.1.name', 'z', o, special) + assert.deepEqual([1,{name:'z'},9], o.first.second.third); + + mpath.set('comments.1.name', 'ttwwoo', o, special); + assert.deepEqual({ name: 'two', _doc: { name: 'ttwwoo' }}, o.comments[1]); + + mpath.set('comments.2.comments.1.comments.0.expander', 'adder', o, special, function (v) { + return 'super' + }); + assert.deepEqual( + { val: 2, expander: 'super'} + , o.comments[2]._doc.comments[1]._doc.comments[0]); + + mpath.set('comments.2.comments.1.comments.0.expander', 'adder', o, special); + assert.deepEqual( + { val: 2, expander: 'adder'} + , o.comments[2]._doc.comments[1]._doc.comments[0]); + + mpath.set('comments.2.comments.1.comments.2', 'set', o, special); + assert.equal(3, o.comments[2]._doc.comments[1]._doc.comments.length); + assert.deepEqual( + { val: 2, expander: 'adder'} + , o.comments[2]._doc.comments[1]._doc.comments[0]); + assert.deepEqual( + undefined + , o.comments[2]._doc.comments[1]._doc.comments[1]); + assert.deepEqual( + 'set' + , o.comments[2]._doc.comments[1]._doc.comments[2]); + done(); + }) + + describe('array.path', function(){ + describe('with single non-array value', function(){ + it('works', function(done){ + o.arr[1]._doc = { special: true } + + mpath.set('arr.yep', false, o, special, function (v) { + return 'yes'; + }); + assert.deepEqual([ + { yep: 'yes', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: true, _doc: { special: true, yep: 'yes'}} + ], o.arr); + + mpath.set('arr.yep', false, o, special); + assert.deepEqual([ + { yep: false, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: true, _doc: { special: true, yep: false }} + ], o.arr); + + done(); + }) + }) + describe('with array of values', function(){ + it('that are equal in length', function(done){ + mpath.set('arr.yep', ['one',2], o, special, function (v) { + return 2 === v ? 20 : v; + }); + assert.deepEqual([ + { yep: 'one', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: true, _doc: { special: true, yep: 20}} + ], o.arr); + + mpath.set('arr.yep', ['one',2], o, special); + assert.deepEqual([ + { yep: 'one', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: true, _doc: { special: true, yep: 2}} + ], o.arr); + + done(); + }) + + it('that is less than length', function(done){ + mpath.set('arr.yep', [47], o, special, function (v) { + return 80; + }); + assert.deepEqual([ + { yep: 80, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: true, _doc: { special: true, yep: 2}} + ], o.arr); + + mpath.set('arr.yep', [47], o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + , { yep: true, _doc: { special: true, yep: 2}} + ], o.arr); + + // add _doc to first element + o.arr[0]._doc = { yep: 46, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } + + mpath.set('arr.yep', [20], o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }], _doc: { yep: 20, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } } + , { yep: true, _doc: { special: true, yep: 2}} + ], o.arr); + + done(); + }) + + it('that is greater than length', function(done){ + mpath.set('arr.yep', [5,6,7], o, special, function () { + return 'x'; + }); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }], _doc: { yep: 'x', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } } + , { yep: true, _doc: { special: true, yep: 'x'}} + ], o.arr); + + mpath.set('arr.yep', [5,6,7], o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }], _doc: { yep: 5, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } } + , { yep: true, _doc: { special: true, yep: 6}} + ], o.arr); + + done(); + }) + }) + }) + + describe('array.$.path', function(){ + describe('with single non-array value', function(){ + it('copies the value to each item in array', function(done){ + mpath.set('arr.$.yep', {xtra: 'double good'}, o, special, function (v) { + return 9; + }); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: 9, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } } + , { yep: true, _doc: { special: true, yep: 9}} + ], o.arr); + + mpath.set('arr.$.yep', {xtra: 'double good'}, o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: {xtra:'double good'}, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } } + , { yep: true, _doc: { special: true, yep: {xtra:'double good'}}} + ], o.arr); + + done(); + }) + }) + describe('with array of values', function(){ + it('copies the value to each item in array', function(done){ + mpath.set('arr.$.yep', [15], o, special, function (v) { + return 'array' + }); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: 'array', arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } } + , { yep: true, _doc: { special: true, yep: 'array'}} + ], o.arr); + + mpath.set('arr.$.yep', [15], o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } } + , { yep: true, _doc: { special: true, yep: [15]}} + ], o.arr); + + done(); + }) + }) + }) + + describe('array.index.path', function(){ + it('works', function(done){ + mpath.set('arr.1.yep', 0, o, special, function (v) { + return 1; + }); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } } + , { yep: true, _doc: { special: true, yep: 1}} + ], o.arr); + + mpath.set('arr.1.yep', 0, o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + done(); + }) + }) + + describe('array.index.array.path', function(){ + it('with single value', function(done){ + mpath.set('arr.0.arr.e', 35, o, special, function (v) { + return 30 + }); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: { b: 47 }, e: 30}, { a: { c: 48 }, e: 30}, { d: 'yep', e: 30 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + mpath.set('arr.0.arr.e', 35, o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: { b: 47 }, e: 35}, { a: { c: 48 }, e: 35}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + done(); + }) + it('with array', function(done){ + mpath.set('arr.0.arr.e', ['a','b'], o, special, function (v) { + return 'a' === v ? 'A' : v; + }); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: { b: 47 }, e: 'A'}, { a: { c: 48 }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + mpath.set('arr.0.arr.e', ['a','b'], o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: { b: 47 }, e: 'a'}, { a: { c: 48 }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + done(); + }) + }) + + describe('array.index.array.path.path', function(){ + it('with single value', function(done){ + mpath.set('arr.0.arr.a.b', 36, o, special, function (v) { + return 20 + }); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: { b: 20 }, e: 'a'}, { a: { c: 48, b: 20 }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + mpath.set('arr.0.arr.a.b', 36, o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: { b: 36 }, e: 'a'}, { a: { c: 48, b: 36 }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + done(); + }) + it('with array', function(done){ + mpath.set('arr.0.arr.a.b', [1,2,3,4], o, special, function (v) { + return v*2; + }); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: { b: 2 }, e: 'a'}, { a: { c: 48, b: 4 }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + mpath.set('arr.0.arr.a.b', [1,2,3,4], o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: { b: 1 }, e: 'a'}, { a: { c: 48, b: 2 }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + done(); + }) + }) + + describe('array.index.array.$.path.path', function(){ + it('with single value', function(done){ + mpath.set('arr.0.arr.$.a.b', '$', o, special, function (v) { + return 'dollaz' + }); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: { b: 'dollaz' }, e: 'a'}, { a: { c: 48, b: 'dollaz' }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + mpath.set('arr.0.arr.$.a.b', '$', o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: { b: '$' }, e: 'a'}, { a: { c: 48, b: '$' }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + done(); + }) + it('with array', function(done){ + mpath.set('arr.0.arr.$.a.b', [1], o, special, function (v) { + return {}; + }); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: { b: {} }, e: 'a'}, { a: { c: 48, b: {} }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + mpath.set('arr.0.arr.$.a.b', [1], o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: { b: [1] }, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + done(); + }) + }) + + describe('array.array.index.path', function(){ + it('with single value', function(done){ + mpath.set('arr.arr.0.a', 'single', o, special, function (v) { + return 88; + }); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: 88, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + mpath.set('arr.arr.0.a', 'single', o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: 'single', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + done(); + }) + it('with array', function(done){ + mpath.set('arr.arr.0.a', [4,8,15,16,23,42], o, special, function (v) { + return v*2; + }); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: 8, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + mpath.set('arr.arr.0.a', [4,8,15,16,23,42], o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: 4, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + done(); + }) + }) + + describe('array.array.$.index.path', function(){ + it('with single value', function(done){ + mpath.set('arr.arr.$.0.a', 'singles', o, special, function (v) { + return v.toUpperCase(); + }); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: 'SINGLES', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + mpath.set('arr.arr.$.0.a', 'singles', o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: 'singles', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + mpath.set('$.arr.arr.0.a', 'single', o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: 'single', e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + done(); + }) + it('with array', function(done){ + mpath.set('arr.arr.$.0.a', [4,8,15,16,23,42], o, special, function (v) { + return Array + }); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: Array, e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + mpath.set('arr.arr.$.0.a', [4,8,15,16,23,42], o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: [4,8,15,16,23,42], e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + mpath.set('arr.$.arr.0.a', [4,8,15,16,23,42,108], o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: [4,8,15,16,23,42,108], e: 'a'}, { a: { c: 48, b: [1] }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + done(); + }) + }) + + describe('array.array.path.index', function(){ + it('with single value', function(done){ + mpath.set('arr.arr.a.7', 47, o, special, function (v) { + return Object; + }); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: [4,8,15,16,23,42,108,Object], e: 'a'}, { a: { c: 48, b: [1], '7': Object }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + mpath.set('arr.arr.a.7', 47, o, special); + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: [4,8,15,16,23,42,108,47], e: 'a'}, { a: { c: 48, b: [1], '7': 47 }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { special: true, yep: 0}} + ], o.arr); + + done(); + }) + it('with array', function(done){ + o.arr[1]._doc.arr = [{ a: [] }, { a: [] }, { a: null }]; + mpath.set('arr.arr.a.7', [[null,46], [undefined, 'woot']], o, special, function (v) { + return undefined === v ? 'nope' : v; + }); + + var a1 = []; + var a2 = []; + a1[7] = 'nope'; + a2[7] = 'woot'; + + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: [4,8,15,16,23,42,108,null], e: 'a'}, { a: { c: 48, b: [1], '7': 46 }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { arr: [{a:a1},{a:a2},{a:null}], special: true, yep: 0}} + ], o.arr); + + mpath.set('arr.arr.a.7', [[null,46], [undefined, 'woot']], o, special); + + a1[7] = undefined; + + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { yep: [15], arr: [{ a: [4,8,15,16,23,42,108,null], e: 'a'}, { a: { c: 48, b: [1], '7': 46 }, e: 'b'}, { d: 'yep', e: 35 }] } } + , { yep: true, _doc: { arr: [{a:a1},{a:a2},{a:null}], special: true, yep: 0}} + ], o.arr); + + done(); + }) + }) + + describe('handles array.array.path', function(){ + it('with single', function(done){ + o.arr[1]._doc.arr = [{},{}]; + assert.deepEqual([{},{}], o.arr[1]._doc.arr); + o.arr.push({ _doc: { arr: 'something else' }}); + o.arr.push({ _doc: { arr: ['something else'] }}); + o.arr.push({ _doc: { arr: [[]] }}); + o.arr.push({ _doc: { arr: [5] }}); + + // test + mpath.set('arr.arr.e', 47, o, special); + + var weird = []; + weird.e = 47; + + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { + yep: [15] + , arr: [ + { a: [4,8,15,16,23,42,108,null], e: 47} + , { a: { c: 48, b: [1], '7': 46 }, e: 47} + , { d: 'yep', e: 47 } + ] + } + } + , { yep: true + , _doc: { + arr: [ + {e:47} + , {e:47} + ] + , special: true + , yep: 0 + } + } + , { _doc: { arr: 'something else' }} + , { _doc: { arr: ['something else'] }} + , { _doc: { arr: [weird] }} + , { _doc: { arr: [5] }} + ] + , o.arr); + + done(); + }) + it('with arrays', function(done){ + mpath.set('arr.arr.e', [[1,2,3],[4,5],null,[],[6], [7,8,9]], o, special); + + var weird = []; + weird.e = 6; + + assert.deepEqual([ + { yep: 47, arr: [{ a: { b: 47 }}, { a: { c: 48 }}, { d: 'yep' }] + , _doc: { + yep: [15] + , arr: [ + { a: [4,8,15,16,23,42,108,null], e: 1} + , { a: { c: 48, b: [1], '7': 46 }, e: 2} + , { d: 'yep', e: 3 } + ] + } + } + , { yep: true + , _doc: { + arr: [ + {e:4} + , {e:5} + ] + , special: true + , yep: 0 + } + } + , { _doc: { arr: 'something else' }} + , { _doc: { arr: ['something else'] }} + , { _doc: { arr: [weird] }} + , { _doc: { arr: [5] }} + ] + , o.arr); + + done(); + }) + }) + + }) + + describe('get/set integration', function(){ + var o = doc(); + + it('works', function(done){ + var vals = mpath.get('array.o.array.x.b', o); + + vals[0][0][2] = 10; + vals[1][0][1] = 0; + vals[1][1] = 'Rambaldi'; + vals[1][2] = [12,14]; + vals[2] = [{changed:true}, [null, ['changed','to','array']]]; + + mpath.set('array.o.array.x.b', vals, o); + + var t = [ + { o: { array: [{x: {b: [4,6,10]}}, { y: 10} ] }} + , { o: { array: [{x: {b: [1,0,3]}}, { x: {b:'Rambaldi',z: 10 }}, { x: {b: [12,14]}}] }} + , { o: { array: [{x: {b: {changed:true}}}, { x: { b: [null, ['changed','to','array']]}}]}} + , { o: { array: [{x: null }] }} + , { o: { array: [{y: 3 }] }} + , { o: { array: [3, 0, null] }} + , { o: { name: 'ha' }} + ]; + assert.deepEqual(t, o.array); + done(); + }) + + it('array.prop', function(done){ + mpath.set('comments.name', ['this', 'was', 'changed'], o); + + assert.deepEqual([ + { name: 'this' } + , { name: 'was', _doc: { name: '2' }} + , { name: 'changed' + , comments: [{},{ comments: [{val: 'twoo'}]}] + , _doc: { name: '3', comments: [{},{ _doc: { comments: [{ val: 2 }] }}] }} + ], o.comments); + + mpath.set('comments.name', ['also', 'changed', 'this'], o, special); + + assert.deepEqual([ + { name: 'also' } + , { name: 'was', _doc: { name: 'changed' }} + , { name: 'changed' + , comments: [{},{ comments: [{val: 'twoo'}]}] + , _doc: { name: 'this', comments: [{},{ _doc: { comments: [{ val: 2 }] }}] }} + ], o.comments); + + done(); + }) + + }) + + describe('multiple $ use', function(){ + var o = doc(); + it('is ok', function(done){ + assert.doesNotThrow(function () { + mpath.set('arr.$.arr.$.a', 35, o); + }); + done(); + }) + }) + + it('ignores setting a nested path that doesnt exist', function(done){ + var o = doc(); + assert.doesNotThrow(function(){ + mpath.set('thing.that.is.new', 10, o); + }) + done(); + }) + }) + +}) diff --git a/node_modules/mongoose/node_modules/mpromise/.npmignore b/node_modules/mongoose/node_modules/mpromise/.npmignore new file mode 100644 index 0000000..be106ca --- /dev/null +++ b/node_modules/mongoose/node_modules/mpromise/.npmignore @@ -0,0 +1,2 @@ +*.sw* +node_modules/ diff --git a/node_modules/mongoose/node_modules/mpromise/.travis.yml b/node_modules/mongoose/node_modules/mpromise/.travis.yml new file mode 100644 index 0000000..895dbd3 --- /dev/null +++ b/node_modules/mongoose/node_modules/mpromise/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.6 + - 0.8 diff --git a/node_modules/mongoose/node_modules/mpromise/History.md b/node_modules/mongoose/node_modules/mpromise/History.md new file mode 100644 index 0000000..2098fe2 --- /dev/null +++ b/node_modules/mongoose/node_modules/mpromise/History.md @@ -0,0 +1,32 @@ + +0.3.0 / 2013-07-25 +================== + + * updated; sliced to 0.0.5 + * fixed; then is passed all fulfillment values + * use setImmediate if available + * conform to Promises A+ 1.1 + +0.2.1 / 2013-02-09 +================== + + * fixed; conformancy with A+ 1.2 + +0.2.0 / 2013-01-09 +================== + + * added; .end() + * fixed; only catch handler executions + +0.1.0 / 2013-01-08 +================== + + * cleaned up API + * customizable event names + * docs + +0.0.1 / 2013-01-07 +================== + + * original release + diff --git a/node_modules/mongoose/node_modules/mpromise/LICENSE b/node_modules/mongoose/node_modules/mpromise/LICENSE new file mode 100644 index 0000000..38c529d --- /dev/null +++ b/node_modules/mongoose/node_modules/mpromise/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2012 [Aaron Heckmann](aaron.heckmann+github@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/mongoose/node_modules/mpromise/Makefile b/node_modules/mongoose/node_modules/mpromise/Makefile new file mode 100644 index 0000000..717a796 --- /dev/null +++ b/node_modules/mongoose/node_modules/mpromise/Makefile @@ -0,0 +1,12 @@ +TESTS = $(shell find test/ -name '*.test.js') + +test: + @make test-unit && echo "testing promises-A+ implementation ..." && make test-promises-A + +test-unit: + @./node_modules/.bin/mocha $(T) --async-only $(TESTS) + +test-promises-A: + @node test/promises-A.js + +.PHONY: test test-unit test-promises-A diff --git a/node_modules/mongoose/node_modules/mpromise/README.md b/node_modules/mongoose/node_modules/mpromise/README.md new file mode 100644 index 0000000..7da2725 --- /dev/null +++ b/node_modules/mongoose/node_modules/mpromise/README.md @@ -0,0 +1,200 @@ +#mpromise +========== + +A [promises/A+](https://github.com/promises-aplus/promises-spec) conformant implementation, written for [mongoose](http://mongoosejs.com). + +## installation + +``` +$ npm install mpromise +``` + +## docs + +An `mpromise` can be in any of three states, pending, fulfilled (success), or rejected (error). Once it is either fulfilled or rejected it's state can no longer be changed. + +The exports object is the Promise constructor. + +```js +var Promise = require('mpromise'); +``` + +The constructor accepts an optional function which is executed when the promise is first resolved (either fulfilled or rejected). + +```js +var promise = new Promise(fn); +``` + +This is the same as passing the `fn` to `onResolve` directly. + +```js +var promise = new Promise; +promise.onResolve(function (err, args..) { + ... +}); +``` + +### Methods + +####fulfill + +Fulfilling a promise with values: + +```js +var promise = new Promise; +promise.fulfill(args...); +``` + +If the promise has already been fulfilled or rejected, no action is taken. + +####reject + +Rejecting a promise with a reason: + +```js +var promise = new Promise; +promise.reject(reason); +``` + +If the promise has already been fulfilled or rejected, no action is taken. + +####resolve + +Node.js callback style promise resolution `(err, args...)`: + +```js +var promise = new Promise; +promise.resolve([reason], [arg1, arg2, ...]); +``` + +If the promise has already been fulfilled or rejected, no action is taken. + +####onFulfill + +To register a function for execution when the promise is fulfilled, pass it to `onFulfill`. When executed it will receive the arguments passed to `fulfill()`. + +```js +var promise = new Promise; +promise.onFulfill(function (a, b) { + assert.equal(3, a + b); +}); +promise.fulfill(1, 2); +``` + +The function will only be called once when the promise is fulfilled, never when rejected. + +Registering a function with `onFulfill` after the promise has already been fulfilled results in the immediate execution of the function with the original arguments used to fulfill the promise. + +```js +var promise = new Promise; +promise.fulfill(" :D "); +promise.onFulfill(function (arg) { + console.log(arg); // logs " :D " +}) +``` + +####onReject + +To register a function for execution when the promise is rejected, pass it to `onReject`. When executed it will receive the argument passed to `reject()`. + +```js +var promise = new Promise; +promise.onReject(function (reason) { + assert.equal('sad', reason); +}); +promise.reject('sad'); +``` + +The function will only be called once when the promise is rejected, never when fulfilled. + +Registering a function with `onReject` after the promise has already been rejected results in the immediate execution of the function with the original argument used to reject the promise. + +```js +var promise = new Promise; +promise.reject(" :( "); +promise.onReject(function (reason) { + console.log(reason); // logs " :( " +}) +``` + +####onResolve + +Allows registration of node.js style callbacks `(err, args..)` to handle either promise resolution type (fulfill or reject). + +```js +// fulfillment +var promise = new Promise; +promise.onResolve(function (err, a, b) { + console.log(a + b); // logs 3 +}); +promise.fulfill(1, 2); + +// rejection +var promise = new Promise; +promise.onResolve(function (err) { + if (err) { + console.log(err.message); // logs "failed" + } +}); +promise.reject(new Error('failed')); +``` + +####then + +Creates a new promise and returns it. If `onFulfill` or `onReject` are passed, they are added as SUCCESS/ERROR callbacks to this promise after the nextTick. + +Conforms to [promises/A+](https://github.com/promises-aplus/promises-spec) specification and passes its [tests](https://github.com/promises-aplus/promises-tests). + +```js +// promise.then(onFulfill, onReject); + +var p = new Promise; + +p.then(function (arg) { + return arg + 1; +}).then(function (arg) { + throw new Error(arg + ' is an error!'); +}).then(null, function (err) { + assert.ok(err instanceof Error); + assert.equal('2 is an error', err.message); +}); +p.complete(1); +``` + +####end + +Signifies that this promise was the last in a chain of `then()s`: if a handler passed to the call to `then` which produced this promise throws, the exception will go uncaught. + +```js +var p = new Promise; +p.then(function(){ throw new Error('shucks') }); +setTimeout(function () { + p.fulfill(); + // error was caught and swallowed by the promise returned from + // p.then(). we either have to always register handlers on + // the returned promises or we can do the following... +}, 10); + +// this time we use .end() which prevents catching thrown errors +var p = new Promise; +var p2 = p.then(function(){ throw new Error('shucks') }).end(); // <-- +setTimeout(function () { + p.fulfill(); // throws "shucks" +}, 10); +``` + +###Event names + +If you'd like to alter this implementations event names used to signify success and failure you may do so by setting `Promise.SUCCESS` or `Promise.FAILURE` respectively. + +```js +Promise.SUCCESS = 'complete'; +Promise.FAILURE = 'err'; +``` + +###Luke, use the Source +For more ideas read the [source](https://github.com/aheckmann/mpromise/blob/master/lib), [tests](https://github.com/aheckmann/mpromise/blob/master/test), or the [mongoose implementation](https://github.com/LearnBoost/mongoose/blob/3.6x/lib/promise.js). + +## license + +[MIT](https://github.com/aheckmann/mpromise/blob/master/LICENSE) diff --git a/node_modules/mongoose/node_modules/mpromise/index.js b/node_modules/mongoose/node_modules/mpromise/index.js new file mode 100644 index 0000000..0b3669d --- /dev/null +++ b/node_modules/mongoose/node_modules/mpromise/index.js @@ -0,0 +1 @@ +module.exports = exports = require('./lib/promise'); diff --git a/node_modules/mongoose/node_modules/mpromise/lib/promise.js b/node_modules/mongoose/node_modules/mpromise/lib/promise.js new file mode 100644 index 0000000..8059715 --- /dev/null +++ b/node_modules/mongoose/node_modules/mpromise/lib/promise.js @@ -0,0 +1,324 @@ +'use strict'; + +/*! + * Module dependencies. + */ + +var slice = require('sliced'); +var EventEmitter = require('events').EventEmitter; + +/** + * compat with node 0.10 + */ + +var next = 'function' == typeof setImmediate + ? setImmediate + : process.nextTick; + +/** + * Promise constructor. + * + * _NOTE: The success and failure event names can be overridden by setting `Promise.SUCCESS` and `Promise.FAILURE` respectively._ + * + * @param {Function} back a function that accepts `fn(err, ...){}` as signature + * @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter + * @event `reject`: Emits when the promise is rejected (event name may be overridden) + * @event `fulfill`: Emits when the promise is fulfilled (event name may be overridden) + * @api public + */ + +function Promise (back) { + this.emitted = {}; + this.ended = false; + if ('function' == typeof back) + this.onResolve(back); +} + +/*! + * event names + */ + +Promise.SUCCESS = 'fulfill'; +Promise.FAILURE = 'reject'; + +/*! + * Inherits from EventEmitter. + */ + +Promise.prototype.__proto__ = EventEmitter.prototype; + +/** + * Adds `listener` to the `event`. + * + * If `event` is either the success or failure event and the event has already been emitted, the`listener` is called immediately and passed the results of the original emitted event. + * + * @param {String} event + * @param {Function} callback + * @return {Promise} this + * @api public + */ + +Promise.prototype.on = function (event, callback) { + if (this.emitted[event]) + callback.apply(this, this.emitted[event]); + else + EventEmitter.prototype.on.call(this, event, callback); + + return this; +} + +/** + * Keeps track of emitted events to run them on `on`. + * + * @api private + */ + +Promise.prototype.emit = function (event) { + // ensures a promise can't be fulfill() or reject() more than once + var success = this.constructor.SUCCESS; + var failure = this.constructor.FAILURE; + + if (event == success || event == failure) { + if (this.emitted[success] || this.emitted[failure]) { + return this; + } + this.emitted[event] = slice(arguments, 1); + } + + return EventEmitter.prototype.emit.apply(this, arguments); +} + +/** + * Fulfills this promise with passed arguments. + * + * If this promise has already been fulfilled or rejected, no action is taken. + * + * @api public + */ + +Promise.prototype.fulfill = function () { + var args = slice(arguments); + return this.emit.apply(this, [this.constructor.SUCCESS].concat(args)); +} + +/** + * Rejects this promise with `reason`. + * + * If this promise has already been fulfilled or rejected, no action is taken. + * + * @api public + * @param {Object|String} reason + * @return {Promise} this + */ + +Promise.prototype.reject = function (reason) { + return this.emit(this.constructor.FAILURE, reason); +} + +/** + * Resolves this promise to a rejected state if `err` is passed or + * fulfilled state if no `err` is passed. + * + * @param {Error} [err] error or null + * @param {Object} [val] value to fulfill the promise with + * @api public + */ + +Promise.prototype.resolve = function (err, val) { + if (err) return this.reject(err); + return this.fulfill(val); +} + +/** + * Adds a listener to the SUCCESS event. + * + * @return {Promise} this + * @api public + */ + +Promise.prototype.onFulfill = function (fn) { + return this.on(this.constructor.SUCCESS, fn); +} + +/** + * Adds a listener to the FAILURE event. + * + * @return {Promise} this + * @api public + */ + +Promise.prototype.onReject = function (fn) { + return this.on(this.constructor.FAILURE, fn); +} + +/** + * Adds a single function as a listener to both SUCCESS and FAILURE. + * + * It will be executed with traditional node.js argument position: + * function (err, args...) {} + * + * @param {Function} fn + * @return {Promise} this + */ + +Promise.prototype.onResolve = function (fn) { + this.on(this.constructor.FAILURE, function(err){ + fn.call(this, err); + }); + + this.on(this.constructor.SUCCESS, function(){ + var args = slice(arguments); + fn.apply(this, [null].concat(args)); + }); + + return this; +} + +/** + * Creates a new promise and returns it. If `onFulfill` or + * `onReject` are passed, they are added as SUCCESS/ERROR callbacks + * to this promise after the next tick. + * + * Conforms to [promises/A+](https://github.com/promises-aplus/promises-spec) specification. Read for more detail how to use this method. + * + * ####Example: + * + * var p = new Promise; + * p.then(function (arg) { + * return arg + 1; + * }).then(function (arg) { + * throw new Error(arg + ' is an error!'); + * }).then(null, function (err) { + * assert.ok(err instanceof Error); + * assert.equal('2 is an error', err.message); + * }); + * p.complete(1); + * + * @see promises-A+ https://github.com/promises-aplus/promises-spec + * @param {Function} onFulFill + * @param {Function} onReject + * @return {Promise} newPromise + */ + +Promise.prototype.then = function (onFulfill, onReject) { + var self = this + , retPromise = new Promise; + + next(function () { + if ('function' == typeof onReject) { + self.onReject(handler(retPromise, onReject)); + } else { + self.onReject(retPromise.reject.bind(retPromise)); + } + + if ('function' == typeof onFulfill) { + self.onFulfill(handler(retPromise, onFulfill)); + } else { + self.onFulfill(retPromise.fulfill.bind(retPromise)); + } + }) + + return retPromise; +} + +function handler (promise, fn) { + return function handle () { + var val; + + try { + val = fn.apply(undefined, arguments); + } catch (err) { + if (promise.ended) throw err; + return promise.reject(err); + } + + var type = typeof val; + if ('undefined' == type) { + return promise.fulfill(val); + } + + resolve(promise, val); + } +} + +function resolve (promise, x) { + var then; + var type; + var done; + var reject_; + var resolve_; + + if (null != x) { + type = typeof x; + + if ('object' == type || 'function' == type) { + try { + then = x.then; + } catch (err) { + if (promise.ended) throw err; + return promise.reject(err); + } + + if ('function' == typeof then) { + try { + resolve_ = resolve.bind(this, promise); + reject_ = promise.reject.bind(promise); + done = false; + return then.call( + x + , function fulfill () { + if (done) return; + done = true; + return resolve_.apply(this, arguments); + } + , function reject () { + if (done) return; + done = true; + return reject_.apply(this, arguments); + }) + } catch (err) { + if (done) return; + done = true; + if (promise.ended) throw err; + return promise.reject(err); + } + } + } + } + + promise.fulfill(x); +} + +/** + * Signifies that this promise was the last in a chain of `then()s`: if a handler passed to the call to `then` which produced this promise throws, the exception will go uncaught. + * + * ####Example: + * + * var p = new Promise; + * p.then(function(){ throw new Error('shucks') }); + * setTimeout(function () { + * p.fulfill(); + * // error was caught and swallowed by the promise returned from + * // p.then(). we either have to always register handlers on + * // the returned promises or we can do the following... + * }, 10); + * + * // this time we use .end() which prevents catching thrown errors + * var p = new Promise; + * var p2 = p.then(function(){ throw new Error('shucks') }).end(); // <-- + * setTimeout(function () { + * p.fulfill(); // throws "shucks" + * }, 10); + * + * @api public + */ + +Promise.prototype.end = function () { + this.ended = true; +} + +/*! + * Module exports. + */ + +module.exports = Promise; diff --git a/node_modules/mongoose/node_modules/mpromise/package.json b/node_modules/mongoose/node_modules/mpromise/package.json new file mode 100644 index 0000000..41ae528 --- /dev/null +++ b/node_modules/mongoose/node_modules/mpromise/package.json @@ -0,0 +1,43 @@ +{ + "name": "mpromise", + "version": "0.3.0", + "description": "Promises A+ conformant implementation", + "main": "index.js", + "scripts": { + "test": "make test" + }, + "dependencies": { + "sliced": "0.0.5" + }, + "devDependencies": { + "mocha": "1.7.4", + "promises-aplus-tests": ">= 1.2" + }, + "repository": { + "type": "git", + "url": "git://github.com/aheckmann/mpromise" + }, + "keywords": [ + "promise", + "mongoose", + "aplus", + "a+", + "plus" + ], + "author": { + "name": "Aaron Heckmann", + "email": "aaron.heckmann+github@gmail.com" + }, + "license": "MIT", + "readme": "#mpromise\n==========\n\nA [promises/A+](https://github.com/promises-aplus/promises-spec) conformant implementation, written for [mongoose](http://mongoosejs.com).\n\n## installation\n\n```\n$ npm install mpromise\n```\n\n## docs\n\nAn `mpromise` can be in any of three states, pending, fulfilled (success), or rejected (error). Once it is either fulfilled or rejected it's state can no longer be changed.\n\nThe exports object is the Promise constructor.\n\n```js\nvar Promise = require('mpromise');\n```\n\nThe constructor accepts an optional function which is executed when the promise is first resolved (either fulfilled or rejected).\n\n```js\nvar promise = new Promise(fn);\n```\n\nThis is the same as passing the `fn` to `onResolve` directly.\n\n```js\nvar promise = new Promise;\npromise.onResolve(function (err, args..) {\n ...\n});\n```\n\n### Methods\n\n####fulfill\n\nFulfilling a promise with values:\n\n```js\nvar promise = new Promise;\npromise.fulfill(args...);\n```\n\nIf the promise has already been fulfilled or rejected, no action is taken.\n\n####reject\n\nRejecting a promise with a reason:\n\n```js\nvar promise = new Promise;\npromise.reject(reason);\n```\n\nIf the promise has already been fulfilled or rejected, no action is taken.\n\n####resolve\n\nNode.js callback style promise resolution `(err, args...)`:\n\n```js\nvar promise = new Promise;\npromise.resolve([reason], [arg1, arg2, ...]);\n```\n\nIf the promise has already been fulfilled or rejected, no action is taken.\n\n####onFulfill\n\nTo register a function for execution when the promise is fulfilled, pass it to `onFulfill`. When executed it will receive the arguments passed to `fulfill()`.\n\n```js\nvar promise = new Promise;\npromise.onFulfill(function (a, b) {\n assert.equal(3, a + b);\n});\npromise.fulfill(1, 2);\n```\n\nThe function will only be called once when the promise is fulfilled, never when rejected.\n\nRegistering a function with `onFulfill` after the promise has already been fulfilled results in the immediate execution of the function with the original arguments used to fulfill the promise.\n\n```js\nvar promise = new Promise;\npromise.fulfill(\" :D \");\npromise.onFulfill(function (arg) {\n console.log(arg); // logs \" :D \"\n})\n```\n\n####onReject\n\nTo register a function for execution when the promise is rejected, pass it to `onReject`. When executed it will receive the argument passed to `reject()`.\n\n```js\nvar promise = new Promise;\npromise.onReject(function (reason) {\n assert.equal('sad', reason);\n});\npromise.reject('sad');\n```\n\nThe function will only be called once when the promise is rejected, never when fulfilled.\n\nRegistering a function with `onReject` after the promise has already been rejected results in the immediate execution of the function with the original argument used to reject the promise.\n\n```js\nvar promise = new Promise;\npromise.reject(\" :( \");\npromise.onReject(function (reason) {\n console.log(reason); // logs \" :( \"\n})\n```\n\n####onResolve\n\nAllows registration of node.js style callbacks `(err, args..)` to handle either promise resolution type (fulfill or reject).\n\n```js\n// fulfillment\nvar promise = new Promise;\npromise.onResolve(function (err, a, b) {\n console.log(a + b); // logs 3\n});\npromise.fulfill(1, 2);\n\n// rejection\nvar promise = new Promise;\npromise.onResolve(function (err) {\n if (err) {\n console.log(err.message); // logs \"failed\"\n }\n});\npromise.reject(new Error('failed'));\n```\n\n####then\n\nCreates a new promise and returns it. If `onFulfill` or `onReject` are passed, they are added as SUCCESS/ERROR callbacks to this promise after the nextTick.\n\nConforms to [promises/A+](https://github.com/promises-aplus/promises-spec) specification and passes its [tests](https://github.com/promises-aplus/promises-tests).\n\n```js\n// promise.then(onFulfill, onReject);\n\nvar p = new Promise;\n\np.then(function (arg) {\n return arg + 1;\n}).then(function (arg) {\n throw new Error(arg + ' is an error!');\n}).then(null, function (err) {\n assert.ok(err instanceof Error);\n assert.equal('2 is an error', err.message);\n});\np.complete(1);\n```\n\n####end\n\nSignifies that this promise was the last in a chain of `then()s`: if a handler passed to the call to `then` which produced this promise throws, the exception will go uncaught.\n\n```js\nvar p = new Promise;\np.then(function(){ throw new Error('shucks') });\nsetTimeout(function () {\n p.fulfill();\n // error was caught and swallowed by the promise returned from\n // p.then(). we either have to always register handlers on\n // the returned promises or we can do the following...\n}, 10);\n\n// this time we use .end() which prevents catching thrown errors\nvar p = new Promise;\nvar p2 = p.then(function(){ throw new Error('shucks') }).end(); // <--\nsetTimeout(function () {\n p.fulfill(); // throws \"shucks\"\n}, 10);\n```\n\n###Event names\n\nIf you'd like to alter this implementations event names used to signify success and failure you may do so by setting `Promise.SUCCESS` or `Promise.FAILURE` respectively.\n\n```js\nPromise.SUCCESS = 'complete';\nPromise.FAILURE = 'err';\n```\n\n###Luke, use the Source\nFor more ideas read the [source](https://github.com/aheckmann/mpromise/blob/master/lib), [tests](https://github.com/aheckmann/mpromise/blob/master/test), or the [mongoose implementation](https://github.com/LearnBoost/mongoose/blob/3.6x/lib/promise.js).\n\n## license\n\n[MIT](https://github.com/aheckmann/mpromise/blob/master/LICENSE)\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/aheckmann/mpromise/issues" + }, + "_id": "mpromise@0.3.0", + "dist": { + "shasum": "cb864c2f642eb2192765087e3692e1dc152afe4b" + }, + "_from": "mpromise@0.3.0", + "_resolved": "https://registry.npmjs.org/mpromise/-/mpromise-0.3.0.tgz" +} diff --git a/node_modules/mongoose/node_modules/mpromise/test/promise.test.js b/node_modules/mongoose/node_modules/mpromise/test/promise.test.js new file mode 100644 index 0000000..5d098d8 --- /dev/null +++ b/node_modules/mongoose/node_modules/mpromise/test/promise.test.js @@ -0,0 +1,217 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert') +var Promise = require('../lib/promise'); + +/** + * Test. + */ + +describe('promise', function(){ + it('events fire right after fulfill()', function(done){ + var promise = new Promise() + , called = 0; + + promise.on('fulfill', function (a, b) { + assert.equal(a, '1'); + assert.equal(b, '2'); + called++; + }); + + promise.fulfill('1', '2'); + + promise.on('fulfill', function (a, b) { + assert.equal(a, '1'); + assert.equal(b, '2'); + called++; + }); + + assert.equal(2, called); + done(); + }); + + it('events fire right after reject()', function(done){ + var promise = new Promise() + , called = 0; + + promise.on('reject', function (err) { + assert.ok(err instanceof Error); + called++; + }); + + promise.reject(new Error('booyah')); + + promise.on('reject', function (err) { + assert.ok(err instanceof Error); + called++; + }); + + assert.equal(2, called); + done() + }); + + describe('onResolve()', function(){ + it('from constructor works', function(done){ + var called = 0; + + var promise = new Promise(function (err) { + assert.ok(err instanceof Error); + called++; + }) + + promise.reject(new Error('dawg')); + + assert.equal(1, called); + done(); + }); + + it('after fulfill()', function(done){ + var promise = new Promise() + , called = 0; + + promise.fulfill('woot'); + + promise.onResolve(function (err, data){ + assert.equal(data,'woot'); + called++; + }); + + promise.onResolve(function (err, data){ + assert.strictEqual(err, null); + called++; + }); + + assert.equal(2, called); + done(); + }) + }); + + describe('onFulfill shortcut', function(){ + it('works', function(done){ + var promise = new Promise() + , called = 0; + + promise.onFulfill(function (woot) { + assert.strictEqual(woot, undefined); + called++; + }); + + promise.fulfill(); + + assert.equal(1, called); + done(); + }) + }) + + describe('onReject shortcut', function(){ + it('works', function(done){ + var promise = new Promise() + , called = 0; + + promise.onReject(function (err) { + assert.ok(err instanceof Error); + called++; + }); + + promise.reject(new Error); + assert.equal(1, called); + done(); + }) + }); + + describe('return values', function(){ + it('on()', function(done){ + var promise = new Promise() + assert.ok(promise.on('jump', function(){}) instanceof Promise); + done() + }); + + it('onFulfill()', function(done){ + var promise = new Promise() + assert.ok(promise.onFulfill(function(){}) instanceof Promise); + done(); + }) + it('onReject()', function(done){ + var promise = new Promise() + assert.ok(promise.onReject(function(){}) instanceof Promise); + done(); + }) + it('onResolve()', function(done){ + var promise = new Promise() + assert.ok(promise.onResolve(function(){}) instanceof Promise); + done(); + }) + }) + + describe('casting errors', function(){ + describe('reject()', function(){ + it('does not cast arguments to Error', function(done){ + var p = new Promise(function (err, arg) { + assert.equal(3, err); + done(); + }); + + p.reject(3); + }) + }) + }) + + describe('then', function(){ + describe('catching', function(){ + it('should not catch returned promise fulfillments', function(done){ + var p1 = new Promise; + + var p2 = p1.then(function () { return 'step 1' }) + + p2.onFulfill(function () { throw new Error('fulfill threw me') }) + p2.reject = assert.ifError.bind(assert, new Error('reject should not have been called')); + + setTimeout(function () { + assert.throws(function () { + p1.fulfill(); + }, /fulfill threw me/) + done(); + }, 10); + + }) + + it('can be disabled using .end()', function(done){ + var p = new Promise; + + var p2 = p.then(function () { throw new Error('shucks') }) + p2.end(); + + setTimeout(function () { + try { + p.fulfill(); + } catch (err) { + assert.ok(/shucks/.test(err)) + done(); + } + + setTimeout(function () { + done(new Error('error was swallowed')); + }, 10); + + }, 10); + }) + }); + + it('accepts multiple completion values', function(done){ + var p = new Promise; + + p.then(function (a, b) { + assert.equal(2, arguments.length); + assert.equal('hi', a); + assert.equal(4, b); + done(); + }, done).end(); + + p.fulfill('hi', 4); + }) + }) + +}) diff --git a/node_modules/mongoose/node_modules/mpromise/test/promises-A.js b/node_modules/mongoose/node_modules/mpromise/test/promises-A.js new file mode 100644 index 0000000..ebb4626 --- /dev/null +++ b/node_modules/mongoose/node_modules/mpromise/test/promises-A.js @@ -0,0 +1,35 @@ + +/** + * Module dependencies. + */ + +var assert = require('assert') +var Promise = require('../lib/promise'); +var aplus = require('promises-aplus-tests'); + +// tests + +var adapter = {}; +adapter.fulfilled = function (value) { + var p = new Promise; + p.fulfill(value); + return p; +}; +adapter.rejected = function (reason) { + var p = new Promise; + p.reject(reason); + return p; +} +adapter.pending = function () { + var p = new Promise; + return { + promise: p + , fulfill: p.fulfill.bind(p) + , reject: p.reject.bind(p) + } +} + +aplus(adapter, function (err) { + assert.ifError(err); +}); + diff --git a/node_modules/mongoose/node_modules/mquery/.npmignore b/node_modules/mongoose/node_modules/mquery/.npmignore new file mode 100644 index 0000000..be106ca --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/.npmignore @@ -0,0 +1,2 @@ +*.sw* +node_modules/ diff --git a/node_modules/mongoose/node_modules/mquery/.travis.yml b/node_modules/mongoose/node_modules/mquery/.travis.yml new file mode 100644 index 0000000..ce393d5 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/.travis.yml @@ -0,0 +1,6 @@ +language: node_js +node_js: + - 0.6 + - 0.8 +services: + - mongodb diff --git a/node_modules/mongoose/node_modules/mquery/History.md b/node_modules/mongoose/node_modules/mquery/History.md new file mode 100644 index 0000000..e9b3a67 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/History.md @@ -0,0 +1,102 @@ + +0.3.2 / 2013-09-06 +================== + + * added; geometry support for near() + +0.3.1 / 2013-08-22 +================== + + * fixed; update retains key order #19 + +0.3.0 / 2013-08-22 +================== + + * less hardcoded isNode env detection #18 [vshulyak](https://github.com/vshulyak) + * added; validation of findAndModify varients + * clone update doc before execution + * stricter env checks + +0.2.7 / 2013-08-2 +================== + + * Now support GeoJSON point values for Query#near + +0.2.6 / 2013-07-30 +================== + + * internally, 'asc' and 'desc' for sorts are now converted into 1 and -1, respectively + +0.2.5 / 2013-07-30 +================== + + * updated docs + * changed internal representation of `sort` to use objects instead of arrays + +0.2.4 / 2013-07-25 +================== + + * updated; sliced to 0.0.5 + +0.2.3 / 2013-07-09 +================== + + * now using a callback in collection.find instead of directly calling toArray() on the cursor [ebensing](https://github.com/ebensing) + +0.2.2 / 2013-07-09 +================== + + * now exposing mongodb export to allow for better testing [ebensing](https://github.com/ebensing) + +0.2.1 / 2013-07-08 +================== + + * select no longer accepts arrays as parameters [ebensing](https://github.com/ebensing) + +0.2.0 / 2013-07-05 +================== + + * use $geoWithin by default + +0.1.2 / 2013-07-02 +================== + + * added use$geoWithin flag [ebensing](https://github.com/ebensing) + * fix read preferences typo [ebensing](https://github.com/ebensing) + * fix reference to old param name in exists() [ebensing](https://github.com/ebensing) + +0.1.1 / 2013-06-24 +================== + + * fixed; $intersects -> $geoIntersects #14 [ebensing](https://github.com/ebensing) + * fixed; Retain key order when copying objects #15 [ebensing](https://github.com/ebensing) + * bump mongodb dev dep + +0.1.0 / 2013-05-06 +================== + + * findAndModify; return the query + * move mquery.proto.canMerge to mquery.canMerge + * overwrite option now works with non-empty objects + * use strict mode + * validate count options + * validate distinct options + * add aggregate to base collection methods + * clone merge arguments + * clone merged update arguments + * move subclass to mquery.prototype.toConstructor + * fixed; maxScan casing + * use regexp-clone + * added; geometry/intersects support + * support $and + * near: do not use "radius" + * callbacks always fire on next turn of loop + * defined collection interface + * remove time from tests + * clarify goals + * updated docs; + +0.0.1 / 2012-12-15 +================== + + * initial release diff --git a/node_modules/mongoose/node_modules/mquery/LICENSE b/node_modules/mongoose/node_modules/mquery/LICENSE new file mode 100644 index 0000000..38c529d --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2012 [Aaron Heckmann](aaron.heckmann+github@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/mongoose/node_modules/mquery/Makefile b/node_modules/mongoose/node_modules/mquery/Makefile new file mode 100644 index 0000000..2ad4e47 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/Makefile @@ -0,0 +1,5 @@ + +test: + @./node_modules/.bin/mocha $(T) $(TESTS) + +.PHONY: test diff --git a/node_modules/mongoose/node_modules/mquery/README.md b/node_modules/mongoose/node_modules/mquery/README.md new file mode 100644 index 0000000..8e6317e --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/README.md @@ -0,0 +1,979 @@ +#mquery +=========== + +`mquery` is a fluent mongodb query builder designed to run in multiple environments. As of v0.1, `mquery` runs on `Node.js` only with support for the MongoDB shell and browser environments planned for upcoming releases. + +##Features + + - fluent query builder api + - custom base query support + - MongoDB 2.4 geoJSON support + - method + option combinations validation + - node.js driver compatibility + - environment detection + - [debug](https://github.com/visionmedia/debug) support + - separated collection implementations for maximum flexibility + +[![Build Status](https://travis-ci.org/aheckmann/mquery.png)](https://travis-ci.org/aheckmann/mquery) + +##Use + +```js +require('mongodb').connect(uri, function (err, db) { + if (err) return handleError(err); + + // get a collection + var collection = db.collection('artists'); + + // pass it to the constructor + mquery(collection).find({..}, callback); + + // or pass it to the collection method + mquery().find({..}).collection(collection).exec(callback) + + // or better yet, create a custom query constructor that has it always set + var Artist = mquery(collection).toConstructor(); + Artist().find(..).where(..).exec(callback) +}) +``` + +`mquery` requires a collection object to work with. In the example above we just pass the collection object created using the official [MongoDB driver](https://github.com/mongodb/node-mongodb-native). + + +##Fluent API + +###find() + +Declares this query a _find_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed. + +```js +mquery().find() +mquery().find(match) +mquery().find(callback) +mquery().find(match, function (err, docs) { + assert(Array.isArray(docs)); +}) +``` + +###findOne() + +Declares this query a _findOne_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed. + +```js +mquery().findOne() +mquery().findOne(match) +mquery().findOne(callback) +mquery().findOne(match, function (err, doc) { + if (doc) { + // the document may not be found + console.log(doc); + } +}) +``` + +###count() + +Declares this query a _count_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed. + +```js +mquery().count() +mquery().count(match) +mquery().count(callback) +mquery().count(match, function (err, number){ + console.log('we found %d matching documents', number); +}) +``` + +###remove() + +Declares this query a _remove_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed. + +```js +mquery().remove() +mquery().remove(match) +mquery().remove(callback) +mquery().remove(match, function (err){}) +``` + +###update() + +Declares this query an _update_ query. Optionally pass an update document, match clause, options or callback. If a callback is passed, the query is executed. To force execution without passing a callback, run `update(true)`. + +```js +mquery().update() +mquery().update(match, updateDocument) +mquery().update(match, updateDocument, options) + +// the following all execute the command +mquery().update(callback) +mquery().update({$set: updateDocument, callback) +mquery().update(match, updateDocument, callback) +mquery().update(match, updateDocument, options, function (err, result){}) +mquery().update(true) // executes (unsafe write) +``` + +#####the update document + +All paths passed that are not `$atomic` operations will become `$set` ops. For example: + +```js +mquery(collection).where({ _id: id }).update({ title: 'words' }, callback) +``` + +becomes + +```js +collection.update({ _id: id }, { $set: { title: 'words' }}, callback) +``` + +This behavior can be overridden using the `overwrite` option (see below). + +#####options + +Options are passed to the `setOptions()` method. + +- overwrite + +Passing an empty object `{ }` as the update document will result in a no-op unless the `overwrite` option is passed. Without the `overwrite` option, the update operation will be ignored and the callback executed without sending the command to MongoDB to prevent accidently overwritting documents in the collection. + +```js +var q = mquery(collection).where({ _id: id }).setOptions({ overwrite: true }); +q.update({ }, callback); // overwrite with an empty doc +``` + +The `overwrite` option isn't just for empty objects, it also provides a means to override the default `$set` conversion and send the update document as is. + +```js +// create a base query +var base = mquery({ _id: 108 }).collection(collection).toConstructor(); + +base().findOne(function (err, doc) { + console.log(doc); // { _id: 108, name: 'cajon' }) + + base().setOptions({ overwrite: true }).update({ changed: true }, function (err) { + base.findOne(function (err, doc) { + console.log(doc); // { _id: 108, changed: true }) - the doc was overwritten + }); + }); +}) +``` + +- multi + +Updates only modify a single document by default. To update multiple documents, set the `multi` option to `true`. + +```js +mquery() + .collection(coll) + .update({ name: /^match/ }, { $addToSet: { arr: 4 }}, { multi: true }, callback) + +// another way of doing it +mquery({ name: /^match/ }) + .collection(coll) + .setOptions({ multi: true }) + .update({ $addToSet: { arr: 4 }}, callback) + +// update multiple documents with an empty doc +var q = mquery(collection).where({ name: /^match/ }); +q.setOptions({ multi: true, overwrite: true }) +q.update({ }); +q.update(function (err, result) { + console.log(arguments); +}); +``` + +###findOneAndUpdate() + +Declares this query a _findAndModify_ with update query. Optionally pass a match clause, update document, options, or callback. If a callback is passed, the query is executed. + +When executed, the first matching document (if found) is modified according to the update document and passed back to the callback. + +#####options + +Options are passed to the `setOptions()` method. + +- `new`: boolean - true to return the modified document rather than the original. defaults to true +- `upsert`: boolean - creates the object if it doesn't exist. defaults to false +- `sort`: if multiple docs are found by the match condition, sets the sort order to choose which doc to update + +```js +query.findOneAndUpdate() +query.findOneAndUpdate(updateDocument) +query.findOneAndUpdate(match, updateDocument) +query.findOneAndUpdate(match, updateDocument, options) + +// the following all execute the command +query.findOneAndUpdate(callback) +query.findOneAndUpdate(updateDocument, callback) +query.findOneAndUpdate(match, updateDocument, callback) +query.findOneAndUpdate(match, updateDocument, options, function (err, doc) { + if (doc) { + // the document may not be found + console.log(doc); + } +}) + ``` + +###findOneAndRemove() + +Declares this query a _findAndModify_ with remove query. Optionally pass a match clause, options, or callback. If a callback is passed, the query is executed. + +When executed, the first matching document (if found) is modified according to the update document, removed from the collection and passed to the callback. + +#####options + +Options are passed to the `setOptions()` method. + +- `sort`: if multiple docs are found by the condition, sets the sort order to choose which doc to modify and remove + +```js +A.where().findOneAndRemove() +A.where().findOneAndRemove(match) +A.where().findOneAndRemove(match, options) + +// the following all execute the command +A.where().findOneAndRemove(callback) +A.where().findOneAndRemove(match, callback) +A.where().findOneAndRemove(match, options, function (err, doc) { + if (doc) { + // the document may not be found + console.log(doc); + } +}) + ``` + +###distinct() + +Declares this query a _distinct_ query. Optionally pass the distinct field, a match clause or callback. If a callback is passed the query is executed. + +```js +mquery().distinct() +mquery().distinct(match) +mquery().distinct(match, field) +mquery().distinct(field) + +// the following all execute the command +mquery().distinct(callback) +mquery().distinct(field, callback) +mquery().distinct(match, callback) +mquery().distinct(match, field, function (err, result) { + console.log(result); +}) +``` + +###exec() + +Executes the query. + +```js +mquery().findOne().where('route').intersects(polygon).exec(function (err, docs){}) +``` + +------------- + +###all() + +Specifies an `$all` query condition + +```js +mquery().where('permission').all(['read', 'write']) +``` + +[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/all/) + +###and() + +Specifies arguments for an `$and` condition + +```js +mquery().and([{ color: 'green' }, { status: 'ok' }]) +``` + +[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/and/) + +###box() + +Specifies a `$box` condition + +```js +var lowerLeft = [40.73083, -73.99756] +var upperRight= [40.741404, -73.988135] + +mquery().where('location').within().box(lowerLeft, upperRight) +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/box/) + +###circle() + +Specifies a `$center` or `$centerSphere` condition. + +```js +var area = { center: [50, 50], radius: 10, unique: true } +query.where('loc').within().circle(area) +query.circle('loc', area); + +// for spherical calculations +var area = { center: [50, 50], radius: 10, unique: true, spherical: true } +query.where('loc').within().circle(area) +query.circle('loc', area); +``` + +- [MongoDB Documentation - center](http://docs.mongodb.org/manual/reference/operator/center/) +- [MongoDB Documentation - centerSphere](http://docs.mongodb.org/manual/reference/operator/centerSphere/) + +###elemMatch() + +Specifies an `$elemMatch` condition + +```js +query.where('comment').elemMatch({ author: 'autobot', votes: {$gte: 5}}) + +query.elemMatch('comment', function (elem) { + elem.where('author').equals('autobot'); + elem.where('votes').gte(5); +}) +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/elemMatch/) + +###equals() + +Specifies the complementary comparison value for the path specified with `where()`. + +```js +mquery().where('age').equals(49); + +// is the same as + +mquery().where({ 'age': 49 }); +``` + +###exists() + +Specifies an `$exists` condition + +```js +// { name: { $exists: true }} +mquery().where('name').exists() +mquery().where('name').exists(true) +mquery().exists('name') + +// { name: { $exists: false }} +mquery().where('name').exists(false); +mquery().exists('name', false); +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/exists/) + +###geometry() + +Specifies a `$geometry` condition + +```js +var polyA = [[[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]] +query.where('loc').within().geometry({ type: 'Polygon', coordinates: polyA }) + +// or +var polyB = [[ 0, 0 ], [ 1, 1 ]] +query.where('loc').within().geometry({ type: 'LineString', coordinates: polyB }) + +// or +var polyC = [ 0, 0 ] +query.where('loc').within().geometry({ type: 'Point', coordinates: polyC }) + +// or +query.where('loc').intersects().geometry({ type: 'Point', coordinates: polyC }) + +// or +query.where('loc').near().geometry({ type: 'Point', coordinates: [3,5] }) +``` + +`geometry()` **must** come after `intersects()`, `within()`, or `near()`. + +The `object` argument must contain `type` and `coordinates` properties. + +- type `String` +- coordinates `Array` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/geometry/) + +###gt() + +Specifies a `$gt` query condition. + +```js +mquery().where('clicks').gt(999) +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/gt/) + +###gte() + +Specifies a `$gte` query condition. + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/gte/) + +```js +mquery().where('clicks').gte(1000) +``` + +###in() + +Specifies an `$in` query condition. + +```js +mquery().where('author_id').in([3, 48901, 761]) +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/in/) + +###intersects() + +Declares an `$geoIntersects` query for `geometry()`. + +```js +query.where('path').intersects().geometry({ + type: 'LineString' + , coordinates: [[180.0, 11.0], [180, 9.0]] +}) + +// geometry arguments are supported +query.where('path').intersects({ + type: 'LineString' + , coordinates: [[180.0, 11.0], [180, 9.0]] +}) +``` + +**Must** be used after `where()`. + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/geoIntersects/) + +###lt() + +Specifies a `$lt` query condition. + +```js +mquery().where('clicks').lt(50) +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/lt/) + +###lte() + +Specifies a `$lte` query condition. + +```js +mquery().where('clicks').lte(49) +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/lte/) + +###maxDistance() + +Specifies a `$maxDistance` query condition. + +```js +mquery().where('location').near({ center: [139, 74.3] }).maxDistance(5) +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/maxDistance/) + +###mod() + +Specifies a `$mod` condition + +```js +mquery().where('count').mod(2, 0) +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/mod/) + +###ne() + +Specifies a `$ne` query condition. + +```js +mquery().where('status').ne('ok') +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/ne/) + +###nin() + +Specifies an `$nin` query condition. + +```js +mquery().where('author_id').nin([3, 48901, 761]) +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/nin/) + +###nor() + +Specifies arguments for an `$nor` condition. + +```js +mquery().nor([{ color: 'green' }, { status: 'ok' }]) +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/nor/) + +###near() + +Specifies arguments for a `$near` or `$nearSphere` condition. + +These operators return documents sorted by distance. + +####Example + +```js +query.where('loc').near({ center: [10, 10] }); +query.where('loc').near({ center: [10, 10], maxDistance: 5 }); +query.near('loc', { center: [10, 10], maxDistance: 5 }); + +// GeoJSON +query.where('loc').near({ center: { type: 'Point', coordinates: [10, 10] }}); +query.where('loc').near({ center: { type: 'Point', coordinates: [10, 10] }, maxDistance: 5, spherical: true }); +query.where('loc').near().geometry({ type: 'Point', coordinates: [10, 10] }); + +// For a $nearSphere condition, pass the `spherical` option. +query.near({ center: [10, 10], maxDistance: 5, spherical: true }); +``` + +[MongoDB Documentation](http://www.mongodb.org/display/DOCS/Geospatial+Indexing) + +###or() + +Specifies arguments for an `$or` condition. + +```js +mquery().or([{ color: 'red' }, { status: 'emergency' }]) +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/or/) + +###polygon() + +Specifies a `$polygon` condition + +```js +mquery().where('loc').within().polygon([10,20], [13, 25], [7,15]) +mquery().polygon('loc', [10,20], [13, 25], [7,15]) +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/polygon/) + +###regex() + +Specifies a `$regex` query condition. + +```js +mquery().where('name').regex(/^sixstepsrecords/) +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/regex/) + +###select() + +Specifies which document fields to include or exclude + +```js +// 1 means include, 0 means exclude +mquery().select({ name: 1, address: 1, _id: 0 }) + +// or + +mquery().select('name address -_id') +``` + +#####String syntax + +When passing a string, prefixing a path with `-` will flag that path as excluded. When a path does not have the `-` prefix, it is included. + +```js +// include a and b, exclude c +query.select('a b -c'); + +// or you may use object notation, useful when +// you have keys already prefixed with a "-" +query.select({a: 1, b: 1, c: 0}); +``` + +_Cannot be used with `distinct()`._ + +###size() + +Specifies a `$size` query condition. + +```js +mquery().where('someArray').size(6) +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/size/) + +###slice() + +Specifies a `$slice` projection for a `path` + +```js +mquery().where('comments').slice(5) +mquery().where('comments').slice(-5) +mquery().where('comments').slice([-10, 5]) +``` + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/projection/slice/) + +###within() + +Sets a `$geoWithin` or `$within` argument for geo-spatial queries. + +```js +mquery().within().box() +mquery().within().circle() +mquery().within().geometry() + +mquery().where('loc').within({ center: [50,50], radius: 10, unique: true, spherical: true }); +mquery().where('loc').within({ box: [[40.73, -73.9], [40.7, -73.988]] }); +mquery().where('loc').within({ polygon: [[],[],[],[]] }); + +mquery().where('loc').within([], [], []) // polygon +mquery().where('loc').within([], []) // box +mquery().where('loc').within({ type: 'LineString', coordinates: [...] }); // geometry +``` + +As of mquery 2.0, `$geoWithin` is used by default. This impacts you if running MongoDB < 2.4. To alter this behavior, see [mquery.use$geoWithin](#mqueryusegeowithin). + +**Must** be used after `where()`. + +[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/geoWithin/) + +###where() + +Specifies a `path` for use with chaining + +```js +// instead of writing: +mquery().find({age: {$gte: 21, $lte: 65}}); + +// we can instead write: +mquery().where('age').gte(21).lte(65); + +// passing query conditions is permitted too +mquery().find().where({ name: 'vonderful' }) + +// chaining +mquery() +.where('age').gte(21).lte(65) +.where({ 'name': /^vonderful/i }) +.where('friends').slice(10) +.exec(callback) +``` + +###$where() + +Specifies a `$where` condition. + +Use `$where` when you need to select documents using a JavaScript expression. + +```js +query.$where('this.comments.length > 10 || this.name.length > 5').exec(callback) + +query.$where(function () { + return this.comments.length > 10 || this.name.length > 5; +}) +``` + +Only use `$where` when you have a condition that cannot be met using other MongoDB operators like `$lt`. Be sure to read about all of [its caveats](http://docs.mongodb.org/manual/reference/operator/where/) before using. + +----------- + +###batchSize() + +Specifies the batchSize option. + +```js +query.batchSize(100) +``` + +_Cannot be used with `distinct()`._ + +[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.batchSize/) + +###comment() + +Specifies the comment option. + +```js +query.comment('login query'); +``` + +_Cannot be used with `distinct()`._ + +[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/) + +###hint() + +Sets query hints. + +```js +mquery().hint({ indexA: 1, indexB: -1 }) +``` + +_Cannot be used with `distinct()`._ + +[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/hint/) + +###limit() + +Specifies the limit option. + +```js +query.limit(20) +``` + +_Cannot be used with `distinct()`._ + +[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.limit/) + +###maxScan() + +Specifies the maxScan option. + +```js +query.maxScan(100) +``` + +_Cannot be used with `distinct()`._ + +[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/maxScan/) + +###skip() + +Specifies the skip option. + +```js +query.skip(100).limit(20) +``` + +_Cannot be used with `distinct()`._ + +[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.skip/) + +###sort() + +Sets the query sort order. + +If an object is passed, key values allowed are `asc`, `desc`, `ascending`, `descending`, `1`, and `-1`. + +If a string is passed, it must be a space delimited list of path names. The sort order of each path is ascending unless the path name is prefixed with `-` which will be treated as descending. + +```js +// these are equivalent +query.sort({ field: 'asc', test: -1 }); +query.sort('field -test'); +``` + +_Cannot be used with `distinct()`._ + +[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.sort/) + +###read() + +Sets the readPreference option for the query. + +```js +mquery().read('primary') +mquery().read('p') // same as primary + +mquery().read('primaryPreferred') +mquery().read('pp') // same as primaryPreferred + +mquery().read('secondary') +mquery().read('s') // same as secondary + +mquery().read('secondaryPreferred') +mquery().read('sp') // same as secondaryPreferred + +mquery().read('nearest') +mquery().read('n') // same as nearest + +// specifying tags +mquery().read('s', [{ dc:'sf', s: 1 },{ dc:'ma', s: 2 }]) +``` + +#####Preferences: + +- `primary` - (default) Read from primary only. Operations will produce an error if primary is unavailable. Cannot be combined with tags. +- `secondary` - Read from secondary if available, otherwise error. +- `primaryPreferred` - Read from primary if available, otherwise a secondary. +- `secondaryPreferred` - Read from a secondary if available, otherwise read from the primary. +- `nearest` - All operations read from among the nearest candidates, but unlike other modes, this option will include both the primary and all secondaries in the random selection. + +Aliases + +- `p` primary +- `pp` primaryPreferred +- `s` secondary +- `sp` secondaryPreferred +- `n` nearest + +Read more about how to use read preferrences [here](http://docs.mongodb.org/manual/applications/replication/#read-preference) and [here](http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences). + +###slaveOk() + +Sets the slaveOk option. `true` allows reading from secondaries. + +**deprecated** use [read()](#read) preferences instead if on mongodb >= 2.2 + +```js +query.slaveOk() // true +query.slaveOk(true) +query.slaveOk(false) +``` + +[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/rs.slaveOk/) + +###snapshot() + +Specifies this query as a snapshot query. + +```js +mquery().snapshot() // true +mquery().snapshot(true) +mquery().snapshot(false) +``` + +_Cannot be used with `distinct()`._ + +[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/snapshot/) + +###tailable() + +Sets tailable option. + +```js +mquery().tailable() <== true +mquery().tailable(true) +mquery().tailable(false) +``` + +_Cannot be used with `distinct()`._ + +[MongoDB Documentation](http://docs.mongodb.org/manual/tutorial/create-tailable-cursor/) + +##Helpers + +###collection() + +Sets the querys collection. + +```js +mquery().collection(aCollection) +``` + + +###merge(object) + +Merges other mquery or match condition objects into this one. When an muery instance is passed, its match conditions, field selection and options are merged. + +```js +var drum = mquery({ type: 'drum' }).collection(instruments); +var redDrum = mqery({ color: 'red' }).merge(drum); +redDrum.count(function (err, n) { + console.log('there are %d red drums', n); +}) +``` + +Internally uses `mquery.canMerge` to determine validity. + +###setOptions(options) + +Sets query options. + +```js +mquery().setOptions({ collection: coll, limit: 20 }) +``` + +#####options + +- [tailable](#tailable) * +- [sort](#sort) * +- [limit](#limit) * +- [skip](#skip) * +- [maxScan](#maxScan) * +- [batchSize](#batchSize) * +- [comment](#comment) * +- [snapshot](#snapshot) * +- [hint](#hint) * +- [slaveOk](#slaveOk) * +- [safe](http://docs.mongodb.org/manual/reference/write-concern/): Boolean - passed through to the collection. Setting to `true` is equivalent to `{ w: 1 }` +- [collection](#collection): the collection to query against + +_* denotes a query helper method is also available_ + +###mquery.canMerge(conditions) + +Determines if `conditions` can be merged using `mquery().merge()`. + +```js +var query = mquery({ type: 'drum' }); +var okToMerge = mquery.canMerge(anObject) +if (okToMerge) { + query.merge(anObject); +} +``` + +##mquery.use$geoWithin + +MongoDB 2.4 introduced the `$geoWithin` operator which replaces and is 100% backward compatible with `$within`. As of mquery 0.2, we default to using `$geoWithin` for all `within()` calls. + +If you are running MongoDB < 2.4 this will be problematic. To force `mquery` to be backward compatible and always use `$within`, set the `mquery.use$geoWithin` flag to `false`. + +```js +mquery.use$geoWithin = false; +``` + +##Custom Base Queries + +Often times we want custom base queries that encapsulate predefined criteria. With `mquery` this is easy. First create the query you want to reuse and call its `toConstructor()` method which returns a new subclass of `mquery` that retains all options and criteria of the original. + +```js +var greatMovies = mquery(movieCollection).where('rating').gte(4.5).toConstructor(); + +// use it! +greatMovies().count(function (err, n) { + console.log('There are %d great movies', n); +}); + +greatMovies().where({ name: /^Life/ }).select('name').find(function (err, docs) { + console.log(docs); +}); +``` + +##Validation + +Method and options combinations are checked for validity at runtime to prevent creation of invalid query constructs. For example, a `distinct` query does not support specifying options like `hint` or field selection. In this case an error will be thrown so you can catch these mistakes in development. + +##Debug support + +Debug mode is provided through the use of the [debug](https://github.com/visionmedia/debug) module. To enable: + + DEBUG=mquery node yourprogram.js + +Read the debug module documentation for more details. + +##Future goals + + - mongo shell compatibility + - browser compatibility + - mongoose compatibility + +## Installation + + $ npm install mquery + +## License + +[MIT](https://github.com/aheckmann/mquery/blob/master/LICENSE) + diff --git a/node_modules/mongoose/node_modules/mquery/index.js b/node_modules/mongoose/node_modules/mquery/index.js new file mode 100644 index 0000000..51b6f49 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/index.js @@ -0,0 +1 @@ +module.exports = exports = require('./lib/mquery'); diff --git a/node_modules/mongoose/node_modules/mquery/lib/collection/collection.js b/node_modules/mongoose/node_modules/mquery/lib/collection/collection.js new file mode 100644 index 0000000..b2882e5 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/lib/collection/collection.js @@ -0,0 +1,33 @@ +'use strict'; + +/** + * methods a collection must implement + */ + +var names = 'find findOne update remove count distict findAndModify aggregate'; +var methods = names.split(' '); + +/** + * Collection base class from which implementations inherit + */ + +function Collection () {} + +for (var i = 0, len = methods.length; i < len; ++i) { + var method = methods[i]; + Collection.prototype[method] = notImplemented(method); +} + +module.exports = exports = Collection; +Collection.methods = methods; + +/** + * creates a function which throws an implementation error + */ + +function notImplemented (method) { + return function () { + throw new Error('collection.' + method + ' not implemented'); + } +} + diff --git a/node_modules/mongoose/node_modules/mquery/lib/collection/index.js b/node_modules/mongoose/node_modules/mquery/lib/collection/index.js new file mode 100644 index 0000000..8ea6090 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/lib/collection/index.js @@ -0,0 +1,13 @@ +'use strict'; + +var env = require('../env') + +if ('unknown' == env.type) { + throw new Error('Unknown environment') +} + +module.exports = + env.isNode ? require('./node') : + env.isMongo ? require('./mongo') : + require('./browser'); + diff --git a/node_modules/mongoose/node_modules/mquery/lib/collection/node.js b/node_modules/mongoose/node_modules/mquery/lib/collection/node.js new file mode 100644 index 0000000..577d437 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/lib/collection/node.js @@ -0,0 +1,96 @@ +'use strict'; + +/** + * Module dependencies + */ + +var Collection = require('./collection'); +var utils = require('../utils'); + +function NodeCollection (col) { + this.collection = col; +} + +/** + * inherit from collection base class + */ + +utils.inherits(NodeCollection, Collection); + +/** + * find(match, options, function(err, docs)) + */ + +NodeCollection.prototype.find = function (match, options, cb) { + this.collection.find(match, options, function (err, cursor) { + if (err) return cb(err); + + cursor.toArray(cb); + }); +} + +/** + * findOne(match, options, function(err, doc)) + */ + +NodeCollection.prototype.findOne = function (match, options, cb) { + this.collection.findOne(match, options, cb); +} + +/** + * count(match, options, function(err, count)) + */ + +NodeCollection.prototype.count = function (match, options, cb) { + this.collection.count(match, options, cb); +} + +/** + * distinct(prop, match, options, function(err, count)) + */ + +NodeCollection.prototype.distinct = function (prop, match, options, cb) { + this.collection.distinct(prop, match, options, cb); +} + +/** + * update(match, update, options, function(err[, result])) + */ + +NodeCollection.prototype.update = function (match, update, options, cb) { + this.collection.update(match, update, options, cb); +} + +/** + * remove(match, options, function(err[, result]) + */ + +NodeCollection.prototype.remove = function (match, options, cb) { + this.collection.remove(match, options, cb); +} + +/** + * findAndModify(match, update, options, function(err, doc)) + */ + +NodeCollection.prototype.findAndModify = function (match, update, options, cb) { + var sort = Array.isArray(options.sort) ? options.sort : []; + this.collection.findAndModify(match, sort, update, options, cb); +} + +/** + * aggregation(operators..., function(err, doc)) + * TODO + */ + +/** + * Streams + * TODO + */ + +/** + * Expose + */ + +module.exports = exports = NodeCollection; + diff --git a/node_modules/mongoose/node_modules/mquery/lib/env.js b/node_modules/mongoose/node_modules/mquery/lib/env.js new file mode 100644 index 0000000..3313b46 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/lib/env.js @@ -0,0 +1,22 @@ +'use strict'; + +exports.isNode = 'undefined' != typeof process + && 'object' == typeof module + && 'object' == typeof global + && 'function' == typeof Buffer + && process.argv + +exports.isMongo = !exports.isNode + && 'function' == typeof printjson + && 'function' == typeof ObjectId + && 'function' == typeof rs + && 'function' == typeof sh; + +exports.isBrowser = !exports.isNode + && !exports.isMongo + && 'undefined' != typeof window; + +exports.type = exports.isNode ? 'node' + : exports.isMongo ? 'mongo' + : exports.isBrowser ? 'browser' + : 'unknown' diff --git a/node_modules/mongoose/node_modules/mquery/lib/mquery.js b/node_modules/mongoose/node_modules/mquery/lib/mquery.js new file mode 100644 index 0000000..6d190bf --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/lib/mquery.js @@ -0,0 +1,2335 @@ +'use strict'; + +/** + * Dependencies + */ + +var slice = require('sliced') +var assert = require('assert') +var util = require('util') +var utils = require('./utils') +var debug = require('debug')('mquery'); + +/** + * Query constructor used for building queries. + * + * ####Example: + * + * var query = new Query({ name: 'mquery' }); + * query.setOptions({ collection: moduleCollection }) + * query.where('age').gte(21).exec(callback); + * + * @param {Object} [criteria] + * @param {Object} [options] + * @api public + */ + +function Query (criteria, options) { + if (!(this instanceof Query)) + return new Query(criteria, options); + + var proto = this.constructor.prototype; + + this.op = proto.op || undefined; + + this.options = {}; + this.setOptions(proto.options); + + this._conditions = proto._conditions + ? utils.clone(proto._conditions) + : {}; + + this._fields = proto._fields + ? utils.clone(proto._fields) + : undefined; + + this._update = proto._update + ? utils.clone(proto._update) + : undefined; + + this._path = proto._path || undefined; + this._distinct = proto._distinct || undefined; + this._collection = proto._collection || undefined; + + if (options) { + this.setOptions(options); + } + + if (criteria) { + if (criteria.find && criteria.remove && criteria.update) { + // quack quack! + this.collection(criteria); + } else { + this.find(criteria); + } + } +} + +/** + * This is a parameter that the user can set which determines if mquery + * uses $within or $geoWithin for queries. It defaults to true which + * means $geoWithin will be used. If using MongoDB < 2.4 you should + * set this to false. + * + * @api public + * @property use$geoWithin + */ + +var $withinCmd = '$geoWithin'; +Object.defineProperty(Query, 'use$geoWithin', { + get: function ( ) { return $withinCmd == '$geoWithin' } + , set: function (v) { + if (true === v) { + // mongodb >= 2.4 + $withinCmd = '$geoWithin'; + } else { + $withinCmd = '$within'; + } + } +}); + +/** + * Converts this query to a constructor function with all arguments and options retained. + * + * ####Example + * + * // Create a query that will read documents with a "video" category from + * // `aCollection` on the primary node in the replica-set unless it is down, + * // in which case we'll read from a secondary node. + * var query = mquery({ category: 'video' }) + * query.setOptions({ collection: aCollection, read: 'primaryPreferred' }); + * + * // create a constructor based off these settings + * var Video = query.toConstructor(); + * + * // Video is now a subclass of mquery() and works the same way but with the + * // default query parameters and options set. + * + * // run a query with the previous settings but filter for movies with names + * // that start with "Life". + * Video().where({ name: /^Life/ }).exec(cb); + * + * @return {Query} new Query + * @api public + */ + +Query.prototype.toConstructor = function toConstructor () { + function CustomQuery (criteria, options) { + if (!(this instanceof CustomQuery)) + return new CustomQuery(criteria, options); + Query.call(this, criteria, options); + } + + utils.inherits(CustomQuery, Query); + + // set inherited defaults + var p = CustomQuery.prototype; + + p.options = {}; + p.setOptions(this.options); + + p.op = this.op; + p._conditions = utils.clone(this._conditions); + p._fields = utils.clone(this._fields); + p._update = utils.clone(this._update); + p._path = this._path; + p._distict = this._distinct; + p._collection = this._collection; + + return CustomQuery; +} + +/** + * Sets query options. + * + * ####Options: + * + * - [tailable](http://www.mongodb.org/display/DOCS/Tailable+Cursors) * + * - [sort](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bsort(\)%7D%7D) * + * - [limit](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Blimit%28%29%7D%7D) * + * - [skip](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bskip%28%29%7D%7D) * + * - [maxScan](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24maxScan) * + * - [batchSize](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7BbatchSize%28%29%7D%7D) * + * - [comment](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24comment) * + * - [snapshot](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bsnapshot%28%29%7D%7D) * + * - [hint](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24hint) * + * - [slaveOk](http://docs.mongodb.org/manual/applications/replication/#read-preference) * + * - [safe](http://www.mongodb.org/display/DOCS/getLastError+Command) + * - collection the collection to query against + * + * _* denotes a query helper method is also available_ + * + * @param {Object} options + * @api public + */ + +Query.prototype.setOptions = function (options) { + if (!(options && utils.isObject(options))) + return this; + + // set arbitrary options + var methods = utils.keys(options) + , method + + for (var i = 0; i < methods.length; ++i) { + method = methods[i]; + + // use methods if exist (safer option manipulation) + if ('function' == typeof this[method]) { + var args = utils.isArray(options[method]) + ? options[method] + : [options[method]]; + this[method].apply(this, args) + } else { + this.options[method] = options[method]; + } + } + + return this; +} + +/** + * Sets this Querys collection. + * + * @param {Collection} coll + * @return {Query} this + */ + +Query.prototype.collection = function collection (coll) { + this._collection = new Query.Collection(coll); + + return this; +} + +/** + * Specifies a `$where` condition + * + * Use `$where` when you need to select documents using a JavaScript expression. + * + * ####Example + * + * query.$where('this.comments.length > 10 || this.name.length > 5') + * + * query.$where(function () { + * return this.comments.length > 10 || this.name.length > 5; + * }) + * + * @param {String|Function} js javascript string or function + * @return {Query} this + * @memberOf Query + * @method $where + * @api public + */ + +Query.prototype.$where = function (js) { + this._conditions.$where = js; + return this; +} + +/** + * Specifies a `path` for use with chaining. + * + * ####Example + * + * // instead of writing: + * User.find({age: {$gte: 21, $lte: 65}}, callback); + * + * // we can instead write: + * User.where('age').gte(21).lte(65); + * + * // passing query conditions is permitted + * User.find().where({ name: 'vonderful' }) + * + * // chaining + * User + * .where('age').gte(21).lte(65) + * .where('name', /^vonderful/i) + * .where('friends').slice(10) + * .exec(callback) + * + * @param {String} [path] + * @param {Object} [val] + * @return {Query} this + * @api public + */ + +Query.prototype.where = function () { + if (!arguments.length) return this; + if (!this.op) this.op = 'find'; + + var type = typeof arguments[0]; + + if ('string' == type) { + this._path = arguments[0]; + + if (2 === arguments.length) { + this._conditions[this._path] = arguments[1]; + } + + return this; + } + + if ('object' == type && !Array.isArray(arguments[0])) { + return this.merge(arguments[0]); + } + + throw new TypeError('path must be a string or object'); +} + +/** + * Specifies the complementary comparison value for paths specified with `where()` + * + * ####Example + * + * User.where('age').equals(49); + * + * // is the same as + * + * User.where('age', 49); + * + * @param {Object} val + * @return {Query} this + * @api public + */ + +Query.prototype.equals = function equals (val) { + this._ensurePath('equals'); + var path = this._path; + this._conditions[path] = val; + return this; +} + +/** + * Specifies arguments for an `$or` condition. + * + * ####Example + * + * query.or([{ color: 'red' }, { status: 'emergency' }]) + * + * @param {Array} array array of conditions + * @return {Query} this + * @api public + */ + +Query.prototype.or = function or (array) { + var or = this._conditions.$or || (this._conditions.$or = []); + if (!utils.isArray(array)) array = [array]; + or.push.apply(or, array); + return this; +} + +/** + * Specifies arguments for a `$nor` condition. + * + * ####Example + * + * query.nor([{ color: 'green' }, { status: 'ok' }]) + * + * @param {Array} array array of conditions + * @return {Query} this + * @api public + */ + +Query.prototype.nor = function nor (array) { + var nor = this._conditions.$nor || (this._conditions.$nor = []); + if (!utils.isArray(array)) array = [array]; + nor.push.apply(nor, array); + return this; +} + +/** + * Specifies arguments for a `$and` condition. + * + * ####Example + * + * query.and([{ color: 'green' }, { status: 'ok' }]) + * + * @see $and http://docs.mongodb.org/manual/reference/operator/and/ + * @param {Array} array array of conditions + * @return {Query} this + * @api public + */ + +Query.prototype.and = function and (array) { + var and = this._conditions.$and || (this._conditions.$and = []); + if (!Array.isArray(array)) array = [array]; + and.push.apply(and, array); + return this; +} + +/** + * Specifies a $gt query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * ####Example + * + * Thing.find().where('age').gt(21) + * + * // or + * Thing.find().gt('age', 21) + * + * @method gt + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies a $gte query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @method gte + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies a $lt query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @method lt + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies a $lte query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @method lte + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies a $ne query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @method ne + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies an $in query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @method in + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies an $nin query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @method nin + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies an $all query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @method all + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies a $size query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @method size + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies a $regex query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @method regex + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/** + * Specifies a $maxDistance query condition. + * + * When called with one argument, the most recent path passed to `where()` is used. + * + * @method maxDistance + * @memberOf Query + * @param {String} [path] + * @param {Number} val + * @api public + */ + +/*! + * gt, gte, lt, lte, ne, in, nin, all, regex, size, maxDistance + * + * Thing.where('type').nin(array) + */ + +'gt gte lt lte ne in nin all regex size maxDistance'.split(' ').forEach(function ($conditional) { + Query.prototype[$conditional] = function () { + var path, val; + + if (1 === arguments.length) { + this._ensurePath($conditional); + val = arguments[0]; + path = this._path; + } else { + val = arguments[1]; + path = arguments[0]; + } + + var conds = this._conditions[path] || (this._conditions[path] = {}); + conds['$' + $conditional] = val; + return this; + }; +}) + +/** + * Specifies a `$mod` condition + * + * @param {String} [path] + * @param {Number} val + * @return {Query} this + * @api public + */ + +Query.prototype.mod = function () { + var val, path; + + if (1 === arguments.length) { + this._ensurePath('mod') + val = arguments[0]; + path = this._path; + } else if (2 === arguments.length && !utils.isArray(arguments[1])) { + this._ensurePath('mod') + val = slice(arguments); + path = this._path; + } else if (3 === arguments.length) { + val = slice(arguments, 1); + path = arguments[0]; + } else { + val = arguments[1]; + path = arguments[0]; + } + + var conds = this._conditions[path] || (this._conditions[path] = {}); + conds.$mod = val; + return this; +} + +/** + * Specifies an `$exists` condition + * + * ####Example + * + * // { name: { $exists: true }} + * Thing.where('name').exists() + * Thing.where('name').exists(true) + * Thing.find().exists('name') + * + * // { name: { $exists: false }} + * Thing.where('name').exists(false); + * Thing.find().exists('name', false); + * + * @param {String} [path] + * @param {Number} val + * @return {Query} this + * @api public + */ + +Query.prototype.exists = function () { + var path, val; + + if (0 === arguments.length) { + this._ensurePath('exists'); + path = this._path; + val = true; + } else if (1 === arguments.length) { + if ('boolean' === typeof arguments[0]) { + this._ensurePath('exists'); + path = this._path; + val = arguments[0]; + } else { + path = arguments[0]; + val = true; + } + } else if (2 === arguments.length) { + path = arguments[0]; + val = arguments[1]; + } + + var conds = this._conditions[path] || (this._conditions[path] = {}); + conds.$exists = val; + return this; +} + +/** + * Specifies an `$elemMatch` condition + * + * ####Example + * + * query.elemMatch('comment', { author: 'autobot', votes: {$gte: 5}}) + * + * query.where('comment').elemMatch({ author: 'autobot', votes: {$gte: 5}}) + * + * query.elemMatch('comment', function (elem) { + * elem.where('author').equals('autobot'); + * elem.where('votes').gte(5); + * }) + * + * query.where('comment').elemMatch(function (elem) { + * elem.where({ author: 'autobot' }); + * elem.where('votes').gte(5); + * }) + * + * @param {String|Object|Function} path + * @param {Object|Function} criteria + * @return {Query} this + * @api public + */ + +Query.prototype.elemMatch = function () { + if (null == arguments[0]) + throw new TypeError("Invalid argument"); + + var fn, path, criteria; + + if ('function' === typeof arguments[0]) { + this._ensurePath('elemMatch'); + path = this._path; + fn = arguments[0]; + } else if (utils.isObject(arguments[0])) { + this._ensurePath('elemMatch'); + path = this._path; + criteria = arguments[0]; + } else if ('function' === typeof arguments[1]) { + path = arguments[0]; + fn = arguments[1]; + } else if (arguments[1] && utils.isObject(arguments[1])) { + path = arguments[0]; + criteria = arguments[1]; + } else { + throw new TypeError("Invalid argument"); + } + + if (fn) { + criteria = new Query; + fn(criteria); + criteria = criteria._conditions; + } + + var conds = this._conditions[path] || (this._conditions[path] = {}); + conds.$elemMatch = criteria; + return this; +} + +// Spatial queries + +/** + * Sugar for geo-spatial queries. + * + * ####Example + * + * query.within().box() + * query.within().circle() + * query.within().geometry() + * + * query.where('loc').within({ center: [50,50], radius: 10, unique: true, spherical: true }); + * query.where('loc').within({ box: [[40.73, -73.9], [40.7, -73.988]] }); + * query.where('loc').within({ polygon: [[],[],[],[]] }); + * + * query.where('loc').within([], [], []) // polygon + * query.where('loc').within([], []) // box + * query.where('loc').within({ type: 'LineString', coordinates: [...] }); // geometry + * + * ####NOTE: + * + * Must be used after `where()`. + * + * @memberOf Query + * @return {Query} this + * @api public + */ + +Query.prototype.within = function within () { + // opinionated, must be used after where + this._ensurePath('within'); + this._geoComparison = $withinCmd; + + if (0 === arguments.length) { + return this; + } + + if (2 === arguments.length) { + return this.box.apply(this, arguments); + } else if (2 < arguments.length) { + return this.polygon.apply(this, arguments); + } + + var area = arguments[0]; + + if (!area) + throw new TypeError('Invalid argument'); + + if (area.center) + return this.circle(area); + + if (area.box) + return this.box.apply(this, area.box); + + if (area.polygon) + return this.polygon.apply(this, area.polygon); + + if (area.type && area.coordinates) + return this.geometry(area); + + throw new TypeError('Invalid argument'); +} + +/** + * Specifies a $box condition + * + * ####Example + * + * var lowerLeft = [40.73083, -73.99756] + * var upperRight= [40.741404, -73.988135] + * + * query.where('loc').within().box(lowerLeft, upperRight) + * query.box('loc', lowerLeft, upperRight ) + * + * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing + * @see Query#within #query_Query-within + * @param {String} path + * @param {Object} val + * @return {Query} this + * @api public + */ + +Query.prototype.box = function () { + var path, box; + + if (3 === arguments.length) { + // box('loc', [], []) + path = arguments[0]; + box = [arguments[1], arguments[2]]; + } else if (2 === arguments.length) { + // box([], []) + this._ensurePath('box'); + path = this._path; + box = [arguments[0], arguments[1]]; + } else { + throw new TypeError("Invalid argument"); + } + + var conds = this._conditions[path] || (this._conditions[path] = {}); + conds[this._geoComparison || $withinCmd] = { '$box': box }; + return this; +} + +/** + * Specifies a $polygon condition + * + * ####Example + * + * query.where('loc').within().polygon([10,20], [13, 25], [7,15]) + * query.polygon('loc', [10,20], [13, 25], [7,15]) + * + * @param {String|Array} [path] + * @param {Array|Object} [val] + * @return {Query} this + * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing + * @api public + */ + +Query.prototype.polygon = function () { + var val, path; + + if ('string' == typeof arguments[0]) { + // polygon('loc', [],[],[]) + path = arguments[0]; + val = slice(arguments, 1); + } else { + // polygon([],[],[]) + this._ensurePath('polygon'); + path = this._path; + val = slice(arguments); + } + + var conds = this._conditions[path] || (this._conditions[path] = {}); + conds[this._geoComparison || $withinCmd] = { '$polygon': val }; + return this; +} + +/** + * Specifies a $center or $centerSphere condition. + * + * ####Example + * + * var area = { center: [50, 50], radius: 10, unique: true } + * query.where('loc').within().circle(area) + * query.center('loc', area); + * + * // for spherical calculations + * var area = { center: [50, 50], radius: 10, unique: true, spherical: true } + * query.where('loc').within().circle(area) + * query.center('loc', area); + * + * @param {String} [path] + * @param {Object} area + * @return {Query} this + * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing + * @api public + */ + +Query.prototype.circle = function () { + var path, val; + + if (1 === arguments.length) { + this._ensurePath('circle'); + path = this._path; + val = arguments[0]; + } else if (2 === arguments.length) { + path = arguments[0]; + val = arguments[1]; + } else { + throw new TypeError("Invalid argument"); + } + + if (!('radius' in val && val.center)) + throw new Error('center and radius are required'); + + var conds = this._conditions[path] || (this._conditions[path] = {}); + + var type = val.spherical + ? '$centerSphere' + : '$center'; + + var wKey = this._geoComparison || $withinCmd; + conds[wKey] = {}; + conds[wKey][type] = [val.center, val.radius]; + + if ('unique' in val) + conds[wKey].$uniqueDocs = !! val.unique; + + return this; +} + +/** + * Specifies a `$near` or `$nearSphere` condition + * + * These operators return documents sorted by distance. + * + * ####Example + * + * query.where('loc').near({ center: [10, 10] }); + * query.where('loc').near({ center: [10, 10], maxDistance: 5 }); + * query.where('loc').near({ center: [10, 10], maxDistance: 5, spherical: true }); + * query.near('loc', { center: [10, 10], maxDistance: 5 }); + * query.near({ center: { type: 'Point', coordinates: [..] }}) + * query.near().geometry({ type: 'Point', coordinates: [..] }) + * + * @param {String} [path] + * @param {Object} val + * @return {Query} this + * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing + * @api public + */ + +Query.prototype.near = function near () { + var path, val; + + this._geoComparison = '$near'; + + if (0 === arguments.length) { + return this; + } else if (1 === arguments.length) { + this._ensurePath('near'); + path = this._path; + val = arguments[0]; + } else if (2 === arguments.length) { + path = arguments[0]; + val = arguments[1]; + } else { + throw new TypeError("Invalid argument"); + } + + if (!val.center) { + throw new Error('center is required'); + } + + var conds = this._conditions[path] || (this._conditions[path] = {}); + + var type = val.spherical + ? '$nearSphere' + : '$near'; + + // center could be a GeoJSON object or an Array + if (Array.isArray(val.center)) { + conds[type] = val.center; + } else { + // GeoJSON? + if (val.center.type != 'Point' || !Array.isArray(val.center.coordinates)) { + throw new Error(util.format("Invalid GeoJSON specified for %s", type)); + } + conds[type] = { $geometry : val.center }; + } + + var radius = 'maxDistance' in val + ? val.maxDistance + : null; + + if (null != radius) { + conds.$maxDistance = radius; + } + + return this; +} + +/** + * Declares an intersects query for `geometry()`. + * + * ####Example + * + * query.where('path').intersects().geometry({ + * type: 'LineString' + * , coordinates: [[180.0, 11.0], [180, 9.0]] + * }) + * + * query.where('path').intersects({ + * type: 'LineString' + * , coordinates: [[180.0, 11.0], [180, 9.0]] + * }) + * + * @param {Object} [arg] + * @return {Query} this + * @api public + */ + +Query.prototype.intersects = function intersects () { + // opinionated, must be used after where + this._ensurePath('intersects'); + + this._geoComparison = '$geoIntersects'; + + if (0 === arguments.length) { + return this; + } + + var area = arguments[0]; + + if (null != area && area.type && area.coordinates) + return this.geometry(area); + + throw new TypeError('Invalid argument'); +} + +/** + * Specifies a `$geometry` condition + * + * ####Example + * + * var polyA = [[[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]] + * query.where('loc').within().geometry({ type: 'Polygon', coordinates: polyA }) + * + * // or + * var polyB = [[ 0, 0 ], [ 1, 1 ]] + * query.where('loc').within().geometry({ type: 'LineString', coordinates: polyB }) + * + * // or + * var polyC = [ 0, 0 ] + * query.where('loc').within().geometry({ type: 'Point', coordinates: polyC }) + * + * // or + * query.where('loc').intersects().geometry({ type: 'Point', coordinates: polyC }) + * + * ####NOTE: + * + * `geometry()` **must** come after either `intersects()` or `within()`. + * + * The `object` argument must contain `type` and `coordinates` properties. + * - type {String} + * - coordinates {Array} + * + * The most recent path passed to `where()` is used. + * + * @param {Object} object Must contain a `type` property which is a String and a `coordinates` property which is an Array. See the examples. + * @return {Query} this + * @see http://docs.mongodb.org/manual/release-notes/2.4/#new-geospatial-indexes-with-geojson-and-improved-spherical-geometry + * @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing + * @see $geometry http://docs.mongodb.org/manual/reference/operator/geometry/ + * @api public + */ + +Query.prototype.geometry = function geometry () { + if (!('$within' == this._geoComparison || + '$geoWithin' == this._geoComparison || + '$near' == this._geoComparison || + '$geoIntersects' == this._geoComparison)) { + throw new Error('geometry() must come after `within()`, `intersects()`, or `near()'); + } + + var val, path; + + if (1 === arguments.length) { + this._ensurePath('geometry'); + path = this._path; + val = arguments[0]; + } else { + throw new TypeError("Invalid argument"); + } + + if (!(val.type && Array.isArray(val.coordinates))) { + throw new TypeError('Invalid argument'); + } + + var conds = this._conditions[path] || (this._conditions[path] = {}); + conds[this._geoComparison] = { $geometry: val }; + + return this; +} + +// end spatial + +/** + * Specifies which document fields to include or exclude + * + * ####String syntax + * + * When passing a string, prefixing a path with `-` will flag that path as excluded. When a path does not have the `-` prefix, it is included. + * + * ####Example + * + * // include a and b, exclude c + * query.select('a b -c'); + * + * // or you may use object notation, useful when + * // you have keys already prefixed with a "-" + * query.select({a: 1, b: 1, c: 0}); + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @param {Object|String} arg + * @return {Query} this + * @see SchemaType + * @api public + */ + +Query.prototype.select = function select () { + var arg = arguments[0]; + if (!arg) return this; + + if (arguments.length !== 1) { + throw new Error("Invalid select: select only takes 1 argument"); + } + + this._validate('select'); + + var fields = this._fields || (this._fields = {}); + var type = typeof arg; + + if ('string' == type || 'object' == type && 'number' == typeof arg.length && !Array.isArray(arg)) { + if ('string' == type) + arg = arg.split(/\s+/); + + for (var i = 0, len = arg.length; i < len; ++i) { + var field = arg[i]; + if (!field) continue; + var include = '-' == field[0] ? 0 : 1; + if (include === 0) field = field.substring(1); + fields[field] = include; + } + + return this; + } + + if (utils.isObject(arg) && !Array.isArray(arg)) { + var keys = utils.keys(arg); + for (var i = 0; i < keys.length; ++i) { + fields[keys[i]] = arg[keys[i]]; + } + return this; + } + + throw new TypeError('Invalid select() argument. Must be string or object.'); +} + +/** + * Specifies a $slice condition for a `path` + * + * ####Example + * + * query.slice('comments', 5) + * query.slice('comments', -5) + * query.slice('comments', [10, 5]) + * query.where('comments').slice(5) + * query.where('comments').slice([-10, 5]) + * + * @param {String} [path] + * @param {Number} val number/range of elements to slice + * @return {Query} this + * @see mongodb http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields#RetrievingaSubsetofFields-RetrievingaSubrangeofArrayElements + * @api public + */ + +Query.prototype.slice = function () { + if (0 === arguments.length) + return this; + + this._validate('slice'); + + var path, val; + + if (1 === arguments.length) { + this._ensurePath('slice'); + path = this._path; + val = arguments[0]; + } else if (2 === arguments.length) { + if ('number' === typeof arguments[0]) { + this._ensurePath('slice'); + path = this._path; + val = slice(arguments); + } else { + path = arguments[0]; + val = arguments[1]; + } + } else if (3 === arguments.length) { + path = arguments[0]; + val = slice(arguments, 1); + } + + var myFields = this._fields || (this._fields = {}); + myFields[path] = { '$slice': val }; + return this; +} + +/** + * Sets the sort order + * + * If an object is passed, values allowed are 'asc', 'desc', 'ascending', 'descending', 1, and -1. + * + * If a string is passed, it must be a space delimited list of path names. The sort order of each path is ascending unless the path name is prefixed with `-` which will be treated as descending. + * + * ####Example + * + * // these are equivalent + * query.sort({ field: 'asc', test: -1 }); + * query.sort('field -test'); + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @param {Object|String} arg + * @return {Query} this + * @api public + */ + +Query.prototype.sort = function (arg) { + if (!arg) return this; + + this._validate('sort'); + + var type = typeof arg; + + if (1 === arguments.length && 'string' == type) { + arg = arg.split(/\s+/); + + for (var i = 0, len = arg.length; i < len; ++i) { + var field = arg[i]; + if (!field) continue; + var ascend = '-' == field[0] ? -1 : 1; + if (ascend === -1) field = field.substring(1); + push(this.options, field, ascend); + } + + return this; + } + + if (utils.isObject(arg)) { + var keys = utils.keys(arg); + for (var i = 0; i < keys.length; ++i) { + var field = keys[i]; + push(this.options, field, arg[field]); + } + + return this; + } + + throw new TypeError('Invalid sort() argument. Must be a string or object.'); +} + +/*! + * @ignore + */ + +function push (opts, field, value) { + var val = String(value || 1).toLowerCase(); + if (!/^(?:ascending|asc|descending|desc|1|-1)$/.test(val)) { + if (utils.isArray(value)) value = '['+value+']'; + throw new TypeError('Invalid sort value: {' + field + ': ' + value + ' }'); + } + // store `sort` in a sane format + var s = opts.sort || (opts.sort = {}); + var valueStr = value.toString() + .replace("asc", "1") + .replace("ascending", "1") + .replace("desc", "-1") + .replace("descending", "-1"); + s[field] = parseInt(valueStr); +} + +/** + * Specifies the limit option. + * + * ####Example + * + * query.limit(20) + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @method limit + * @memberOf Query + * @param {Number} val + * @see mongodb http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Blimit%28%29%7D%7D + * @api public + */ +/** + * Specifies the skip option. + * + * ####Example + * + * query.skip(100).limit(20) + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @method skip + * @memberOf Query + * @param {Number} val + * @see mongodb http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bskip%28%29%7D%7D + * @api public + */ +/** + * Specifies the maxScan option. + * + * ####Example + * + * query.maxScan(100) + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @method maxScan + * @memberOf Query + * @param {Number} val + * @see mongodb http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24maxScan + * @api public + */ +/** + * Specifies the batchSize option. + * + * ####Example + * + * query.batchSize(100) + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @method batchSize + * @memberOf Query + * @param {Number} val + * @see mongodb http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7BbatchSize%28%29%7D%7D + * @api public + */ +/** + * Specifies the `comment` option. + * + * ####Example + * + * query.comment('login query') + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @method comment + * @memberOf Query + * @param {Number} val + * @see mongodb http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24comment + * @api public + */ + +/*! + * limit, skip, maxScan, batchSize, comment + * + * Sets these associated options. + * + * query.comment('feed query'); + */ + +;['limit', 'skip', 'maxScan', 'batchSize', 'comment'].forEach(function (method) { + Query.prototype[method] = function (v) { + this._validate(method); + this.options[method] = v; + return this; + }; +}) + +/** + * Specifies this query as a `snapshot` query. + * + * ####Example + * + * mquery().snapshot() // true + * mquery().snapshot(true) + * mquery().snapshot(false) + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @see mongodb http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bsnapshot%28%29%7D%7D + * @return {Query} this + * @api public + */ + +Query.prototype.snapshot = function () { + this._validate('snapshot'); + + this.options.snapshot = arguments.length + ? !! arguments[0] + : true + + return this; +} + +/** + * Sets query hints. + * + * ####Example + * + * query.hint({ indexA: 1, indexB: -1}) + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @param {Object} val a hint object + * @return {Query} this + * @see mongodb http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24hint + * @api public + */ + +Query.prototype.hint = function () { + if (0 === arguments.length) return this; + + this._validate('hint'); + + var arg = arguments[0]; + if (utils.isObject(arg)) { + var hint = this.options.hint || (this.options.hint = {}); + + // must keep object keys in order so don't use Object.keys() + for (var k in arg) { + hint[k] = arg[k]; + } + + return this; + } + + throw new TypeError('Invalid hint. ' + arg); +} + +/** + * Sets the slaveOk option. _Deprecated_ in MongoDB 2.2 in favor of read preferences. + * + * ####Example: + * + * query.slaveOk() // true + * query.slaveOk(true) + * query.slaveOk(false) + * + * @deprecated use read() preferences instead if on mongodb >= 2.2 + * @param {Boolean} v defaults to true + * @see mongodb http://docs.mongodb.org/manual/applications/replication/#read-preference + * @see read() + * @return {Query} this + * @api public + */ + +Query.prototype.slaveOk = function (v) { + this.options.slaveOk = arguments.length ? !!v : true; + return this; +} + +/** + * Sets the readPreference option for the query. + * + * ####Example: + * + * new Query().read('primary') + * new Query().read('p') // same as primary + * + * new Query().read('primaryPreferred') + * new Query().read('pp') // same as primaryPreferred + * + * new Query().read('secondary') + * new Query().read('s') // same as secondary + * + * new Query().read('secondaryPreferred') + * new Query().read('sp') // same as secondaryPreferred + * + * new Query().read('nearest') + * new Query().read('n') // same as nearest + * + * // with tags + * new Query().read('s', [{ dc:'sf', s: 1 },{ dc:'ma', s: 2 }]) + * + * ####Preferences: + * + * primary - (default) Read from primary only. Operations will produce an error if primary is unavailable. Cannot be combined with tags. + * secondary Read from secondary if available, otherwise error. + * primaryPreferred Read from primary if available, otherwise a secondary. + * secondaryPreferred Read from a secondary if available, otherwise read from the primary. + * nearest All operations read from among the nearest candidates, but unlike other modes, this option will include both the primary and all secondaries in the random selection. + * + * Aliases + * + * p primary + * pp primaryPreferred + * s secondary + * sp secondaryPreferred + * n nearest + * + * Read more about how to use read preferrences [here](http://docs.mongodb.org/manual/applications/replication/#read-preference) and [here](http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences). + * + * @param {String} pref one of the listed preference options or their aliases + * @param {Array} [tags] optional tags for this query + * @see mongodb http://docs.mongodb.org/manual/applications/replication/#read-preference + * @see driver http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences + * @return {Query} this + * @api public + */ + +Query.prototype.read = function (pref, tags) { + this.options.readPreference = utils.readPref(pref, tags); + return this; +} + +/** + * Sets tailable option. + * + * ####Example + * + * query.tailable() <== true + * query.tailable(true) + * query.tailable(false) + * + * ####Note + * + * Cannot be used with `distinct()` + * + * @param {Boolean} v defaults to true + * @see mongodb http://www.mongodb.org/display/DOCS/Tailable+Cursors + * @api public + */ + +Query.prototype.tailable = function () { + this._validate('tailable'); + + this.options.tailable = arguments.length + ? !! arguments[0] + : true; + + return this; +} + +/** + * Merges another Query or conditions object into this one. + * + * When a Query is passed, conditions, field selection and options are merged. + * + * @param {Query|Object} source + * @return {Query} this + */ + +Query.prototype.merge = function (source) { + if (!source) + return this; + + if (!Query.canMerge(source)) + throw new TypeError('Invalid argument. Expected instanceof mquery or plain object'); + + if (source instanceof Query) { + // if source has a feature, apply it to ourselves + + if (source._conditions) { + utils.merge(this._conditions, source._conditions); + } + + if (source._fields) { + this._fields || (this._fields = {}); + utils.merge(this._fields, source._fields); + } + + if (source.options) { + this.options || (this.options = {}); + utils.merge(this.options, source.options); + } + + if (source._update) { + this._update || (this._update = {}); + utils.mergeClone(this._update, source._update); + } + + if (source._distinct) { + this._distinct = source._distinct; + } + + return this; + } + + // plain object + utils.merge(this._conditions, source); + + return this; +} + +/** + * Finds documents. + * + * Passing a `callback` executes the query. + * + * ####Example + * + * query.find() + * query.find(callback) + * query.find({ name: 'Burning Lights' }, callback) + * + * @param {Object} [criteria] mongodb selector + * @param {Function} [callback] + * @return {Query} this + * @api public + */ + +Query.prototype.find = function (criteria, callback) { + this.op = 'find'; + + if ('function' === typeof criteria) { + callback = criteria; + criteria = undefined; + } else if (Query.canMerge(criteria)) { + this.merge(criteria); + } + + if (!callback) return this; + + var self = this + , conds = this._conditions + , options = this._optionsForExec() + + options.fields = this._fieldsForExec() + + debug('find', conds, options); + + this._collection.find(conds, options, utils.tick(callback)); + return this; +} + +/** + * Executes the query as a findOne() operation. + * + * Passing a `callback` executes the query. + * + * ####Example + * + * query.findOne().where('name', /^Burning/); + * + * query.findOne({ name: /^Burning/ }) + * + * query.findOne({ name: /^Burning/ }, callback); // executes + * + * query.findOne(function (err, doc) { + * if (err) return handleError(err); + * if (doc) { + * // doc may be null if no document matched + * + * } + * }); + * + * @param {Object|Query} [criteria] mongodb selector + * @param {Function} [callback] + * @return {Query} this + * @api public + */ + +Query.prototype.findOne = function (criteria, callback) { + this.op = 'findOne'; + + if ('function' === typeof criteria) { + callback = criteria; + criteria = undefined; + } else if (Query.canMerge(criteria)) { + this.merge(criteria); + } + + if (!callback) return this; + + var self = this + , conds = this._conditions + , options = this._optionsForExec() + + options.fields = this._fieldsForExec(); + + debug('findOne', conds, options); + this._collection.findOne(conds, options, utils.tick(callback)); + + return this; +} + +/** + * Exectues the query as a count() operation. + * + * Passing a `callback` executes the query. + * + * ####Example + * + * query.count().where('color', 'black').exec(callback); + * + * query.count({ color: 'black' }).count(callback) + * + * query.count({ color: 'black' }, callback) + * + * query.where('color', 'black').count(function (err, count) { + * if (err) return handleError(err); + * console.log('there are %d kittens', count); + * }) + * + * @param {Object} [criteria] mongodb selector + * @param {Function} [callback] + * @return {Query} this + * @see mongodb http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Count + * @api public + */ + +Query.prototype.count = function (criteria, callback) { + this.op = 'count'; + this._validate(); + + if ('function' === typeof criteria) { + callback = criteria; + criteria = undefined; + } else if (Query.canMerge(criteria)) { + this.merge(criteria); + } + + if (!callback) return this; + + var conds = this._conditions + , options = this._optionsForExec() + + debug('count', conds, options); + this._collection.count(conds, options, utils.tick(callback)); + return this; +} + +/** + * Declares or executes a distict() operation. + * + * Passing a `callback` executes the query. + * + * ####Example + * + * distinct(criteria, field, fn) + * distinct(criteria, field) + * distinct(field, fn) + * distinct(field) + * distinct(fn) + * distinct() + * + * @param {Object|Query} [criteria] + * @param {String} [field] + * @param {Function} [callback] + * @return {Query} this + * @see mongodb http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Distinct + * @api public + */ + +Query.prototype.distinct = function (criteria, field, callback) { + this.op = 'distinct'; + this._validate(); + + if (!callback) { + switch (typeof field) { + case 'function': + callback = field; + if ('string' == typeof criteria) { + field = criteria; + criteria = undefined; + } + break; + case 'undefined': + case 'string': + break; + default: + throw new TypeError('Invalid `field` argument. Must be string or function') + break; + } + + switch (typeof criteria) { + case 'function': + callback = criteria; + criteria = field = undefined; + break; + case 'string': + field = criteria; + criteria = undefined; + break; + } + } + + if ('string' == typeof field) { + this._distinct = field; + } + + if (Query.canMerge(criteria)) { + this.merge(criteria); + } + + if (!callback) { + return this; + } + + if (!this._distinct) { + throw new Error('No value for `distinct` has been declared'); + } + + var conds = this._conditions + , options = this._optionsForExec() + + debug('distinct', conds, options); + this._collection.distinct(this._distinct, conds, options, utils.tick(callback)); + + return this; +} + +/** + * Declare and/or execute this query as an update() operation. + * + * _All paths passed that are not $atomic operations will become $set ops._ + * + * ####Example + * + * mquery({ _id: id }).update({ title: 'words' }, ...) + * + * becomes + * + * collection.update({ _id: id }, { $set: { title: 'words' }}, ...) + * + * ####Note + * + * Passing an empty object `{}` as the doc will result in a no-op unless the `overwrite` option is passed. Without the `overwrite` option set, the update operation will be ignored and the callback executed without sending the command to MongoDB so as to prevent accidently overwritting documents in the collection. + * + * ####Note + * + * The operation is only executed when a callback is passed. To force execution without a callback (which would be an unsafe write), we must first call update() and then execute it by using the `exec()` method. + * + * var q = mquery(collection).where({ _id: id }); + * q.update({ $set: { name: 'bob' }}).update(); // not executed + * + * var q = mquery(collection).where({ _id: id }); + * q.update({ $set: { name: 'bob' }}).exec(); // executed as unsafe + * + * // keys that are not $atomic ops become $set. + * // this executes the same command as the previous example. + * q.update({ name: 'bob' }).where({ _id: id }).exec(); + * + * var q = mquery(collection).update(); // not executed + * + * // overwriting with empty docs + * var q.where({ _id: id }).setOptions({ overwrite: true }) + * q.update({ }, callback); // executes + * + * // multi update with overwrite to empty doc + * var q = mquery(collection).where({ _id: id }); + * q.setOptions({ multi: true, overwrite: true }) + * q.update({ }); + * q.update(callback); // executed + * + * // multi updates + * mquery() + * .collection(coll) + * .update({ name: /^match/ }, { $set: { arr: [] }}, { multi: true }, callback) + * // more multi updates + * mquery({ }) + * .collection(coll) + * .setOptions({ multi: true }) + * .update({ $set: { arr: [] }}, callback) + * + * // single update by default + * mquery({ email: 'address@example.com' }) + * .collection(coll) + * .update({ $inc: { counter: 1 }}, callback) + * + * // summary + * update(criteria, doc, opts, cb) // executes + * update(criteria, doc, opts) + * update(criteria, doc, cb) // executes + * update(criteria, doc) + * update(doc, cb) // executes + * update(doc) + * update(cb) // executes + * update(true) // executes (unsafe write) + * update() + * + * @param {Object} [criteria] + * @param {Object} [doc] the update command + * @param {Object} [options] + * @param {Function} [callback] + * @return {Query} this + * @api public + */ + +Query.prototype.update = function update (criteria, doc, options, callback) { + this.op = 'update'; + var force; + + switch (arguments.length) { + case 3: + if ('function' == typeof options) { + callback = options; + options = undefined; + } + break; + case 2: + if ('function' == typeof doc) { + callback = doc; + doc = criteria; + criteria = undefined; + } + break; + case 1: + switch (typeof criteria) { + case 'function': + callback = criteria; + criteria = options = doc = undefined; + break; + case 'boolean': + // execution with no callback (unsafe write) + force = criteria; + criteria = undefined; + break; + default: + doc = criteria; + criteria = options = undefined; + break; + } + } + + if (Query.canMerge(criteria)) { + this.merge(criteria); + } + + if (doc) { + this._mergeUpdate(doc); + } + + if (utils.isObject(options)) { + // { overwrite: true } + this.setOptions(options); + } + + // we are done if we don't have callback and they are + // not forcing an unsafe write. + if (!(force || callback)) + return this; + + if (!this._update || + !this.options.overwrite && 0 === utils.keys(this._update).length) { + callback && utils.soon(callback.bind(null, null, 0)); + return this; + } + + options = this._optionsForExec(); + if (!callback) options.safe = false; + + var criteria = this._conditions; + doc = this._updateForExec(); + + debug('update', criteria, doc, options); + this._collection.update(criteria, doc, options, utils.tick(callback)); + + return this; +} + +/** + * Declare and/or execute this query as a remove() operation. + * + * ####Example + * + * mquery(collection).remove({ artist: 'Anne Murray' }, callback) + * + * ####Note + * + * The operation is only executed when a callback is passed. To force execution without a callback (which would be an unsafe write), we must first call remove() and then execute it by using the `exec()` method. + * + * // not executed + * var query = mquery(collection).remove({ name: 'Anne Murray' }) + * + * // executed + * mquery(collection).remove({ name: 'Anne Murray' }, callback) + * mquery(collection).remove({ name: 'Anne Murray' }).remove(callback) + * + * // executed without a callback (unsafe write) + * query.exec() + * + * // summary + * query.remove(conds, fn); // executes + * query.remove(conds) + * query.remove(fn) // executes + * query.remove() + * + * @param {Object|Query} [criteria] mongodb selector + * @param {Function} [callback] + * @return {Query} this + * @api public + */ + +Query.prototype.remove = function (criteria, callback) { + this.op = 'remove'; + var force; + + if ('function' === typeof criteria) { + callback = criteria; + criteria = undefined; + } else if (Query.canMerge(criteria)) { + this.merge(criteria); + } else if (true === criteria) { + force = criteria; + criteria = undefined; + } + + if (!(force || callback)) + return this; + + var options = this._optionsForExec() + if (!callback) options.safe = false; + + var conds = this._conditions; + + debug('remove', conds, options); + this._collection.remove(conds, options, utils.tick(callback)); + + return this; +} + +/** + * Issues a mongodb [findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) update command. + * + * Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes immediately if `callback` is passed. + * + * ####Available options + * + * - `new`: bool - true to return the modified document rather than the original. defaults to true + * - `upsert`: bool - creates the object if it doesn't exist. defaults to false. + * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update + * + * ####Examples + * + * query.findOneAndUpdate(conditions, update, options, callback) // executes + * query.findOneAndUpdate(conditions, update, options) // returns Query + * query.findOneAndUpdate(conditions, update, callback) // executes + * query.findOneAndUpdate(conditions, update) // returns Query + * query.findOneAndUpdate(update, callback) // returns Query + * query.findOneAndUpdate(update) // returns Query + * query.findOneAndUpdate(callback) // executes + * query.findOneAndUpdate() // returns Query + * + * @param {Object|Query} [query] + * @param {Object} [doc] + * @param {Object} [options] + * @param {Function} [callback] + * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command + * @return {Query} this + * @api public + */ + +Query.prototype.findOneAndUpdate = function (criteria, doc, options, callback) { + this.op = 'findOneAndUpdate'; + this._validate(); + + switch (arguments.length) { + case 3: + if ('function' == typeof options) { + callback = options; + options = {}; + } + break; + case 2: + if ('function' == typeof doc) { + callback = doc; + doc = criteria; + criteria = undefined; + } + options = undefined; + break; + case 1: + if ('function' == typeof criteria) { + callback = criteria; + criteria = options = doc = undefined; + } else { + doc = criteria; + criteria = options = undefined; + } + } + + if (Query.canMerge(criteria)) { + this.merge(criteria); + } + + // apply doc + if (doc) { + this._mergeUpdate(doc); + } + + options && this.setOptions(options); + + if (!callback) return this; + return this._findAndModify('update', callback); +} + +/** + * Issues a mongodb [findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) remove command. + * + * Finds a matching document, removes it, passing the found document (if any) to the callback. Executes immediately if `callback` is passed. + * + * ####Available options + * + * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update + * + * ####Examples + * + * A.where().findOneAndRemove(conditions, options, callback) // executes + * A.where().findOneAndRemove(conditions, options) // return Query + * A.where().findOneAndRemove(conditions, callback) // executes + * A.where().findOneAndRemove(conditions) // returns Query + * A.where().findOneAndRemove(callback) // executes + * A.where().findOneAndRemove() // returns Query + * + * @param {Object} [conditions] + * @param {Object} [options] + * @param {Function} [callback] + * @return {Query} this + * @see mongodb http://www.mongodb.org/display/DOCS/findAndModify+Command + * @api public + */ + +Query.prototype.findOneAndRemove = function (conditions, options, callback) { + this.op = 'findOneAndRemove'; + this._validate(); + + if ('function' == typeof options) { + callback = options; + options = undefined; + } else if ('function' == typeof conditions) { + callback = conditions; + conditions = undefined; + } + + // apply conditions + if (Query.canMerge(conditions)) { + this.merge(conditions); + } + + // apply options + options && this.setOptions(options); + + if (!callback) return this; + + return this._findAndModify('remove', callback); +} + +/** + * _findAndModify + * + * @param {String} type - either "remove" or "update" + * @param {Function} callback + * @api private + */ + +Query.prototype._findAndModify = function (type, callback) { + assert.equal('function', typeof callback); + + var opts = this._optionsForExec() + , self = this + , fields + , sort + , doc + + if ('remove' == type) { + opts.remove = true; + } else { + if (!('new' in opts)) opts.new = true; + if (!('upsert' in opts)) opts.upsert = false; + + doc = this._updateForExec() + if (!doc) { + if (opts.upsert) { + // still need to do the upsert to empty doc + doc = { $set: {} }; + } else { + return this.findOne(callback); + } + } + } + + var fields = this._fieldsForExec(); + if (fields) { + opts.fields = fields; + } + + var conds = this._conditions; + + debug('findAndModify', conds, doc, opts); + + this._collection + .findAndModify(conds, doc, opts, utils.tick(callback)); + + return this; +} + +/** + * Executes the query + * + * ####Examples + * + * query.exec(); + * query.exec(callback); + * query.exec('update'); + * query.exec('find', callback); + * + * @param {String|Function} [operation] + * @param {Function} [callback] + * @return {Promise} + * @api public + */ + +Query.prototype.exec = function exec (op, callback) { + switch (typeof op) { + case 'function': + callback = op; + op = null; + break; + case 'string': + this.op = op; + break; + } + + assert.ok(this.op, "Missing query type: (find, update, etc)"); + + if ('update' == this.op || 'remove' == this.op) { + callback || (callback = true); + } + + this[this.op](callback); +} + +/** + * Merges `doc` with the current update object. + * + * @param {Object} doc + */ + +Query.prototype._mergeUpdate = function (doc) { + if (!this._update) this._update = {}; + if (doc instanceof Query) { + if (doc._update) { + utils.mergeClone(this._update, doc._update); + } + } else { + utils.mergeClone(this._update, doc); + } +} + +/** + * Returns default options. + * + * @return {Object} + * @api private + */ + +Query.prototype._optionsForExec = function () { + var options = utils.clone(this.options, { retainKeyOrder: true }); + return options; +} + +/** + * Returns fields selection for this query. + * + * @return {Object} + * @api private + */ + +Query.prototype._fieldsForExec = function () { + return utils.clone(this._fields); +} + +/** + * Return an update document with corrected $set operations. + * + * @api private + */ + +Query.prototype._updateForExec = function () { + var update = utils.clone(this._update, { retainKeyOrder: true }) + , ops = utils.keys(update) + , i = ops.length + , ret = {} + , hasKeys + , val + + while (i--) { + var op = ops[i]; + + if (this.options.overwrite) { + ret[op] = update[op]; + continue; + } + + if ('$' !== op[0]) { + // fix up $set sugar + if (!ret.$set) { + if (update.$set) { + ret.$set = update.$set; + } else { + ret.$set = {}; + } + } + ret.$set[op] = update[op]; + ops.splice(i, 1); + if (!~ops.indexOf('$set')) ops.push('$set'); + } else if ('$set' === op) { + if (!ret.$set) { + ret[op] = update[op]; + } + } else { + ret[op] = update[op]; + } + } + + return ret; +} + +/** + * Make sure _path is set. + * + * @parmam {String} method + */ + +Query.prototype._ensurePath = function (method) { + if (!this._path) { + var msg = method + '() must be used after where() ' + + 'when called with these arguments' + throw new Error(msg); + } +} + +/*! + * Permissions + */ + +Query.permissions = require('./permissions'); + +Query._isPermitted = function (a, b) { + var denied = Query.permissions[b]; + if (!denied) return true; + return true !== denied[a]; +} + +Query.prototype._validate = function (action) { + var fail; + var validator; + + if (undefined === action) { + + validator = Query.permissions[this.op]; + if ('function' != typeof validator) return true; + + fail = validator(this); + + } else if (!Query._isPermitted(action, this.op)) { + fail = action; + } + + if (fail) { + throw new Error(fail + ' cannot be used with ' + this.op); + } +} + +/** + * Determines if `conds` can be merged using `mquery().merge()` + * + * @param {Object} conds + * @return {Boolean} + */ + +Query.canMerge = function (conds) { + return conds instanceof Query || utils.isObject(conds); +} + +/*! + * Exports. + */ + +Query.utils = utils; +Query.env = require('./env') +Query.Collection = require('./collection'); +Query.BaseCollection = require('./collection/collection'); +module.exports = exports = Query; + +// TODO +// test utils diff --git a/node_modules/mongoose/node_modules/mquery/lib/permissions.js b/node_modules/mongoose/node_modules/mquery/lib/permissions.js new file mode 100644 index 0000000..07351d3 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/lib/permissions.js @@ -0,0 +1,91 @@ +'use strict'; + +var denied = exports; + +denied.distinct = function (self) { + if (self._fields && Object.keys(self._fields).length > 0) { + return 'field selection and slice' + } + + var keys = Object.keys(denied.distinct); + var err; + + keys.every(function (option) { + if (self.options[option]) { + err = option; + return false; + } + return true; + }); + + return err; +}; +denied.distinct.select = +denied.distinct.slice = +denied.distinct.sort = +denied.distinct.limit = +denied.distinct.skip = +denied.distinct.batchSize = +denied.distinct.comment = +denied.distinct.maxScan = +denied.distinct.snapshot = +denied.distinct.hint = +denied.distinct.tailable = true; + + +// aggregation integration + + +denied.findOneAndUpdate = +denied.findOneAndRemove = function (self) { + var keys = Object.keys(denied.findOneAndUpdate); + var err; + + keys.every(function (option) { + if (self.options[option]) { + err = option; + return false; + } + return true; + }); + + return err; +} +denied.findOneAndUpdate.limit = +denied.findOneAndUpdate.skip = +denied.findOneAndUpdate.batchSize = +denied.findOneAndUpdate.maxScan = +denied.findOneAndUpdate.snapshot = +denied.findOneAndUpdate.hint = +denied.findOneAndUpdate.tailable = +denied.findOneAndUpdate.comment = true; + + +denied.count = function (self) { + if (self._fields && Object.keys(self._fields).length > 0) { + return 'field selection and slice' + } + + var keys = Object.keys(denied.count); + var err; + + keys.every(function (option) { + if (self.options[option]) { + err = option; + return false; + } + return true; + }); + + return err; +} + +denied.count.select = +denied.count.slice = +denied.count.sort = +denied.count.batchSize = +denied.count.comment = +denied.count.maxScan = +denied.count.snapshot = +denied.count.hint = +denied.count.tailable = true; diff --git a/node_modules/mongoose/node_modules/mquery/lib/utils.js b/node_modules/mongoose/node_modules/mquery/lib/utils.js new file mode 100644 index 0000000..fe0e162 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/lib/utils.js @@ -0,0 +1,319 @@ +'use strict'; + +/*! + * Module dependencies. + */ + +var mongodb = require('mongodb') + , ReadPref = mongodb.ReadPreference + , ObjectId = mongodb.ObjectID + , RegExpClone = require('regexp-clone') + +/** + * Object clone with Mongoose natives support. + * + * Creates a minimal data Object. + * It does not clone empty Arrays, empty Objects, and undefined values. + * This makes the data payload sent to MongoDB as minimal as possible. + * + * @param {Object} obj the object to clone + * @param {Object} options + * @return {Object} the cloned object + * @api private + */ + +exports.clone = function clone (obj, options) { + if (obj === undefined || obj === null) + return obj; + + if (Array.isArray(obj)) + return exports.cloneArray(obj, options); + + if ('Object' === obj.constructor.name) + return exports.cloneObject(obj, options); + + if ('Date' === obj.constructor.name || 'Function' === obj.constructor.name) + return new obj.constructor(+obj); + + if ('RegExp' === obj.constructor.name) { + return RegExpClone(obj); + } + + if (obj instanceof ObjectId) + return new ObjectId(obj.id); + + if (obj.valueOf) + return obj.valueOf(); +}; +var clone = exports.clone; + +/*! + * ignore + */ + +var cloneObject = exports.cloneObject = function cloneObject (obj, options) { + var retainKeyOrder = options && options.retainKeyOrder + , minimize = options && options.minimize + , ret = {} + , hasKeys + , keys + , val + , k + , i + + if (retainKeyOrder) { + for (k in obj) { + val = clone(obj[k], options); + + if (!minimize || ('undefined' !== typeof val)) { + hasKeys || (hasKeys = true); + ret[k] = val; + } + } + } else { + // faster + + keys = Object.keys(obj); + i = keys.length; + + while (i--) { + k = keys[i]; + val = clone(obj[k], options); + + if (!minimize || ('undefined' !== typeof val)) { + if (!hasKeys) hasKeys = true; + ret[k] = val; + } + } + } + + return minimize + ? hasKeys && ret + : ret; +}; + +var cloneArray = exports.cloneArray = function cloneArray (arr, options) { + var ret = []; + for (var i = 0, l = arr.length; i < l; i++) + ret.push(clone(arr[i], options)); + return ret; +}; + +/** + * process.nextTick helper. + * + * Wraps the given `callback` in a try/catch. If an error is + * caught it will be thrown on nextTick. + * + * node-mongodb-native had a habit of state corruption when + * an error was immediately thrown from within a collection + * method (find, update, etc) callback. + * + * @param {Function} [callback] + * @api private + */ + +var tick = exports.tick = function tick (callback) { + if ('function' !== typeof callback) return; + return function () { + // callbacks should always be fired on the next + // turn of the event loop. A side benefit is + // errors thrown from executing the callback + // will not cause drivers state to be corrupted + // which has historically been a problem. + var args = arguments; + soon(function(){ + callback.apply(this, args); + }); + } +} + +/** + * Merges `from` into `to` without overwriting existing properties. + * + * @param {Object} to + * @param {Object} from + * @api private + */ + +var merge = exports.merge = function merge (to, from) { + var keys = Object.keys(from) + , i = keys.length + , key + + while (i--) { + key = keys[i]; + if ('undefined' === typeof to[key]) { + to[key] = from[key]; + } else { + if (exports.isObject(from[key])) { + merge(to[key], from[key]); + } else { + to[key] = from[key]; + } + } + } +} + +/** + * Same as merge but clones the assigned values. + * + * @param {Object} to + * @param {Object} from + * @api private + */ + +var mergeClone = exports.mergeClone = function mergeClone (to, from) { + var keys = Object.keys(from) + , i = keys.length + , key + + while (i--) { + key = keys[i]; + if ('undefined' === typeof to[key]) { + // make sure to retain key order here because of a bug handling the $each + // operator in mongodb 2.4.4 + to[key] = clone(from[key], { retainKeyOrder : 1}); + } else { + if (exports.isObject(from[key])) { + mergeClone(to[key], from[key]); + } else { + // make sure to retain key order here because of a bug handling the + // $each operator in mongodb 2.4.4 + to[key] = clone(from[key], { retainKeyOrder : 1}); + } + } + } +} + +/** + * Read pref helper (mongo 2.2 drivers support this) + * + * Allows using aliases instead of full preference names: + * + * p primary + * pp primaryPreferred + * s secondary + * sp secondaryPreferred + * n nearest + * + * @param {String|Array} pref + * @param {Array} [tags] + */ + +exports.readPref = function readPref (pref, tags) { + if (Array.isArray(pref)) { + tags = pref[1]; + pref = pref[0]; + } + + switch (pref) { + case 'p': + pref = 'primary'; + break; + case 'pp': + pref = 'primaryPreferred'; + break; + case 's': + pref = 'secondary'; + break; + case 'sp': + pref = 'secondaryPreferred'; + break; + case 'n': + pref = 'nearest'; + break; + } + + return new ReadPref(pref, tags); +} + +/** + * Object.prototype.toString.call helper + */ + +var toString = Object.prototype.toString; +exports.toString = function (arg) { + return toString.call(arg); +} + +/** + * Determines if `arg` is an object. + * + * @param {Object|Array|String|Function|RegExp|any} arg + * @return {Boolean} + */ + +exports.isObject = function (arg) { + return '[object Object]' == exports.toString(arg); +} + +/** + * Determines if `arg` is an array. + * + * @param {Object} + * @return {Boolean} + * @see nodejs utils + */ + +exports.isArray = function (arg) { + return Array.isArray(arg) || + 'object' == typeof arg && '[object Array]' == exports.toString(arg); +} + +/** + * Object.keys helper + */ + +exports.keys = Object.keys || function (obj) { + var keys = []; + for (var k in obj) if (obj.hasOwnProperty(k)) { + keys.push(k); + } + return keys; +} + +/** + * Basic Object.create polyfill. + * Only one argument is supported. + * + * Based on https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create + */ + +exports.create = 'function' == typeof Object.create + ? Object.create + : create; + +function create (proto) { + if (arguments.length > 1) { + throw new Error("Adding properties is not supported") + } + + function F () {} + F.prototype = proto; + return new F; +} + +/** + * inheritance + */ + +exports.inherits = function (ctor, superCtor) { + ctor.prototype = exports.create(superCtor.prototype); + ctor.prototype.constructor = ctor; +} + +/** + * nextTick helper + * compat with node 0.10 which behaves differently than previous versions + */ + +var soon = exports.soon = 'function' == typeof setImmediate + ? setImmediate + : process.nextTick; + +/** + * need to export this for checking issues + */ + +exports.mongo = mongodb; diff --git a/node_modules/mongoose/node_modules/mquery/node_modules/debug/.npmignore b/node_modules/mongoose/node_modules/mquery/node_modules/debug/.npmignore new file mode 100644 index 0000000..f1250e5 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/node_modules/debug/.npmignore @@ -0,0 +1,4 @@ +support +test +examples +*.sock diff --git a/node_modules/mongoose/node_modules/mquery/node_modules/debug/History.md b/node_modules/mongoose/node_modules/mquery/node_modules/debug/History.md new file mode 100644 index 0000000..2220632 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/node_modules/debug/History.md @@ -0,0 +1,47 @@ + +0.7.0 / 2012-05-04 +================== + + * Added .component to package.json + * Added debug.component.js build + +0.6.0 / 2012-03-16 +================== + + * Added support for "-" prefix in DEBUG [Vinay Pulim] + * Added `.enabled` flag to the node version [TooTallNate] + +0.5.0 / 2012-02-02 +================== + + * Added: humanize diffs. Closes #8 + * Added `debug.disable()` to the CS variant + * Removed padding. Closes #10 + * Fixed: persist client-side variant again. Closes #9 + +0.4.0 / 2012-02-01 +================== + + * Added browser variant support for older browsers [TooTallNate] + * Added `debug.enable('project:*')` to browser variant [TooTallNate] + * Added padding to diff (moved it to the right) + +0.3.0 / 2012-01-26 +================== + + * Added millisecond diff when isatty, otherwise UTC string + +0.2.0 / 2012-01-22 +================== + + * Added wildcard support + +0.1.0 / 2011-12-02 +================== + + * Added: remove colors unless stderr isatty [TooTallNate] + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/node_modules/mongoose/node_modules/mquery/node_modules/debug/Makefile b/node_modules/mongoose/node_modules/mquery/node_modules/debug/Makefile new file mode 100644 index 0000000..692f2c1 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/node_modules/debug/Makefile @@ -0,0 +1,4 @@ + +debug.component.js: head.js debug.js tail.js + cat $^ > $@ + diff --git a/node_modules/mongoose/node_modules/mquery/node_modules/debug/Readme.md b/node_modules/mongoose/node_modules/mquery/node_modules/debug/Readme.md new file mode 100644 index 0000000..419fcdf --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/node_modules/debug/Readme.md @@ -0,0 +1,130 @@ + +# debug + + tiny node.js debugging utility. + +## Installation + +``` +$ npm install debug +``` + +## Example + + This module is modelled after node core's debugging technique, allowing you to enable one or more topic-specific debugging functions, for example core does the following within many modules: + +```js +var debug; +if (process.env.NODE_DEBUG && /cluster/.test(process.env.NODE_DEBUG)) { + debug = function(x) { + var prefix = process.pid + ',' + + (process.env.NODE_WORKER_ID ? 'Worker' : 'Master'); + console.error(prefix, x); + }; +} else { + debug = function() { }; +} +``` + + This concept is extremely simple but it works well. With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility. + +Example _app.js_: + +```js +var debug = require('debug')('http') + , http = require('http') + , name = 'My App'; + +// fake app + +debug('booting %s', name); + +http.createServer(function(req, res){ + debug(req.method + ' ' + req.url); + res.end('hello\n'); +}).listen(3000, function(){ + debug('listening'); +}); + +// fake worker of some kind + +require('./worker'); +``` + +Example _worker.js_: + +```js +var debug = require('debug')('worker'); + +setInterval(function(){ + debug('doing some work'); +}, 1000); +``` + + The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples: + + ![debug http and worker](http://f.cl.ly/items/18471z1H402O24072r1J/Screenshot.png) + + ![debug worker](http://f.cl.ly/items/1X413v1a3M0d3C2c1E0i/Screenshot.png) + +## Millisecond diff + + When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls. + + ![](http://f.cl.ly/items/2i3h1d3t121M2Z1A3Q0N/Screenshot.png) + + When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below: + + ![](http://f.cl.ly/items/112H3i0e0o0P0a2Q2r11/Screenshot.png) + +## Conventions + + If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser". + +## Wildcards + + The "*" character may be used as a wildcard. Suppose for example your library has debuggers named "connect:bodyParser", "connect:compress", "connect:session", instead of listing all three with `DEBUG=connect:bodyParser,connect.compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`. + + You can also exclude specific debuggers by prefixing them with a "-" character. For example, `DEBUG=* -connect:*` would include all debuggers except those starting with "connect:". + +## Browser support + + Debug works in the browser as well, currently persisted by `localStorage`. For example if you have `worker:a` and `worker:b` as shown below, and wish to debug both type `debug.enable('worker:*')` in the console and refresh the page, this will remain until you disable with `debug.disable()`. + +```js +a = debug('worker:a'); +b = debug('worker:b'); + +setInterval(function(){ + a('doing some work'); +}, 1000); + +setInterval(function(){ + a('doing some work'); +}, 1200); +``` + +## License + +(The MIT License) + +Copyright (c) 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. \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mquery/node_modules/debug/debug.component.js b/node_modules/mongoose/node_modules/mquery/node_modules/debug/debug.component.js new file mode 100644 index 0000000..e6e9dbf --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/node_modules/debug/debug.component.js @@ -0,0 +1,120 @@ +;(function(){ + +/** + * Create a debugger with the given `name`. + * + * @param {String} name + * @return {Type} + * @api public + */ + +function debug(name) { + if (!debug.enabled(name)) return function(){}; + + return function(fmt){ + var curr = new Date; + var ms = curr - (debug[name] || curr); + debug[name] = curr; + + fmt = name + + ' ' + + fmt + + ' +' + debug.humanize(ms); + + // This hackery is required for IE8 + // where `console.log` doesn't have 'apply' + window.console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); + } +} + +/** + * The currently active debug mode names. + */ + +debug.names = []; +debug.skips = []; + +/** + * Enables a debug mode by name. This can include modes + * separated by a colon and wildcards. + * + * @param {String} name + * @api public + */ + +debug.enable = function(name) { + localStorage.debug = name; + + var split = (name || '').split(/[\s,]+/) + , len = split.length; + + for (var i = 0; i < len; i++) { + name = split[i].replace('*', '.*?'); + if (name[0] === '-') { + debug.skips.push(new RegExp('^' + name.substr(1) + '$')); + } + else { + debug.names.push(new RegExp('^' + name + '$')); + } + } +}; + +/** + * Disable debug output. + * + * @api public + */ + +debug.disable = function(){ + debug.enable(''); +}; + +/** + * Humanize the given `ms`. + * + * @param {Number} m + * @return {String} + * @api private + */ + +debug.humanize = function(ms) { + var sec = 1000 + , min = 60 * 1000 + , hour = 60 * min; + + if (ms >= hour) return (ms / hour).toFixed(1) + 'h'; + if (ms >= min) return (ms / min).toFixed(1) + 'm'; + if (ms >= sec) return (ms / sec | 0) + 's'; + return ms + 'ms'; +}; + +/** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ + +debug.enabled = function(name) { + for (var i = 0, len = debug.skips.length; i < len; i++) { + if (debug.skips[i].test(name)) { + return false; + } + } + for (var i = 0, len = debug.names.length; i < len; i++) { + if (debug.names[i].test(name)) { + return true; + } + } + return false; +}; + +// persist + +if (window.localStorage) debug.enable(localStorage.debug); + module.exports = debug; + +})(); \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mquery/node_modules/debug/debug.js b/node_modules/mongoose/node_modules/mquery/node_modules/debug/debug.js new file mode 100644 index 0000000..905fbd4 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/node_modules/debug/debug.js @@ -0,0 +1,116 @@ + +/** + * Create a debugger with the given `name`. + * + * @param {String} name + * @return {Type} + * @api public + */ + +function debug(name) { + if (!debug.enabled(name)) return function(){}; + + return function(fmt){ + var curr = new Date; + var ms = curr - (debug[name] || curr); + debug[name] = curr; + + fmt = name + + ' ' + + fmt + + ' +' + debug.humanize(ms); + + // This hackery is required for IE8 + // where `console.log` doesn't have 'apply' + window.console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); + } +} + +/** + * The currently active debug mode names. + */ + +debug.names = []; +debug.skips = []; + +/** + * Enables a debug mode by name. This can include modes + * separated by a colon and wildcards. + * + * @param {String} name + * @api public + */ + +debug.enable = function(name) { + localStorage.debug = name; + + var split = (name || '').split(/[\s,]+/) + , len = split.length; + + for (var i = 0; i < len; i++) { + name = split[i].replace('*', '.*?'); + if (name[0] === '-') { + debug.skips.push(new RegExp('^' + name.substr(1) + '$')); + } + else { + debug.names.push(new RegExp('^' + name + '$')); + } + } +}; + +/** + * Disable debug output. + * + * @api public + */ + +debug.disable = function(){ + debug.enable(''); +}; + +/** + * Humanize the given `ms`. + * + * @param {Number} m + * @return {String} + * @api private + */ + +debug.humanize = function(ms) { + var sec = 1000 + , min = 60 * 1000 + , hour = 60 * min; + + if (ms >= hour) return (ms / hour).toFixed(1) + 'h'; + if (ms >= min) return (ms / min).toFixed(1) + 'm'; + if (ms >= sec) return (ms / sec | 0) + 's'; + return ms + 'ms'; +}; + +/** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ + +debug.enabled = function(name) { + for (var i = 0, len = debug.skips.length; i < len; i++) { + if (debug.skips[i].test(name)) { + return false; + } + } + for (var i = 0, len = debug.names.length; i < len; i++) { + if (debug.names[i].test(name)) { + return true; + } + } + return false; +}; + +// persist + +if (window.localStorage) debug.enable(localStorage.debug); \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mquery/node_modules/debug/example/app.js b/node_modules/mongoose/node_modules/mquery/node_modules/debug/example/app.js new file mode 100644 index 0000000..05374d9 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/node_modules/debug/example/app.js @@ -0,0 +1,19 @@ + +var debug = require('../')('http') + , http = require('http') + , name = 'My App'; + +// fake app + +debug('booting %s', name); + +http.createServer(function(req, res){ + debug(req.method + ' ' + req.url); + res.end('hello\n'); +}).listen(3000, function(){ + debug('listening'); +}); + +// fake worker of some kind + +require('./worker'); \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mquery/node_modules/debug/example/browser.html b/node_modules/mongoose/node_modules/mquery/node_modules/debug/example/browser.html new file mode 100644 index 0000000..7510eee --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/node_modules/debug/example/browser.html @@ -0,0 +1,24 @@ + + + debug() + + + + + + + diff --git a/node_modules/mongoose/node_modules/mquery/node_modules/debug/example/wildcards.js b/node_modules/mongoose/node_modules/mquery/node_modules/debug/example/wildcards.js new file mode 100644 index 0000000..1fdac20 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/node_modules/debug/example/wildcards.js @@ -0,0 +1,10 @@ + +var debug = { + foo: require('../')('test:foo'), + bar: require('../')('test:bar'), + baz: require('../')('test:baz') +}; + +debug.foo('foo') +debug.bar('bar') +debug.baz('baz') \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mquery/node_modules/debug/example/worker.js b/node_modules/mongoose/node_modules/mquery/node_modules/debug/example/worker.js new file mode 100644 index 0000000..7f6d288 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/node_modules/debug/example/worker.js @@ -0,0 +1,22 @@ + +// DEBUG=* node example/worker +// DEBUG=worker:* node example/worker +// DEBUG=worker:a node example/worker +// DEBUG=worker:b node example/worker + +var a = require('../')('worker:a') + , b = require('../')('worker:b'); + +function work() { + a('doing lots of uninteresting work'); + setTimeout(work, Math.random() * 1000); +} + +work(); + +function workb() { + b('doing some work'); + setTimeout(workb, Math.random() * 2000); +} + +workb(); \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mquery/node_modules/debug/head.js b/node_modules/mongoose/node_modules/mquery/node_modules/debug/head.js new file mode 100644 index 0000000..55d3817 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/node_modules/debug/head.js @@ -0,0 +1 @@ +;(function(){ diff --git a/node_modules/mongoose/node_modules/mquery/node_modules/debug/index.js b/node_modules/mongoose/node_modules/mquery/node_modules/debug/index.js new file mode 100644 index 0000000..ee54454 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/node_modules/debug/index.js @@ -0,0 +1,2 @@ + +module.exports = require('./lib/debug'); \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mquery/node_modules/debug/lib/debug.js b/node_modules/mongoose/node_modules/mquery/node_modules/debug/lib/debug.js new file mode 100644 index 0000000..969d122 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/node_modules/debug/lib/debug.js @@ -0,0 +1,135 @@ + +/** + * Module dependencies. + */ + +var tty = require('tty'); + +/** + * Expose `debug()` as the module. + */ + +module.exports = debug; + +/** + * Enabled debuggers. + */ + +var names = [] + , skips = []; + +(process.env.DEBUG || '') + .split(/[\s,]+/) + .forEach(function(name){ + name = name.replace('*', '.*?'); + if (name[0] === '-') { + skips.push(new RegExp('^' + name.substr(1) + '$')); + } else { + names.push(new RegExp('^' + name + '$')); + } + }); + +/** + * Colors. + */ + +var colors = [6, 2, 3, 4, 5, 1]; + +/** + * Previous debug() call. + */ + +var prev = {}; + +/** + * Previously assigned color. + */ + +var prevColor = 0; + +/** + * Is stdout a TTY? Colored output is disabled when `true`. + */ + +var isatty = tty.isatty(2); + +/** + * Select a color. + * + * @return {Number} + * @api private + */ + +function color() { + return colors[prevColor++ % colors.length]; +} + +/** + * Humanize the given `ms`. + * + * @param {Number} m + * @return {String} + * @api private + */ + +function humanize(ms) { + var sec = 1000 + , min = 60 * 1000 + , hour = 60 * min; + + if (ms >= hour) return (ms / hour).toFixed(1) + 'h'; + if (ms >= min) return (ms / min).toFixed(1) + 'm'; + if (ms >= sec) return (ms / sec | 0) + 's'; + return ms + 'ms'; +} + +/** + * Create a debugger with the given `name`. + * + * @param {String} name + * @return {Type} + * @api public + */ + +function debug(name) { + function disabled(){} + disabled.enabled = false; + + var match = skips.some(function(re){ + return re.test(name); + }); + + if (match) return disabled; + + match = names.some(function(re){ + return re.test(name); + }); + + if (!match) return disabled; + var c = color(); + + function colored(fmt) { + var curr = new Date; + var ms = curr - (prev[name] || curr); + prev[name] = curr; + + fmt = ' \033[9' + c + 'm' + name + ' ' + + '\033[3' + c + 'm\033[90m' + + fmt + '\033[3' + c + 'm' + + ' +' + humanize(ms) + '\033[0m'; + + console.error.apply(this, arguments); + } + + function plain(fmt) { + fmt = new Date().toUTCString() + + ' ' + name + ' ' + fmt; + console.error.apply(this, arguments); + } + + colored.enabled = plain.enabled = true; + + return isatty + ? colored + : plain; +} diff --git a/node_modules/mongoose/node_modules/mquery/node_modules/debug/package.json b/node_modules/mongoose/node_modules/mquery/node_modules/debug/package.json new file mode 100644 index 0000000..a2b3c07 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/node_modules/debug/package.json @@ -0,0 +1,36 @@ +{ + "name": "debug", + "version": "0.7.0", + "description": "small debugging utility", + "keywords": [ + "debug", + "log", + "debugger" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "*" + }, + "main": "index", + "browserify": "debug.component.js", + "engines": { + "node": "*" + }, + "component": { + "scripts": { + "debug": "debug.component.js" + } + }, + "readme": "\n# debug\n\n tiny node.js debugging utility.\n\n## Installation\n\n```\n$ npm install debug\n```\n\n## Example\n\n This module is modelled after node core's debugging technique, allowing you to enable one or more topic-specific debugging functions, for example core does the following within many modules:\n\n```js\nvar debug;\nif (process.env.NODE_DEBUG && /cluster/.test(process.env.NODE_DEBUG)) {\n debug = function(x) {\n var prefix = process.pid + ',' +\n (process.env.NODE_WORKER_ID ? 'Worker' : 'Master');\n console.error(prefix, x);\n };\n} else {\n debug = function() { };\n}\n```\n\n This concept is extremely simple but it works well. With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility.\n \nExample _app.js_:\n\n```js\nvar debug = require('debug')('http')\n , http = require('http')\n , name = 'My App';\n\n// fake app\n\ndebug('booting %s', name);\n\nhttp.createServer(function(req, res){\n debug(req.method + ' ' + req.url);\n res.end('hello\\n');\n}).listen(3000, function(){\n debug('listening');\n});\n\n// fake worker of some kind\n\nrequire('./worker');\n```\n\nExample _worker.js_:\n\n```js\nvar debug = require('debug')('worker');\n\nsetInterval(function(){\n debug('doing some work');\n}, 1000);\n```\n\n The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples:\n\n ![debug http and worker](http://f.cl.ly/items/18471z1H402O24072r1J/Screenshot.png)\n\n ![debug worker](http://f.cl.ly/items/1X413v1a3M0d3C2c1E0i/Screenshot.png)\n\n## Millisecond diff\n\n When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the \"+NNNms\" will show you how much time was spent between calls.\n\n ![](http://f.cl.ly/items/2i3h1d3t121M2Z1A3Q0N/Screenshot.png)\n\n When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below:\n \n ![](http://f.cl.ly/items/112H3i0e0o0P0a2Q2r11/Screenshot.png)\n\n## Conventions\n\n If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use \":\" to separate features. For example \"bodyParser\" from Connect would then be \"connect:bodyParser\". \n\n## Wildcards\n\n The \"*\" character may be used as a wildcard. Suppose for example your library has debuggers named \"connect:bodyParser\", \"connect:compress\", \"connect:session\", instead of listing all three with `DEBUG=connect:bodyParser,connect.compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.\n\n You can also exclude specific debuggers by prefixing them with a \"-\" character. For example, `DEBUG=* -connect:*` would include all debuggers except those starting with \"connect:\".\n\n## Browser support\n\n Debug works in the browser as well, currently persisted by `localStorage`. For example if you have `worker:a` and `worker:b` as shown below, and wish to debug both type `debug.enable('worker:*')` in the console and refresh the page, this will remain until you disable with `debug.disable()`. \n\n```js\na = debug('worker:a');\nb = debug('worker:b');\n\nsetInterval(function(){\n a('doing some work');\n}, 1000);\n\nsetInterval(function(){\n a('doing some work');\n}, 1200);\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", + "readmeFilename": "Readme.md", + "_id": "debug@0.7.0", + "dist": { + "shasum": "0f4ebcd3f73504e06739c26435611ad0a45afd9c" + }, + "_from": "debug@0.7.0", + "_resolved": "https://registry.npmjs.org/debug/-/debug-0.7.0.tgz" +} diff --git a/node_modules/mongoose/node_modules/mquery/node_modules/debug/tail.js b/node_modules/mongoose/node_modules/mquery/node_modules/debug/tail.js new file mode 100644 index 0000000..5bf3fd3 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/node_modules/debug/tail.js @@ -0,0 +1,4 @@ + + module.exports = debug; + +})(); \ No newline at end of file diff --git a/node_modules/mongoose/node_modules/mquery/package.json b/node_modules/mongoose/node_modules/mquery/package.json new file mode 100644 index 0000000..324f8ec --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/package.json @@ -0,0 +1,44 @@ +{ + "name": "mquery", + "version": "0.3.2", + "description": "Expressive query building for MongoDB", + "main": "index.js", + "scripts": { + "test": "make test" + }, + "repository": { + "type": "git", + "url": "git://github.com/aheckmann/mquery.git" + }, + "keywords": [ + "mongodb", + "query", + "builder" + ], + "dependencies": { + "sliced": "0.0.5", + "debug": "0.7.0", + "regexp-clone": "0.0.1" + }, + "devDependencies": { + "mocha": "1.9.x", + "mongodb": "1.3.x" + }, + "bugs": { + "url": "https://github.com/aheckmann/mquery/issues/new" + }, + "author": { + "name": "Aaron Heckmann", + "email": "aaron.heckmann+github@gmail.com" + }, + "license": "MIT", + "homepage": "https://github.com/aheckmann/mquery/", + "readme": "#mquery\n===========\n\n`mquery` is a fluent mongodb query builder designed to run in multiple environments. As of v0.1, `mquery` runs on `Node.js` only with support for the MongoDB shell and browser environments planned for upcoming releases.\n\n##Features\n\n - fluent query builder api\n - custom base query support\n - MongoDB 2.4 geoJSON support\n - method + option combinations validation\n - node.js driver compatibility\n - environment detection\n - [debug](https://github.com/visionmedia/debug) support\n - separated collection implementations for maximum flexibility\n\n[![Build Status](https://travis-ci.org/aheckmann/mquery.png)](https://travis-ci.org/aheckmann/mquery)\n\n##Use\n\n```js\nrequire('mongodb').connect(uri, function (err, db) {\n if (err) return handleError(err);\n\n // get a collection\n var collection = db.collection('artists');\n\n // pass it to the constructor\n mquery(collection).find({..}, callback);\n\n // or pass it to the collection method\n mquery().find({..}).collection(collection).exec(callback)\n\n // or better yet, create a custom query constructor that has it always set\n var Artist = mquery(collection).toConstructor();\n Artist().find(..).where(..).exec(callback)\n})\n```\n\n`mquery` requires a collection object to work with. In the example above we just pass the collection object created using the official [MongoDB driver](https://github.com/mongodb/node-mongodb-native).\n\n\n##Fluent API\n\n###find()\n\nDeclares this query a _find_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.\n\n```js\nmquery().find()\nmquery().find(match)\nmquery().find(callback)\nmquery().find(match, function (err, docs) {\n assert(Array.isArray(docs));\n})\n```\n\n###findOne()\n\nDeclares this query a _findOne_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.\n\n```js\nmquery().findOne()\nmquery().findOne(match)\nmquery().findOne(callback)\nmquery().findOne(match, function (err, doc) {\n if (doc) {\n // the document may not be found\n console.log(doc);\n }\n})\n```\n\n###count()\n\nDeclares this query a _count_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.\n\n```js\nmquery().count()\nmquery().count(match)\nmquery().count(callback)\nmquery().count(match, function (err, number){\n console.log('we found %d matching documents', number);\n})\n```\n\n###remove()\n\nDeclares this query a _remove_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.\n\n```js\nmquery().remove()\nmquery().remove(match)\nmquery().remove(callback)\nmquery().remove(match, function (err){})\n```\n\n###update()\n\nDeclares this query an _update_ query. Optionally pass an update document, match clause, options or callback. If a callback is passed, the query is executed. To force execution without passing a callback, run `update(true)`.\n\n```js\nmquery().update()\nmquery().update(match, updateDocument)\nmquery().update(match, updateDocument, options)\n\n// the following all execute the command\nmquery().update(callback)\nmquery().update({$set: updateDocument, callback)\nmquery().update(match, updateDocument, callback)\nmquery().update(match, updateDocument, options, function (err, result){})\nmquery().update(true) // executes (unsafe write)\n```\n\n#####the update document\n\nAll paths passed that are not `$atomic` operations will become `$set` ops. For example:\n\n```js\nmquery(collection).where({ _id: id }).update({ title: 'words' }, callback)\n```\n\nbecomes\n\n```js\ncollection.update({ _id: id }, { $set: { title: 'words' }}, callback)\n```\n\nThis behavior can be overridden using the `overwrite` option (see below).\n\n#####options\n\nOptions are passed to the `setOptions()` method.\n\n- overwrite\n\nPassing an empty object `{ }` as the update document will result in a no-op unless the `overwrite` option is passed. Without the `overwrite` option, the update operation will be ignored and the callback executed without sending the command to MongoDB to prevent accidently overwritting documents in the collection.\n\n```js\nvar q = mquery(collection).where({ _id: id }).setOptions({ overwrite: true });\nq.update({ }, callback); // overwrite with an empty doc\n```\n\nThe `overwrite` option isn't just for empty objects, it also provides a means to override the default `$set` conversion and send the update document as is.\n\n```js\n// create a base query\nvar base = mquery({ _id: 108 }).collection(collection).toConstructor();\n\nbase().findOne(function (err, doc) {\n console.log(doc); // { _id: 108, name: 'cajon' })\n\n base().setOptions({ overwrite: true }).update({ changed: true }, function (err) {\n base.findOne(function (err, doc) {\n console.log(doc); // { _id: 108, changed: true }) - the doc was overwritten\n });\n });\n})\n```\n\n- multi\n\nUpdates only modify a single document by default. To update multiple documents, set the `multi` option to `true`.\n\n```js\nmquery()\n .collection(coll)\n .update({ name: /^match/ }, { $addToSet: { arr: 4 }}, { multi: true }, callback)\n\n// another way of doing it\nmquery({ name: /^match/ })\n .collection(coll)\n .setOptions({ multi: true })\n .update({ $addToSet: { arr: 4 }}, callback)\n\n// update multiple documents with an empty doc\nvar q = mquery(collection).where({ name: /^match/ });\nq.setOptions({ multi: true, overwrite: true })\nq.update({ });\nq.update(function (err, result) {\n console.log(arguments);\n});\n```\n\n###findOneAndUpdate()\n\nDeclares this query a _findAndModify_ with update query. Optionally pass a match clause, update document, options, or callback. If a callback is passed, the query is executed.\n\nWhen executed, the first matching document (if found) is modified according to the update document and passed back to the callback.\n\n#####options\n\nOptions are passed to the `setOptions()` method.\n\n- `new`: boolean - true to return the modified document rather than the original. defaults to true\n- `upsert`: boolean - creates the object if it doesn't exist. defaults to false\n- `sort`: if multiple docs are found by the match condition, sets the sort order to choose which doc to update\n\n```js\nquery.findOneAndUpdate()\nquery.findOneAndUpdate(updateDocument)\nquery.findOneAndUpdate(match, updateDocument)\nquery.findOneAndUpdate(match, updateDocument, options)\n\n// the following all execute the command\nquery.findOneAndUpdate(callback)\nquery.findOneAndUpdate(updateDocument, callback)\nquery.findOneAndUpdate(match, updateDocument, callback)\nquery.findOneAndUpdate(match, updateDocument, options, function (err, doc) {\n if (doc) {\n // the document may not be found\n console.log(doc);\n }\n})\n ```\n\n###findOneAndRemove()\n\nDeclares this query a _findAndModify_ with remove query. Optionally pass a match clause, options, or callback. If a callback is passed, the query is executed.\n\nWhen executed, the first matching document (if found) is modified according to the update document, removed from the collection and passed to the callback.\n\n#####options\n\nOptions are passed to the `setOptions()` method.\n\n- `sort`: if multiple docs are found by the condition, sets the sort order to choose which doc to modify and remove\n\n```js\nA.where().findOneAndRemove()\nA.where().findOneAndRemove(match)\nA.where().findOneAndRemove(match, options)\n\n// the following all execute the command\nA.where().findOneAndRemove(callback)\nA.where().findOneAndRemove(match, callback)\nA.where().findOneAndRemove(match, options, function (err, doc) {\n if (doc) {\n // the document may not be found\n console.log(doc);\n }\n})\n ```\n\n###distinct()\n\nDeclares this query a _distinct_ query. Optionally pass the distinct field, a match clause or callback. If a callback is passed the query is executed.\n\n```js\nmquery().distinct()\nmquery().distinct(match)\nmquery().distinct(match, field)\nmquery().distinct(field)\n\n// the following all execute the command\nmquery().distinct(callback)\nmquery().distinct(field, callback)\nmquery().distinct(match, callback)\nmquery().distinct(match, field, function (err, result) {\n console.log(result);\n})\n```\n\n###exec()\n\nExecutes the query.\n\n```js\nmquery().findOne().where('route').intersects(polygon).exec(function (err, docs){})\n```\n\n-------------\n\n###all()\n\nSpecifies an `$all` query condition\n\n```js\nmquery().where('permission').all(['read', 'write'])\n```\n\n[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/all/)\n\n###and()\n\nSpecifies arguments for an `$and` condition\n\n```js\nmquery().and([{ color: 'green' }, { status: 'ok' }])\n```\n\n[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/and/)\n\n###box()\n\nSpecifies a `$box` condition\n\n```js\nvar lowerLeft = [40.73083, -73.99756]\nvar upperRight= [40.741404, -73.988135]\n\nmquery().where('location').within().box(lowerLeft, upperRight)\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/box/)\n\n###circle()\n\nSpecifies a `$center` or `$centerSphere` condition.\n\n```js\nvar area = { center: [50, 50], radius: 10, unique: true }\nquery.where('loc').within().circle(area)\nquery.circle('loc', area);\n\n// for spherical calculations\nvar area = { center: [50, 50], radius: 10, unique: true, spherical: true }\nquery.where('loc').within().circle(area)\nquery.circle('loc', area);\n```\n\n- [MongoDB Documentation - center](http://docs.mongodb.org/manual/reference/operator/center/)\n- [MongoDB Documentation - centerSphere](http://docs.mongodb.org/manual/reference/operator/centerSphere/)\n\n###elemMatch()\n\nSpecifies an `$elemMatch` condition\n\n```js\nquery.where('comment').elemMatch({ author: 'autobot', votes: {$gte: 5}})\n\nquery.elemMatch('comment', function (elem) {\n elem.where('author').equals('autobot');\n elem.where('votes').gte(5);\n})\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/elemMatch/)\n\n###equals()\n\nSpecifies the complementary comparison value for the path specified with `where()`.\n\n```js\nmquery().where('age').equals(49);\n\n// is the same as\n\nmquery().where({ 'age': 49 });\n```\n\n###exists()\n\nSpecifies an `$exists` condition\n\n```js\n// { name: { $exists: true }}\nmquery().where('name').exists()\nmquery().where('name').exists(true)\nmquery().exists('name')\n\n// { name: { $exists: false }}\nmquery().where('name').exists(false);\nmquery().exists('name', false);\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/exists/)\n\n###geometry()\n\nSpecifies a `$geometry` condition\n\n```js\nvar polyA = [[[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]]\nquery.where('loc').within().geometry({ type: 'Polygon', coordinates: polyA })\n\n// or\nvar polyB = [[ 0, 0 ], [ 1, 1 ]]\nquery.where('loc').within().geometry({ type: 'LineString', coordinates: polyB })\n\n// or\nvar polyC = [ 0, 0 ]\nquery.where('loc').within().geometry({ type: 'Point', coordinates: polyC })\n\n// or\nquery.where('loc').intersects().geometry({ type: 'Point', coordinates: polyC })\n\n// or\nquery.where('loc').near().geometry({ type: 'Point', coordinates: [3,5] })\n```\n\n`geometry()` **must** come after `intersects()`, `within()`, or `near()`.\n\nThe `object` argument must contain `type` and `coordinates` properties.\n\n- type `String`\n- coordinates `Array`\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/geometry/)\n\n###gt()\n\nSpecifies a `$gt` query condition.\n\n```js\nmquery().where('clicks').gt(999)\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/gt/)\n\n###gte()\n\nSpecifies a `$gte` query condition.\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/gte/)\n\n```js\nmquery().where('clicks').gte(1000)\n```\n\n###in()\n\nSpecifies an `$in` query condition.\n\n```js\nmquery().where('author_id').in([3, 48901, 761])\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/in/)\n\n###intersects()\n\nDeclares an `$geoIntersects` query for `geometry()`.\n\n```js\nquery.where('path').intersects().geometry({\n type: 'LineString'\n , coordinates: [[180.0, 11.0], [180, 9.0]]\n})\n\n// geometry arguments are supported\nquery.where('path').intersects({\n type: 'LineString'\n , coordinates: [[180.0, 11.0], [180, 9.0]]\n})\n```\n\n**Must** be used after `where()`.\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/geoIntersects/)\n\n###lt()\n\nSpecifies a `$lt` query condition.\n\n```js\nmquery().where('clicks').lt(50)\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/lt/)\n\n###lte()\n\nSpecifies a `$lte` query condition.\n\n```js\nmquery().where('clicks').lte(49)\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/lte/)\n\n###maxDistance()\n\nSpecifies a `$maxDistance` query condition.\n\n```js\nmquery().where('location').near({ center: [139, 74.3] }).maxDistance(5)\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/maxDistance/)\n\n###mod()\n\nSpecifies a `$mod` condition\n\n```js\nmquery().where('count').mod(2, 0)\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/mod/)\n\n###ne()\n\nSpecifies a `$ne` query condition.\n\n```js\nmquery().where('status').ne('ok')\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/ne/)\n\n###nin()\n\nSpecifies an `$nin` query condition.\n\n```js\nmquery().where('author_id').nin([3, 48901, 761])\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/nin/)\n\n###nor()\n\nSpecifies arguments for an `$nor` condition.\n\n```js\nmquery().nor([{ color: 'green' }, { status: 'ok' }])\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/nor/)\n\n###near()\n\nSpecifies arguments for a `$near` or `$nearSphere` condition.\n\nThese operators return documents sorted by distance.\n\n####Example\n\n```js\nquery.where('loc').near({ center: [10, 10] });\nquery.where('loc').near({ center: [10, 10], maxDistance: 5 });\nquery.near('loc', { center: [10, 10], maxDistance: 5 });\n\n// GeoJSON\nquery.where('loc').near({ center: { type: 'Point', coordinates: [10, 10] }});\nquery.where('loc').near({ center: { type: 'Point', coordinates: [10, 10] }, maxDistance: 5, spherical: true });\nquery.where('loc').near().geometry({ type: 'Point', coordinates: [10, 10] });\n\n// For a $nearSphere condition, pass the `spherical` option.\nquery.near({ center: [10, 10], maxDistance: 5, spherical: true });\n```\n\n[MongoDB Documentation](http://www.mongodb.org/display/DOCS/Geospatial+Indexing)\n\n###or()\n\nSpecifies arguments for an `$or` condition.\n\n```js\nmquery().or([{ color: 'red' }, { status: 'emergency' }])\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/or/)\n\n###polygon()\n\nSpecifies a `$polygon` condition\n\n```js\nmquery().where('loc').within().polygon([10,20], [13, 25], [7,15])\nmquery().polygon('loc', [10,20], [13, 25], [7,15])\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/polygon/)\n\n###regex()\n\nSpecifies a `$regex` query condition.\n\n```js\nmquery().where('name').regex(/^sixstepsrecords/)\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/regex/)\n\n###select()\n\nSpecifies which document fields to include or exclude\n\n```js\n// 1 means include, 0 means exclude\nmquery().select({ name: 1, address: 1, _id: 0 })\n\n// or\n\nmquery().select('name address -_id')\n```\n\n#####String syntax\n\nWhen passing a string, prefixing a path with `-` will flag that path as excluded. When a path does not have the `-` prefix, it is included.\n\n```js\n// include a and b, exclude c\nquery.select('a b -c');\n\n// or you may use object notation, useful when\n// you have keys already prefixed with a \"-\"\nquery.select({a: 1, b: 1, c: 0});\n```\n\n_Cannot be used with `distinct()`._\n\n###size()\n\nSpecifies a `$size` query condition.\n\n```js\nmquery().where('someArray').size(6)\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/size/)\n\n###slice()\n\nSpecifies a `$slice` projection for a `path`\n\n```js\nmquery().where('comments').slice(5)\nmquery().where('comments').slice(-5)\nmquery().where('comments').slice([-10, 5])\n```\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/projection/slice/)\n\n###within()\n\nSets a `$geoWithin` or `$within` argument for geo-spatial queries.\n\n```js\nmquery().within().box()\nmquery().within().circle()\nmquery().within().geometry()\n\nmquery().where('loc').within({ center: [50,50], radius: 10, unique: true, spherical: true });\nmquery().where('loc').within({ box: [[40.73, -73.9], [40.7, -73.988]] });\nmquery().where('loc').within({ polygon: [[],[],[],[]] });\n\nmquery().where('loc').within([], [], []) // polygon\nmquery().where('loc').within([], []) // box\nmquery().where('loc').within({ type: 'LineString', coordinates: [...] }); // geometry\n```\n\nAs of mquery 2.0, `$geoWithin` is used by default. This impacts you if running MongoDB < 2.4. To alter this behavior, see [mquery.use$geoWithin](#mqueryusegeowithin).\n\n**Must** be used after `where()`.\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/geoWithin/)\n\n###where()\n\nSpecifies a `path` for use with chaining\n\n```js\n// instead of writing:\nmquery().find({age: {$gte: 21, $lte: 65}});\n\n// we can instead write:\nmquery().where('age').gte(21).lte(65);\n\n// passing query conditions is permitted too\nmquery().find().where({ name: 'vonderful' })\n\n// chaining\nmquery()\n.where('age').gte(21).lte(65)\n.where({ 'name': /^vonderful/i })\n.where('friends').slice(10)\n.exec(callback)\n```\n\n###$where()\n\nSpecifies a `$where` condition.\n\nUse `$where` when you need to select documents using a JavaScript expression.\n\n```js\nquery.$where('this.comments.length > 10 || this.name.length > 5').exec(callback)\n\nquery.$where(function () {\n return this.comments.length > 10 || this.name.length > 5;\n})\n```\n\nOnly use `$where` when you have a condition that cannot be met using other MongoDB operators like `$lt`. Be sure to read about all of [its caveats](http://docs.mongodb.org/manual/reference/operator/where/) before using.\n\n-----------\n\n###batchSize()\n\nSpecifies the batchSize option.\n\n```js\nquery.batchSize(100)\n```\n\n_Cannot be used with `distinct()`._\n\n[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.batchSize/)\n\n###comment()\n\nSpecifies the comment option.\n\n```js\nquery.comment('login query');\n```\n\n_Cannot be used with `distinct()`._\n\n[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/)\n\n###hint()\n\nSets query hints.\n\n```js\nmquery().hint({ indexA: 1, indexB: -1 })\n```\n\n_Cannot be used with `distinct()`._\n\n[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/hint/)\n\n###limit()\n\nSpecifies the limit option.\n\n```js\nquery.limit(20)\n```\n\n_Cannot be used with `distinct()`._\n\n[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.limit/)\n\n###maxScan()\n\nSpecifies the maxScan option.\n\n```js\nquery.maxScan(100)\n```\n\n_Cannot be used with `distinct()`._\n\n[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/maxScan/)\n\n###skip()\n\nSpecifies the skip option.\n\n```js\nquery.skip(100).limit(20)\n```\n\n_Cannot be used with `distinct()`._\n\n[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.skip/)\n\n###sort()\n\nSets the query sort order.\n\nIf an object is passed, key values allowed are `asc`, `desc`, `ascending`, `descending`, `1`, and `-1`.\n\nIf a string is passed, it must be a space delimited list of path names. The sort order of each path is ascending unless the path name is prefixed with `-` which will be treated as descending.\n\n```js\n// these are equivalent\nquery.sort({ field: 'asc', test: -1 });\nquery.sort('field -test');\n```\n\n_Cannot be used with `distinct()`._\n\n[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.sort/)\n\n###read()\n\nSets the readPreference option for the query.\n\n```js\nmquery().read('primary')\nmquery().read('p') // same as primary\n\nmquery().read('primaryPreferred')\nmquery().read('pp') // same as primaryPreferred\n\nmquery().read('secondary')\nmquery().read('s') // same as secondary\n\nmquery().read('secondaryPreferred')\nmquery().read('sp') // same as secondaryPreferred\n\nmquery().read('nearest')\nmquery().read('n') // same as nearest\n\n// specifying tags\nmquery().read('s', [{ dc:'sf', s: 1 },{ dc:'ma', s: 2 }])\n```\n\n#####Preferences:\n\n- `primary` - (default) Read from primary only. Operations will produce an error if primary is unavailable. Cannot be combined with tags.\n- `secondary` - Read from secondary if available, otherwise error.\n- `primaryPreferred` - Read from primary if available, otherwise a secondary.\n- `secondaryPreferred` - Read from a secondary if available, otherwise read from the primary.\n- `nearest` - All operations read from among the nearest candidates, but unlike other modes, this option will include both the primary and all secondaries in the random selection.\n\nAliases\n\n- `p` primary\n- `pp` primaryPreferred\n- `s` secondary\n- `sp` secondaryPreferred\n- `n` nearest\n\nRead more about how to use read preferrences [here](http://docs.mongodb.org/manual/applications/replication/#read-preference) and [here](http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences).\n\n###slaveOk()\n\nSets the slaveOk option. `true` allows reading from secondaries.\n\n**deprecated** use [read()](#read) preferences instead if on mongodb >= 2.2\n\n```js\nquery.slaveOk() // true\nquery.slaveOk(true)\nquery.slaveOk(false)\n```\n\n[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/rs.slaveOk/)\n\n###snapshot()\n\nSpecifies this query as a snapshot query.\n\n```js\nmquery().snapshot() // true\nmquery().snapshot(true)\nmquery().snapshot(false)\n```\n\n_Cannot be used with `distinct()`._\n\n[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/snapshot/)\n\n###tailable()\n\nSets tailable option.\n\n```js\nmquery().tailable() <== true\nmquery().tailable(true)\nmquery().tailable(false)\n```\n\n_Cannot be used with `distinct()`._\n\n[MongoDB Documentation](http://docs.mongodb.org/manual/tutorial/create-tailable-cursor/)\n\n##Helpers\n\n###collection()\n\nSets the querys collection.\n\n```js\nmquery().collection(aCollection)\n```\n\n\n###merge(object)\n\nMerges other mquery or match condition objects into this one. When an muery instance is passed, its match conditions, field selection and options are merged.\n\n```js\nvar drum = mquery({ type: 'drum' }).collection(instruments);\nvar redDrum = mqery({ color: 'red' }).merge(drum);\nredDrum.count(function (err, n) {\n console.log('there are %d red drums', n);\n})\n```\n\nInternally uses `mquery.canMerge` to determine validity.\n\n###setOptions(options)\n\nSets query options.\n\n```js\nmquery().setOptions({ collection: coll, limit: 20 })\n```\n\n#####options\n\n- [tailable](#tailable) *\n- [sort](#sort) *\n- [limit](#limit) *\n- [skip](#skip) *\n- [maxScan](#maxScan) *\n- [batchSize](#batchSize) *\n- [comment](#comment) *\n- [snapshot](#snapshot) *\n- [hint](#hint) *\n- [slaveOk](#slaveOk) *\n- [safe](http://docs.mongodb.org/manual/reference/write-concern/): Boolean - passed through to the collection. Setting to `true` is equivalent to `{ w: 1 }`\n- [collection](#collection): the collection to query against\n\n_* denotes a query helper method is also available_\n\n###mquery.canMerge(conditions)\n\nDetermines if `conditions` can be merged using `mquery().merge()`.\n\n```js\nvar query = mquery({ type: 'drum' });\nvar okToMerge = mquery.canMerge(anObject)\nif (okToMerge) {\n query.merge(anObject);\n}\n```\n\n##mquery.use$geoWithin\n\nMongoDB 2.4 introduced the `$geoWithin` operator which replaces and is 100% backward compatible with `$within`. As of mquery 0.2, we default to using `$geoWithin` for all `within()` calls.\n\nIf you are running MongoDB < 2.4 this will be problematic. To force `mquery` to be backward compatible and always use `$within`, set the `mquery.use$geoWithin` flag to `false`.\n\n```js\nmquery.use$geoWithin = false;\n```\n\n##Custom Base Queries\n\nOften times we want custom base queries that encapsulate predefined criteria. With `mquery` this is easy. First create the query you want to reuse and call its `toConstructor()` method which returns a new subclass of `mquery` that retains all options and criteria of the original.\n\n```js\nvar greatMovies = mquery(movieCollection).where('rating').gte(4.5).toConstructor();\n\n// use it!\ngreatMovies().count(function (err, n) {\n console.log('There are %d great movies', n);\n});\n\ngreatMovies().where({ name: /^Life/ }).select('name').find(function (err, docs) {\n console.log(docs);\n});\n```\n\n##Validation\n\nMethod and options combinations are checked for validity at runtime to prevent creation of invalid query constructs. For example, a `distinct` query does not support specifying options like `hint` or field selection. In this case an error will be thrown so you can catch these mistakes in development.\n\n##Debug support\n\nDebug mode is provided through the use of the [debug](https://github.com/visionmedia/debug) module. To enable:\n\n DEBUG=mquery node yourprogram.js\n\nRead the debug module documentation for more details.\n\n##Future goals\n\n - mongo shell compatibility\n - browser compatibility\n - mongoose compatibility\n\n## Installation\n\n $ npm install mquery\n\n## License\n\n[MIT](https://github.com/aheckmann/mquery/blob/master/LICENSE)\n\n", + "readmeFilename": "README.md", + "_id": "mquery@0.3.2", + "dist": { + "shasum": "074cb82c51ec1b15897d8afb80a7b3567a2f8eca" + }, + "_from": "mquery@0.3.2", + "_resolved": "https://registry.npmjs.org/mquery/-/mquery-0.3.2.tgz" +} diff --git a/node_modules/mongoose/node_modules/mquery/test/collection/browser.js b/node_modules/mongoose/node_modules/mquery/test/collection/browser.js new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/mongoose/node_modules/mquery/test/collection/mongo.js b/node_modules/mongoose/node_modules/mquery/test/collection/mongo.js new file mode 100644 index 0000000..e69de29 diff --git a/node_modules/mongoose/node_modules/mquery/test/collection/node.js b/node_modules/mongoose/node_modules/mquery/test/collection/node.js new file mode 100644 index 0000000..43f446e --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/test/collection/node.js @@ -0,0 +1,29 @@ + +var assert = require('assert') +var slice = require('sliced') +var mongo = require('mongodb') +var utils = require('../../').utils; + +var uri = process.env.MQUERY_URI || 'mongodb://localhost/mquery'; +var db; + +exports.getCollection = function (cb) { + mongo.Db.connect(uri, function (err, db_) { + assert.ifError(err); + db = db_; + + var collection = db.collection('stuff'); + collection.opts.safe = true; + + // clean test db before starting + db.dropDatabase(function () { + cb(null, collection); + }); + }) +} + +exports.dropCollection = function (cb) { + db.dropDatabase(function () { + db.close(cb); + }) +} diff --git a/node_modules/mongoose/node_modules/mquery/test/env.js b/node_modules/mongoose/node_modules/mquery/test/env.js new file mode 100644 index 0000000..9b9b80b --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/test/env.js @@ -0,0 +1,20 @@ + +var assert = require('assert') +var env = require('../').env; + +console.log('environment: %s', env.type); + +var col; +switch (env.type) { + case 'node': + col = require('./collection/node'); + break; + case 'mongo': + col = require('./collection/mongo'); + case 'browser': + col = require('./collection/browser'); + default: + throw new Error('missing collection implementation for environment: ' + env.type); +} + +module.exports = exports = col; diff --git a/node_modules/mongoose/node_modules/mquery/test/index.js b/node_modules/mongoose/node_modules/mquery/test/index.js new file mode 100644 index 0000000..293e089 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/test/index.js @@ -0,0 +1,2574 @@ + +var mquery = require('../') +var mongo = require('mongodb') +var assert = require('assert') +var slice = require('sliced') + +describe('mquery', function(){ + var col; + + before(function(done){ + // get the env specific collection interface + require('./env').getCollection(function (err, collection) { + assert.ifError(err); + col = collection; + done(); + }); + }) + + after(function(done){ + require('./env').dropCollection(done); + }) + + describe('mquery', function(){ + it('is a function', function(){ + assert.equal('function', typeof mquery); + }) + it('creates instances with the `new` keyword', function(){ + assert.ok(mquery() instanceof mquery); + }) + describe('defaults', function(){ + it('are set', function(){ + var m = mquery(); + assert.strictEqual(undefined, m.op); + assert.deepEqual({}, m.options); + }) + }) + describe('criteria', function(){ + it('if collection-like is used as collection', function(){ + var m = mquery(col); + assert.equal(col, m._collection.collection); + }) + it('non-collection-like is used as criteria', function(){ + var m = mquery({ works: true }); + assert.ok(!m._collection); + assert.deepEqual({ works: true }, m._conditions); + }) + }) + describe('options', function(){ + it('are merged when passed', function(){ + var m = mquery(col, { safe: true }); + assert.deepEqual({ safe: true }, m.options); + var m = mquery({ name: 'mquery' }, { safe: true }); + assert.deepEqual({ safe: true }, m.options); + }) + }) + }) + + describe('toConstructor', function(){ + it('creates subclasses of mquery', function(){ + var opts = { safe: { w: 'majority' }, readPreference: 'p' }; + var match = { name: 'test', count: { $gt: 101 }}; + var select = { name: 1, count: 0 } + var update = { $set: { x: true }}; + var path = 'street'; + + var q = mquery().setOptions(opts); + q.where(match); + q.select(select); + q.update(update); + q.where(path); + q.find(); + + var M = q.toConstructor(); + var m = M(); + + assert.ok(m instanceof mquery); + assert.deepEqual(opts, m.options); + assert.deepEqual(match, m._conditions); + assert.deepEqual(select, m._fields); + assert.deepEqual(update, m._update); + assert.equal(path, m._path); + assert.equal('find', m.op); + }) + }) + + describe('setOptions', function(){ + it('calls associated methods', function(){ + var m = mquery(); + assert.equal(m._collection, null); + m.setOptions({ collection: col }); + assert.equal(m._collection.collection, col); + }) + it('directly sets option when no method exists', function(){ + var m = mquery(); + assert.equal(m.options.woot, null); + m.setOptions({ woot: 'yay' }); + assert.equal(m.options.woot, 'yay'); + }) + it('is chainable', function(){ + var m = mquery(); + var n = m.setOptions(); + assert.equal(m, n); + var n = m.setOptions({ x: 1 }); + assert.equal(m, n); + }) + }) + + describe('collection', function(){ + it('sets the _collection', function(){ + var m = mquery(); + m.collection(col); + assert.equal(m._collection.collection, col); + }) + it('is chainable', function(){ + var m = mquery(); + var n = m.collection(col); + assert.equal(m, n); + }) + }) + + describe('$where', function(){ + it('sets the $where condition', function(){ + var m = mquery(); + function go () {} + m.$where(go); + assert.ok(go === m._conditions.$where); + }) + it('is chainable', function(){ + var m = mquery(); + var n = m.$where('x'); + assert.equal(m, n); + }) + }) + + describe('where', function(){ + it('without arguments', function(){ + var m = mquery(); + m.where(); + assert.deepEqual({}, m._conditions); + }) + it('with non-string/object argument', function(){ + var m = mquery(); + + assert.throws(function(){ + m.where([]); + }, /path must be a string or object/); + }) + describe('with one argument', function(){ + it('that is an object', function(){ + var m = mquery(); + m.where({ name: 'flawed' }); + assert.strictEqual(m._conditions.name, 'flawed'); + }) + it('that is a query', function(){ + var m = mquery({ name: 'first' }); + var n = mquery({ name: 'changed' }); + m.where(n); + assert.strictEqual(m._conditions.name, 'changed'); + }) + it('that is a string', function(){ + var m = mquery(); + m.where('name'); + assert.equal('name', m._path); + assert.strictEqual(m._conditions.name, undefined); + }) + }) + it('with two arguments', function(){ + var m = mquery(); + m.where('name', 'The Great Pumpkin'); + assert.equal('name', m._path); + assert.strictEqual(m._conditions.name, 'The Great Pumpkin'); + }) + it('is chainable', function(){ + var m = mquery(); + var n = m.where('x', 'y'); + assert.equal(m, n); + var n = m.where() + assert.equal(m, n); + }) + }) + + describe('equals', function(){ + it('must be called after where()', function(){ + var m = mquery(); + assert.throws(function () { + m.equals(); + }, /must be used after where/) + }) + it('sets value of path set with where()', function(){ + var m = mquery(); + m.where('age').equals(1000); + assert.deepEqual({ age: 1000 }, m._conditions); + }) + it('is chainable', function(){ + var m = mquery(); + var n = m.where('x').equals(3); + assert.equal(m, n); + }) + }) + + describe('or', function(){ + it('pushes onto the internal $or condition', function(){ + var m = mquery(); + m.or({ 'Nightmare Before Christmas': true }); + assert.deepEqual([{'Nightmare Before Christmas': true }], m._conditions.$or) + }) + it('allows passing arrays', function(){ + var m = mquery(); + var arg = [{ 'Nightmare Before Christmas': true }, { x: 1 }]; + m.or(arg); + assert.deepEqual(arg, m._conditions.$or) + }) + it('allows calling multiple times', function(){ + var m = mquery(); + var arg = [{ looper: true }, { x: 1 }]; + m.or(arg); + m.or({ y: 1 }) + m.or([{ w: 'oo' }, { z: 'oo'} ]) + assert.deepEqual([{looper:true},{x:1},{y:1},{w:'oo'},{z:'oo'}], m._conditions.$or) + }) + it('is chainable', function(){ + var m = mquery(); + m.or({ o: "k"}).where('name', 'table'); + assert.deepEqual({ name: 'table', $or: [{ o: 'k' }] }, m._conditions) + }) + }) + + describe('nor', function(){ + it('pushes onto the internal $nor condition', function(){ + var m = mquery(); + m.nor({ 'Nightmare Before Christmas': true }); + assert.deepEqual([{'Nightmare Before Christmas': true }], m._conditions.$nor) + }) + it('allows passing arrays', function(){ + var m = mquery(); + var arg = [{ 'Nightmare Before Christmas': true }, { x: 1 }]; + m.nor(arg); + assert.deepEqual(arg, m._conditions.$nor) + }) + it('allows calling multiple times', function(){ + var m = mquery(); + var arg = [{ looper: true }, { x: 1 }]; + m.nor(arg); + m.nor({ y: 1 }) + m.nor([{ w: 'oo' }, { z: 'oo'} ]) + assert.deepEqual([{looper:true},{x:1},{y:1},{w:'oo'},{z:'oo'}], m._conditions.$nor) + }) + it('is chainable', function(){ + var m = mquery(); + m.nor({ o: "k"}).where('name', 'table'); + assert.deepEqual({ name: 'table', $nor: [{ o: 'k' }] }, m._conditions) + }) + }) + + describe('and', function(){ + it('pushes onto the internal $and condition', function(){ + var m = mquery(); + m.and({ 'Nightmare Before Christmas': true }); + assert.deepEqual([{'Nightmare Before Christmas': true }], m._conditions.$and) + }) + it('allows passing arrays', function(){ + var m = mquery(); + var arg = [{ 'Nightmare Before Christmas': true }, { x: 1 }]; + m.and(arg); + assert.deepEqual(arg, m._conditions.$and) + }) + it('allows calling multiple times', function(){ + var m = mquery(); + var arg = [{ looper: true }, { x: 1 }]; + m.and(arg); + m.and({ y: 1 }) + m.and([{ w: 'oo' }, { z: 'oo'} ]) + assert.deepEqual([{looper:true},{x:1},{y:1},{w:'oo'},{z:'oo'}], m._conditions.$and) + }) + it('is chainable', function(){ + var m = mquery(); + m.and({ o: "k"}).where('name', 'table'); + assert.deepEqual({ name: 'table', $and: [{ o: 'k' }] }, m._conditions) + }) + }) + + function generalCondition (type) { + return function () { + it('accepts 2 args', function(){ + var m = mquery()[type]('count', 3); + var check = {}; + check['$' + type] = 3; + assert.deepEqual(m._conditions.count, check); + }) + it('uses previously set `where` path if 1 arg passed', function(){ + var m = mquery().where('count')[type](3); + var check = {}; + check['$' + type] = 3; + assert.deepEqual(m._conditions.count, check); + }) + it('throws if 1 arg was passed but no previous `where` was used', function(){ + assert.throws(function(){ + mquery()[type](3); + }, /must be used after where/); + }) + it('is chainable', function(){ + var m = mquery().where('count')[type](3).where('x', 8); + var check = {x: 8, count: {}}; + check.count['$' + type] = 3; + assert.deepEqual(m._conditions, check); + }) + it('overwrites previous value', function(){ + var m = mquery().where('count')[type](3)[type](8); + var check = {}; + check['$' + type] = 8; + assert.deepEqual(m._conditions.count, check); + }) + } + } + + 'gt gte lt lte ne in nin regex size maxDistance'.split(' ').forEach(function (type) { + describe(type, generalCondition(type)) + }) + + describe('mod', function () { + describe('with 1 argument', function(){ + it('requires a previous where()', function(){ + assert.throws(function () { + mquery().mod([30, 10]) + }, /must be used after where/); + }) + it('works', function(){ + var m = mquery().where('madmen').mod([10,20]); + assert.deepEqual(m._conditions, { madmen: { $mod: [10,20] }}) + }) + }) + + describe('with 2 arguments and second is non-Array', function(){ + it('requires a previous where()', function(){ + assert.throws(function () { + mquery().mod('x', 10) + }, /must be used after where/); + }) + it('works', function(){ + var m = mquery().where('madmen').mod(10, 20); + assert.deepEqual(m._conditions, { madmen: { $mod: [10,20] }}) + }) + }) + + it('with 2 arguments and second is an array', function(){ + var m = mquery().mod('madmen', [10,20]); + assert.deepEqual(m._conditions, { madmen: { $mod: [10,20] }}) + }) + + it('with 3 arguments', function(){ + var m = mquery().mod('madmen', 10, 20); + assert.deepEqual(m._conditions, { madmen: { $mod: [10,20] }}) + }) + + it('is chainable', function(){ + var m = mquery().mod('madmen', 10, 20).where('x', 8); + var check = { madmen: { $mod: [10,20] }, x: 8}; + assert.deepEqual(m._conditions, check); + }) + }) + + describe('exists', function(){ + it('with 0 args', function(){ + it('throws if not used after where()', function(){ + assert.throws(function () { + mquery().exists() + }, /must be used after where/); + }) + it('works', function(){ + var m = mquery().where('name').exists(); + var check = { name: { $exists: true }}; + assert.deepEqual(m._conditions, check); + }) + }) + + describe('with 1 arg', function(){ + describe('that is boolean', function(){ + it('throws if not used after where()', function(){ + assert.throws(function () { + mquery().exists() + }, /must be used after where/); + }) + it('works', function(){ + var m = mquery().exists('name', false); + var check = { name: { $exists: false }}; + assert.deepEqual(m._conditions, check); + }) + }) + describe('that is not boolean', function(){ + it('sets the value to `true`', function(){ + var m = mquery().where('name').exists('yummy'); + var check = { yummy: { $exists: true }}; + assert.deepEqual(m._conditions, check); + }) + }) + }) + + describe('with 2 args', function(){ + it('works', function(){ + var m = mquery().exists('yummy', false); + var check = { yummy: { $exists: false }}; + assert.deepEqual(m._conditions, check); + }) + }) + + it('is chainable', function(){ + var m = mquery().where('name').exists().find({ x: 1 }); + var check = { name: { $exists: true }, x: 1}; + assert.deepEqual(m._conditions, check); + }) + }) + + describe('elemMatch', function(){ + describe('with null/undefined first argument', function(){ + assert.throws(function () { + mquery().elemMatch(); + }, /Invalid argument/); + assert.throws(function () { + mquery().elemMatch(null); + }, /Invalid argument/); + assert.doesNotThrow(function () { + mquery().elemMatch('', {}); + }); + }) + + describe('with 1 argument', function(){ + it('throws if not a function or object', function(){ + assert.throws(function () { + mquery().elemMatch([]); + }, /Invalid argument/); + }) + + describe('that is an object', function(){ + it('throws if no previous `where` was used', function(){ + assert.throws(function () { + mquery().elemMatch({}); + }, /must be used after where/); + }) + it('works', function(){ + var m = mquery().where('comment').elemMatch({ author: 'joe', votes: {$gte: 3 }}); + assert.deepEqual({ comment: { $elemMatch: { author: 'joe', votes: {$gte: 3}}}}, m._conditions); + }) + }) + describe('that is a function', function(){ + it('throws if no previous `where` was used', function(){ + assert.throws(function () { + mquery().elemMatch(function(){}); + }, /must be used after where/); + }) + it('works', function(){ + var m = mquery().where('comment').elemMatch(function (query) { + query.where({ author: 'joe', votes: {$gte: 3 }}) + }); + assert.deepEqual({ comment: { $elemMatch: { author: 'joe', votes: {$gte: 3}}}}, m._conditions); + }) + }) + }) + + describe('with 2 arguments', function(){ + describe('and the 2nd is an object', function(){ + it('works', function(){ + var m = mquery().elemMatch('comment', { author: 'joe', votes: {$gte: 3 }}); + assert.deepEqual({ comment: { $elemMatch: { author: 'joe', votes: {$gte: 3}}}}, m._conditions); + }) + }) + describe('and the 2nd is a function', function(){ + it('works', function(){ + var m = mquery().elemMatch('comment', function (query) { + query.where({ author: 'joe', votes: {$gte: 3 }}) + }); + assert.deepEqual({ comment: { $elemMatch: { author: 'joe', votes: {$gte: 3}}}}, m._conditions); + }) + }) + it('and the 2nd is not a function or object', function(){ + assert.throws(function () { + mquery().elemMatch('comment', []); + }, /Invalid argument/); + }) + }) + }) + + describe('within', function(){ + it('is chainable', function(){ + var m = mquery(); + assert.equal(m.where('a').within(), m); + }) + describe('when called with arguments', function(){ + it('must follow where()', function(){ + assert.throws(function () { + mquery().within([]); + }, /must be used after where/); + }) + + describe('of length 1', function(){ + it('throws if not a recognized shape', function(){ + assert.throws(function () { + mquery().where('loc').within({}); + }, /Invalid argument/) + assert.throws(function () { + mquery().where('loc').within(null); + }, /Invalid argument/) + }) + it('delegates to circle when center exists', function(){ + var m = mquery().where('loc').within({ center: [10,10], radius: 3 }); + assert.deepEqual({ $geoWithin: {$center:[[10,10], 3]}}, m._conditions.loc); + }) + it('delegates to box when exists', function(){ + var m = mquery().where('loc').within({ box: [[10,10], [11,14]] }); + assert.deepEqual({ $geoWithin: {$box:[[10,10], [11,14]]}}, m._conditions.loc); + }) + it('delegates to polygon when exists', function(){ + var m = mquery().where('loc').within({ polygon: [[10,10], [11,14],[10,9]] }); + assert.deepEqual({ $geoWithin: {$polygon:[[10,10], [11,14],[10,9]]}}, m._conditions.loc); + }) + it('delegates to geometry when exists', function(){ + var m = mquery().where('loc').within({ type: 'Polygon', coordinates: [[10,10], [11,14],[10,9]] }); + assert.deepEqual({ $geoWithin: {$geometry: {type:'Polygon', coordinates: [[10,10], [11,14],[10,9]]}}}, m._conditions.loc); + }) + }) + + describe('of length 2', function(){ + it('delegates to box()', function(){ + var m = mquery().where('loc').within([1,2],[2,5]); + assert.deepEqual(m._conditions.loc, { $geoWithin: { $box: [[1,2],[2,5]]}}); + }) + }) + + describe('of length > 2', function(){ + it('delegates to polygon()', function(){ + var m = mquery().where('loc').within([1,2],[2,5],[2,4],[1,3]); + assert.deepEqual(m._conditions.loc, { $geoWithin: { $polygon: [[1,2],[2,5],[2,4],[1,3]]}}); + }) + }) + }) + }) + + describe('geoWithin', function(){ + before(function(){ + mquery.use$geoWithin = false; + }) + after(function(){ + mquery.use$geoWithin = true; + }) + describe('when called with arguments', function(){ + describe('of length 1', function(){ + it('delegates to circle when center exists', function(){ + var m = mquery().where('loc').within({ center: [10,10], radius: 3 }); + assert.deepEqual({ $within: {$center:[[10,10], 3]}}, m._conditions.loc); + }) + it('delegates to box when exists', function(){ + var m = mquery().where('loc').within({ box: [[10,10], [11,14]] }); + assert.deepEqual({ $within: {$box:[[10,10], [11,14]]}}, m._conditions.loc); + }) + it('delegates to polygon when exists', function(){ + var m = mquery().where('loc').within({ polygon: [[10,10], [11,14],[10,9]] }); + assert.deepEqual({ $within: {$polygon:[[10,10], [11,14],[10,9]]}}, m._conditions.loc); + }) + it('delegates to geometry when exists', function(){ + var m = mquery().where('loc').within({ type: 'Polygon', coordinates: [[10,10], [11,14],[10,9]] }); + assert.deepEqual({ $within: {$geometry: {type:'Polygon', coordinates: [[10,10], [11,14],[10,9]]}}}, m._conditions.loc); + }) + }) + + describe('of length 2', function(){ + it('delegates to box()', function(){ + var m = mquery().where('loc').within([1,2],[2,5]); + assert.deepEqual(m._conditions.loc, { $within: { $box: [[1,2],[2,5]]}}); + }) + }) + + describe('of length > 2', function(){ + it('delegates to polygon()', function(){ + var m = mquery().where('loc').within([1,2],[2,5],[2,4],[1,3]); + assert.deepEqual(m._conditions.loc, { $within: { $polygon: [[1,2],[2,5],[2,4],[1,3]]}}); + }) + }) + }) + }) + + describe('box', function(){ + describe('with 1 argument', function(){ + it('throws', function(){ + assert.throws(function () { + mquery().box('sometihng'); + }, /Invalid argument/); + }) + }) + describe('with > 3 arguments', function(){ + it('throws', function(){ + assert.throws(function () { + mquery().box(1,2,3,4); + }, /Invalid argument/); + }) + }) + + describe('with 2 arguments', function(){ + it('throws if not used after where()', function(){ + assert.throws(function () { + mquery().box([],[]); + }, /must be used after where/); + }) + it('works', function(){ + var m = mquery().where('loc').box([1,2],[3,4]); + assert.deepEqual(m._conditions.loc, { $geoWithin: { $box: [[1,2],[3,4]] }}); + }) + }) + + describe('with 3 arguments', function(){ + it('works', function(){ + var m = mquery().box('loc', [1,2],[3,4]); + assert.deepEqual(m._conditions.loc, { $geoWithin: { $box: [[1,2],[3,4]] }}); + }) + }) + }) + + describe('polygon', function(){ + describe('when first argument is not a string', function(){ + it('throws if not used after where()', function(){ + assert.throws(function () { + mquery().polygon({}); + }, /must be used after where/); + + assert.doesNotThrow(function () { + mquery().where('loc').polygon([1,2], [2,3], [3,6]); + }); + }) + + it('assigns arguments to within polygon condition', function(){ + var m = mquery().where('loc').polygon([1,2], [2,3], [3,6]); + assert.deepEqual(m._conditions, { loc: {$geoWithin: {$polygon: [[1,2],[2,3],[3,6]]}} }); + }) + }) + + describe('when first arg is a string', function(){ + it('assigns remaining arguments to within polygon condition', function(){ + var m = mquery().polygon('loc', [1,2], [2,3], [3,6]); + assert.deepEqual(m._conditions, { loc: {$geoWithin: {$polygon: [[1,2],[2,3],[3,6]]}} }); + }) + }) + }) + + describe('circle', function(){ + describe('with one arg', function(){ + it('must follow where()', function(){ + assert.throws(function () { + mquery().circle('x'); + }, /must be used after where/); + assert.doesNotThrow(function () { + mquery().where('loc').circle({center:[0,0], radius: 3 }); + }); + }) + it('works', function(){ + var m = mquery().where('loc').circle({center:[0,0], radius: 3 }); + assert.deepEqual(m._conditions, { loc: { $geoWithin: {$center: [[0,0],3] }}}); + }) + }) + describe('with 3 args', function(){ + it('throws', function(){ + assert.throws(function () { + mquery().where('loc').circle(1,2,3); + }, /Invalid argument/); + }) + }) + describe('requires radius and center', function(){ + assert.throws(function () { + mquery().circle('loc', { center: 1 }); + }, /center and radius are required/); + assert.throws(function () { + mquery().circle('loc', { radius: 1 }); + }, /center and radius are required/); + assert.doesNotThrow(function () { + mquery().circle('loc', { center: [1,2], radius: 1 }); + }); + }) + }) + + describe('geometry', function(){ + // within + intersects + var point = { type: 'Point', coordinates: [[0,0],[1,1]] }; + + it('must be called after within or intersects', function(done){ + assert.throws(function () { + mquery().where('a').geometry(point); + }, /must come after/); + + assert.doesNotThrow(function () { + mquery().where('a').within().geometry(point); + }); + + assert.doesNotThrow(function () { + mquery().where('a').intersects().geometry(point); + }); + + done(); + }) + + describe('when called with one argument', function(){ + describe('after within()', function(){ + it('and arg quacks like geoJSON', function(done){ + var m = mquery().where('a').within().geometry(point); + assert.deepEqual({ a: { $geoWithin: { $geometry: point }}}, m._conditions); + done(); + }) + }) + + describe('after intersects()', function(){ + it('and arg quacks like geoJSON', function(done){ + var m = mquery().where('a').intersects().geometry(point); + assert.deepEqual({ a: { $geoIntersects: { $geometry: point }}}, m._conditions); + done(); + }) + }) + + it('and arg does not quack like geoJSON', function(done){ + assert.throws(function () { + mquery().where('b').within().geometry({type:1, coordinates:2}); + }, /Invalid argument/); + done(); + }) + }) + + describe('when called with zero arguments', function(){ + it('throws', function(done){ + assert.throws(function () { + mquery().where('a').within().geometry(); + }, /Invalid argument/); + + done(); + }) + }) + + describe('when called with more than one arguments', function(){ + it('throws', function(done){ + assert.throws(function () { + mquery().where('a').within().geometry({type:'a',coordinates:[]}, 2); + }, /Invalid argument/); + done(); + }) + }) + }) + + describe('intersects', function(){ + it('must be used after where()', function(done){ + var m = mquery(); + assert.throws(function () { + m.intersects(); + }, /must be used after where/) + done(); + }) + + it('sets geo comparison to "$intersects"', function(done){ + var n = mquery().where('a').intersects(); + assert.equal('$geoIntersects', n._geoComparison); + done(); + }) + + it('is chainable', function(){ + var m = mquery(); + assert.equal(m.where('a').intersects(), m); + }) + + it('calls geometry if argument quacks like geojson', function(done){ + var m = mquery(); + var o = { type: 'LineString', coordinates: [[0,1],[3,40]] }; + var ran = false; + + m.geometry = function (arg) { + ran = true; + assert.deepEqual(o, arg); + } + + m.where('a').intersects(o); + assert.ok(ran); + + done(); + }) + + it('throws if argument is not geometry-like', function(done){ + var m = mquery().where('a'); + + assert.throws(function () { + m.intersects(null); + }, /Invalid argument/); + + assert.throws(function () { + m.intersects(undefined); + }, /Invalid argument/); + + assert.throws(function () { + m.intersects(false); + }, /Invalid argument/); + + assert.throws(function () { + m.intersects({}); + }, /Invalid argument/); + + assert.throws(function () { + m.intersects([]); + }, /Invalid argument/); + + assert.throws(function () { + m.intersects(function(){}); + }, /Invalid argument/); + + assert.throws(function () { + m.intersects(NaN); + }, /Invalid argument/); + + done(); + }) + }) + + describe('near', function(){ + // near nearSphere + describe('with 0 args', function(){ + it('is compatible with geometry()', function(done){ + var q = mquery().where('x').near().geometry({ type: 'Point', coordinates: [180, 11] }); + assert.deepEqual({ $near: {$geometry: {type:'Point', coordinates: [180,11]}}}, q._conditions.x); + done(); + }) + }) + + describe('with 1 arg', function(){ + it('throws if not used after where()', function(){ + assert.throws(function () { + mquery().near(1); + }, /must be used after where/) + }) + it('does not throw if used after where()', function(){ + assert.doesNotThrow(function () { + mquery().where('loc').near({center:[1,1]}); + }) + }) + }) + describe('with > 2 args', function(){ + it('throws', function(){ + assert.throws(function () { + mquery().near(1,2,3); + }, /Invalid argument/) + }) + }) + + it('creates $geometry args for GeoJSON', function(){ + var m = mquery().where('loc').near({ center: { type: 'Point', coordinates: [10,10] }}); + assert.deepEqual({ $near: {$geometry: {type:'Point', coordinates: [10,10]}}}, m._conditions.loc); + }) + + it('expects `center`', function(){ + assert.throws(function () { + mquery().near('loc', { maxDistance: 3 }); + }, /center is required/) + assert.doesNotThrow(function () { + mquery().near('loc', { center: [3,4] }); + }) + }) + + it('accepts spherical conditions', function(){ + var m = mquery().where('loc').near({ center: [1,2], spherical: true }); + assert.deepEqual(m._conditions, { loc: { $nearSphere: [1,2]}}); + }) + + it('is non-spherical by default', function(){ + var m = mquery().where('loc').near({ center: [1,2] }); + assert.deepEqual(m._conditions, { loc: { $near: [1,2]}}); + }) + + it('supports maxDistance', function(){ + var m = mquery().where('loc').near({ center: [1,2], maxDistance:4 }); + assert.deepEqual(m._conditions, { loc: { $near: [1,2], $maxDistance: 4}}); + }) + + it('is chainable', function(){ + var m = mquery().where('loc').near({ center: [1,2], maxDistance:4 }).find({ x: 1 }); + assert.deepEqual(m._conditions, { loc: { $near: [1,2], $maxDistance: 4}, x: 1}); + }) + + describe('supports passing GeoJSON, gh-13', function(){ + it('with center', function(){ + var m = mquery().where('loc').near({ + center: { type: 'Point', coordinates: [1,1] } + , maxDistance: 2 + }); + + var expect = { + loc: { + $near: { + $geometry: { + type: 'Point' + , coordinates : [1,1] + } + } + , $maxDistance : 2 + } + } + + assert.deepEqual(m._conditions, expect); + }) + }) + }) + + // fields + + describe('select', function(){ + describe('with 0 args', function(){ + it('is chainable', function(){ + var m = mquery() + assert.equal(m, m.select()); + }) + }) + + it('accepts an object', function(){ + var o = { x: 1, y: 1 } + var m = mquery().select(o); + assert.deepEqual(m._fields, o); + }) + + it('accepts a string', function(){ + var o = 'x -y'; + var m = mquery().select(o); + assert.deepEqual(m._fields, { x: 1, y: 0 }); + }) + + it('does not accept an array', function(done){ + assert.throws(function () { + var o = ['x', '-y']; + var m = mquery().select(o); + }, /Invalid select/); + done(); + }) + + it('merges previous arguments', function(){ + var o = { x: 1, y: 0, a: 1 } + var m = mquery().select(o); + m.select('z -u w').select({ x: 0 }) + assert.deepEqual(m._fields, { + x: 0 + , y: 0 + , z: 1 + , u: 0 + , w: 1 + , a: 1 + }); + }) + + it('rejects non-string, object, arrays', function(){ + assert.throws(function () { + mquery().select(function(){}); + }, /Invalid select\(\) argument/); + }) + + it('accepts aguments objects', function(){ + var m = mquery(); + function t () { + m.select(arguments); + assert.deepEqual(m._fields, { x: 1, y: 0 }); + } + t('x', '-y'); + }) + + noDistinct('select'); + no('count', 'select'); + }) + + describe('slice', function(){ + describe('with 0 args', function(){ + it('is chainable', function(){ + var m = mquery() + assert.equal(m, m.slice()); + }) + it('is a noop', function(){ + var m = mquery().slice(); + assert.deepEqual(m._fields, undefined); + }) + }) + + describe('with 1 arg', function(){ + it('throws if not called after where()', function(){ + assert.throws(function () { + mquery().slice(1); + }, /must be used after where/); + assert.doesNotThrow(function () { + mquery().where('a').slice(1); + }); + }) + it('that is a number', function(){ + var query = mquery(); + query.where('collection').slice(5); + assert.deepEqual(query._fields, {collection: {$slice: 5}}); + }) + it('that is an array', function(){ + var query = mquery(); + query.where('collection').slice([5,10]); + assert.deepEqual(query._fields, {collection: {$slice: [5,10]}}); + }) + }) + + describe('with 2 args', function(){ + describe('and first is a number', function(){ + it('throws if not called after where', function(){ + assert.throws(function () { + mquery().slice(2,3); + }, /must be used after where/); + }) + it('does not throw if used after where', function(){ + var query = mquery(); + query.where('collection').slice(2,3); + assert.deepEqual(query._fields, {collection: {$slice: [2,3]}}); + }) + }) + it('and first is not a number', function(){ + var query = mquery().slice('collection', [-5, 2]); + assert.deepEqual(query._fields, {collection: {$slice: [-5,2]}}); + }) + }) + + describe('with 3 args', function(){ + it('works', function(){ + var query = mquery(); + query.slice('collection', 14, 10); + assert.deepEqual(query._fields, {collection: {$slice: [14, 10]}}); + }) + }) + + noDistinct('slice'); + no('count', 'slice'); + }) + + // options + + describe('sort', function(){ + describe('with 0 args', function(){ + it('chains', function(){ + var m = mquery(); + assert.equal(m, m.sort()); + }) + it('has no affect', function(){ + var m = mquery(); + assert.equal(m.options.sort, undefined); + }) + }) + + it('works', function(){ + var query = mquery(); + query.sort('a -c b'); + assert.deepEqual(query.options.sort, { a : 1, b: 1, c : -1}); + + query = mquery(); + query.sort({'a': 1, 'c': -1, 'b': 'asc', e: 'descending', f: 'ascending'}); + assert.deepEqual(query.options.sort, {'a': 1, 'c': -1, 'b': 1, 'e': -1, 'f': 1}); + + query = mquery(); + var e= undefined; + try { + query.sort(['a', 1]); + } catch (err) { + e= err; + } + assert.ok(e, 'uh oh. no error was thrown'); + assert.equal(e.message, 'Invalid sort() argument. Must be a string or object.'); + + e= undefined; + try { + query.sort('a', 1, 'c', -1, 'b', 1); + } catch (err) { + e= err; + } + assert.ok(e, 'uh oh. no error was thrown'); + assert.equal(e.message, 'Invalid sort() argument. Must be a string or object.'); + }) + + no('count', 'sort'); + }) + + function simpleOption (type) { + describe(type, function(){ + it('sets the ' + type + ' option', function(){ + var m = mquery()[type](2); + assert.equal(2, m.options[type]); + }) + it('is chainable', function(){ + var m = mquery(); + assert.equal(m[type](3), m); + }) + + noDistinct(type); + + if ('limit' == type || 'skip' == type) return; + no('count', type); + }) + } + + 'limit skip maxScan batchSize comment'.split(' ').forEach(simpleOption); + + describe('snapshot', function(){ + it('works', function(){ + var query = mquery(); + query.snapshot(); + assert.equal(true, query.options.snapshot); + + var query = mquery() + query.snapshot(true); + assert.equal(true, query.options.snapshot); + + var query = mquery() + query.snapshot(false); + assert.equal(false, query.options.snapshot); + }) + noDistinct('snapshot'); + no('count', 'snapshot'); + }) + + describe('hint', function(){ + it('accepts an object', function(){ + var query2 = mquery(); + query2.hint({'a': 1, 'b': -1}); + assert.deepEqual(query2.options.hint, {'a': 1, 'b': -1}); + }) + + it('rejects everything else', function(){ + assert.throws(function(){ + mquery().hint('c'); + }, /Invalid hint./); + assert.throws(function(){ + mquery().hint(['c']); + }, /Invalid hint./); + assert.throws(function(){ + mquery().hint(1); + }, /Invalid hint./); + }) + + describe('does not have side affects', function(){ + it('on invalid arg', function(){ + var m = mquery(); + try { + m.hint(1); + } catch (err) { + // ignore + } + assert.equal(undefined, m.options.hint); + }) + it('on missing arg', function(){ + var m = mquery().hint(); + assert.equal(undefined, m.options.hint); + }) + }) + + noDistinct('hint'); + no('count', 'hint'); + }) + + describe('slaveOk', function(){ + it('works', function(){ + var query = mquery(); + query.slaveOk(); + assert.equal(true, query.options.slaveOk); + + var query = mquery() + query.slaveOk(true); + assert.equal(true, query.options.slaveOk); + + var query = mquery() + query.slaveOk(false); + assert.equal(false, query.options.slaveOk); + }) + }) + + describe('read', function(){ + it('sets associated readPreference option', function(){ + var m = mquery(); + m.read('p'); + assert.equal('primary', m.options.readPreference.mode); + }) + it('is chainable', function(){ + var m = mquery(); + assert.equal(m, m.read('sp')); + }) + }) + + describe('tailable', function(){ + it('works', function(){ + var query = mquery(); + query.tailable(); + assert.equal(true, query.options.tailable); + + var query = mquery() + query.tailable(true); + assert.equal(true, query.options.tailable); + + var query = mquery() + query.tailable(false); + assert.equal(false, query.options.tailable); + }) + it('is chainable', function(){ + var m = mquery(); + assert.equal(m, m.tailable()); + }) + noDistinct('tailable'); + no('count', 'tailable'); + }) + + // utils + + describe('merge', function(){ + describe('with falsy arg', function(){ + it('returns itself', function(){ + var m = mquery(); + assert.equal(m, m.merge()); + assert.equal(m, m.merge(null)); + assert.equal(m, m.merge(0)); + }) + }) + describe('with an argument', function(){ + describe('that is not a query or plain object', function(){ + it('throws', function(){ + assert.throws(function () { + mquery().merge([]); + }, /Invalid argument/); + assert.throws(function () { + mquery().merge('merge'); + }, /Invalid argument/); + assert.doesNotThrow(function () { + mquery().merge({}); + }, /Invalid argument/); + }) + }) + + describe('that is a query', function(){ + it('merges conditions, field selection, and options', function(){ + var m = mquery({ x: 'hi' }, { select: 'x y', another: true }) + var n = mquery().merge(m); + assert.deepEqual(n._conditions, m._conditions); + assert.deepEqual(n._fields, m._fields); + assert.deepEqual(n.options, m.options); + }) + it('clones update arguments', function(done){ + var original = { $set: { iTerm: true }} + var m = mquery().update(original); + var n = mquery().merge(m); + m.update({ $set: { x: 2 }}) + assert.notDeepEqual(m._update, n._update); + done(); + }) + it('is chainable', function(){ + var m = mquery({ x: 'hi' }); + var n = mquery(); + assert.equal(n, n.merge(m)); + }) + }) + + describe('that is an object', function(){ + it('merges', function(){ + var m = { x: 'hi' }; + var n = mquery().merge(m); + assert.deepEqual(n._conditions, { x: 'hi' }); + }) + it('clones update arguments', function(done){ + var original = { $set: { iTerm: true }} + var m = mquery().update(original); + var n = mquery().merge(original); + m.update({ $set: { x: 2 }}) + assert.notDeepEqual(m._update, n._update); + done(); + }) + it('is chainable', function(){ + var m = { x: 'hi' }; + var n = mquery(); + assert.equal(n, n.merge(m)); + }) + }) + }) + }) + + // queries + + describe('find', function(){ + describe('with no callback', function(){ + it('does not execute', function(){ + var m = mquery(); + assert.doesNotThrow(function () { + m.find() + }) + assert.doesNotThrow(function () { + m.find({ x: 1 }) + }) + }) + }) + + it('is chainable', function(){ + var m = mquery().find({ x: 1 }).find().find({ y: 2 }); + assert.deepEqual(m._conditions, {x:1,y:2}); + }) + + it('merges other queries', function(){ + var m = mquery({ name: 'mquery' }); + m.tailable(); + m.select('_id'); + var a = mquery().find(m); + assert.deepEqual(a._conditions, m._conditions); + assert.deepEqual(a.options, m.options); + assert.deepEqual(a._fields, m._fields); + }) + + describe('executes', function(){ + before(function (done) { + col.insert({ name: 'mquery' }, { safe: true }, done); + }); + + after(function(done){ + col.remove({ name: 'mquery' }, done); + }) + + it('when criteria is passed with a callback', function(done){ + mquery(col).find({ name: 'mquery' }, function (err, docs) { + assert.ifError(err); + assert.equal(1, docs.length); + done(); + }) + }) + it('when Quer yis passed with a callback', function(done){ + var m = mquery({ name: 'mquery' }); + mquery(col).find(m, function (err, docs) { + assert.ifError(err); + assert.equal(1, docs.length); + done(); + }) + }) + it('when just a callback is passed', function(done){ + mquery({ name: 'mquery' }).collection(col).find(function (err, docs) { + assert.ifError(err); + assert.equal(1, docs.length); + done(); + }); + }) + }) + }) + + describe('findOne', function(){ + describe('with no callback', function(){ + it('does not execute', function(){ + var m = mquery(); + assert.doesNotThrow(function () { + m.findOne() + }) + assert.doesNotThrow(function () { + m.findOne({ x: 1 }) + }) + }) + }) + + it('is chainable', function(){ + var m = mquery(); + var n = m.findOne({ x: 1 }).findOne().findOne({ y: 2 }); + assert.equal(m, n); + assert.deepEqual(m._conditions, {x:1,y:2}); + assert.equal('findOne', m.op); + }) + + it('merges other queries', function(){ + var m = mquery({ name: 'mquery' }); + m.read('nearest'); + m.select('_id'); + var a = mquery().findOne(m); + assert.deepEqual(a._conditions, m._conditions); + assert.deepEqual(a.options, m.options); + assert.deepEqual(a._fields, m._fields); + }) + + describe('executes', function(){ + before(function (done) { + col.insert({ name: 'mquery findone' }, { safe: true }, done); + }); + + after(function(done){ + col.remove({ name: 'mquery findone' }, done); + }) + + it('when criteria is passed with a callback', function(done){ + mquery(col).findOne({ name: 'mquery findone' }, function (err, doc) { + assert.ifError(err); + assert.ok(doc); + assert.equal('mquery findone', doc.name); + done(); + }) + }) + it('when Query is passed with a callback', function(done){ + var m = mquery(col).where({ name: 'mquery findone' }); + mquery(col).findOne(m, function (err, doc) { + assert.ifError(err); + assert.ok(doc); + assert.equal('mquery findone', doc.name); + done(); + }) + }) + it('when just a callback is passed', function(done){ + mquery({ name: 'mquery findone' }).collection(col).findOne(function (err, doc) { + assert.ifError(err); + assert.ok(doc); + assert.equal('mquery findone', doc.name); + done(); + }); + }) + }) + }) + + describe('count', function(){ + describe('with no callback', function(){ + it('does not execute', function(){ + var m = mquery(); + assert.doesNotThrow(function () { + m.count() + }) + assert.doesNotThrow(function () { + m.count({ x: 1 }) + }) + }) + }) + + it('is chainable', function(){ + var m = mquery(); + var n = m.count({ x: 1 }).count().count({ y: 2 }); + assert.equal(m, n); + assert.deepEqual(m._conditions, {x:1,y:2}); + assert.equal('count', m.op); + }) + + it('merges other queries', function(){ + var m = mquery({ name: 'mquery' }); + m.read('nearest'); + m.select('_id'); + var a = mquery().count(m); + assert.deepEqual(a._conditions, m._conditions); + assert.deepEqual(a.options, m.options); + assert.deepEqual(a._fields, m._fields); + }) + + describe('executes', function(){ + before(function (done) { + col.insert({ name: 'mquery count' }, { safe: true }, done); + }); + + after(function(done){ + col.remove({ name: 'mquery count' }, done); + }) + + it('when criteria is passed with a callback', function(done){ + mquery(col).count({ name: 'mquery count' }, function (err, count) { + assert.ifError(err); + assert.ok(count); + assert.ok(1 === count); + done(); + }) + }) + it('when Query is passed with a callback', function(done){ + var m = mquery({ name: 'mquery count' }); + mquery(col).count(m, function (err, count) { + assert.ifError(err); + assert.ok(count); + assert.ok(1 === count); + done(); + }) + }) + it('when just a callback is passed', function(done){ + mquery({ name: 'mquery count' }).collection(col).count(function (err, count) { + assert.ifError(err); + assert.ok(1 === count); + done(); + }); + }) + }) + + describe('validates its option', function(){ + it('sort', function(done){ + assert.throws(function(){ + var m = mquery().sort('x').count(); + }, /sort cannot be used with count/); + done(); + }) + + it('select', function(done){ + assert.throws(function(){ + var m = mquery().select('x').count(); + }, /field selection and slice cannot be used with count/); + done(); + }) + + it('slice', function(done){ + assert.throws(function(){ + var m = mquery().where('x').slice(-3).count(); + }, /field selection and slice cannot be used with count/); + done(); + }) + + it('limit', function(done){ + assert.doesNotThrow(function(){ + var m = mquery().limit(3).count(); + }) + done(); + }) + + it('skip', function(done){ + assert.doesNotThrow(function(){ + var m = mquery().skip(3).count(); + }) + done(); + }) + + it('batchSize', function(done){ + assert.throws(function(){ + var m = mquery({}, { batchSize: 3 }).count(); + }, /batchSize cannot be used with count/); + done(); + }) + + it('comment', function(done){ + assert.throws(function(){ + var m = mquery().comment('mquery').count(); + }, /comment cannot be used with count/); + done(); + }) + + it('maxScan', function(done){ + assert.throws(function(){ + var m = mquery().maxScan(300).count(); + }, /maxScan cannot be used with count/); + done(); + }) + + it('snapshot', function(done){ + assert.throws(function(){ + var m = mquery().snapshot().count(); + }, /snapshot cannot be used with count/); + done(); + }) + + it('hint', function(done){ + assert.throws(function(){ + var m = mquery().hint({ x: 1 }).count(); + }, /hint cannot be used with count/); + done(); + }) + + it('tailable', function(done){ + assert.throws(function(){ + var m = mquery().tailable().count(); + }, /tailable cannot be used with count/); + done(); + }) + }) + }) + + describe('distinct', function(){ + describe('with no callback', function(){ + it('does not execute', function(){ + var m = mquery(); + assert.doesNotThrow(function () { + m.distinct() + }) + assert.doesNotThrow(function () { + m.distinct('name') + }) + assert.doesNotThrow(function () { + m.distinct({ name: 'mquery distinct' }) + }) + assert.doesNotThrow(function () { + m.distinct({ name: 'mquery distinct' }, 'name') + }) + }) + }) + + it('is chainable', function(){ + var m = mquery({x:1}).distinct('name'); + var n = m.distinct({y:2}); + assert.equal(m, n); + assert.deepEqual(n._conditions, {x:1, y:2}); + assert.equal('name', n._distinct); + assert.equal('distinct', n.op); + }); + + it('overwrites field', function(){ + var m = mquery({ name: 'mquery' }).distinct('name'); + m.distinct('rename'); + assert.equal(m._distinct, 'rename'); + m.distinct({x:1}, 'renamed'); + assert.equal(m._distinct, 'renamed'); + }) + + it('merges other queries', function(){ + var m = mquery().distinct({ name: 'mquery' }, 'age') + m.read('nearest'); + var a = mquery().distinct(m); + assert.deepEqual(a._conditions, m._conditions); + assert.deepEqual(a.options, m.options); + assert.deepEqual(a._fields, m._fields); + assert.deepEqual(a._distinct, m._distinct); + }) + + describe('executes', function(){ + before(function (done) { + col.insert({ name: 'mquery distinct', age: 1 }, { safe: true }, done); + }); + + after(function(done){ + col.remove({ name: 'mquery distinct' }, done); + }) + + it('when distinct arg is passed with a callback', function(done){ + mquery(col).distinct('distinct', function (err, doc) { + assert.ifError(err); + assert.ok(doc); + done(); + }) + }) + describe('when criteria is passed with a callback', function(){ + it('if distinct arg was declared', function(done){ + mquery(col).distinct('age').distinct({ name: 'mquery distinct' }, function (err, doc) { + assert.ifError(err); + assert.ok(doc); + done(); + }) + }) + it('but not if distinct arg was not declared', function(){ + assert.throws(function(){ + mquery(col).distinct({ name: 'mquery distinct' }, function(){}) + }, /No value for `distinct`/) + }) + }) + describe('when Query is passed with a callback', function(){ + var m = mquery({ name: 'mquery distinct' }); + it('if distinct arg was declared', function(done){ + mquery(col).distinct('age').distinct(m, function (err, doc) { + assert.ifError(err); + assert.ok(doc); + done(); + }) + }) + it('but not if distinct arg was not declared', function(){ + assert.throws(function(){ + mquery(col).distinct(m, function(){}) + }, /No value for `distinct`/) + }) + }) + describe('when just a callback is passed', function(done){ + it('if distinct arg was declared', function(done){ + var m = mquery({ name: 'mquery distinct' }); + m.collection(col); + m.distinct('age'); + m.distinct(function (err, doc) { + assert.ifError(err); + assert.ok(doc); + done(); + }); + }) + it('but not if no distinct arg was declared', function(){ + var m = mquery(); + m.collection(col); + assert.throws(function () { + m.distinct(function(){}); + }, /No value for `distinct`/); + }) + }) + }) + + describe('validates its option', function(){ + it('sort', function(done){ + assert.throws(function(){ + var m = mquery().sort('x').distinct(); + }, /sort cannot be used with distinct/); + done(); + }) + + it('select', function(done){ + assert.throws(function(){ + var m = mquery().select('x').distinct(); + }, /field selection and slice cannot be used with distinct/); + done(); + }) + + it('slice', function(done){ + assert.throws(function(){ + var m = mquery().where('x').slice(-3).distinct(); + }, /field selection and slice cannot be used with distinct/); + done(); + }) + + it('limit', function(done){ + assert.throws(function(){ + var m = mquery().limit(3).distinct(); + }, /limit cannot be used with distinct/); + done(); + }) + + it('skip', function(done){ + assert.throws(function(){ + var m = mquery().skip(3).distinct(); + }, /skip cannot be used with distinct/); + done(); + }) + + it('batchSize', function(done){ + assert.throws(function(){ + var m = mquery({}, { batchSize: 3 }).distinct(); + }, /batchSize cannot be used with distinct/); + done(); + }) + + it('comment', function(done){ + assert.throws(function(){ + var m = mquery().comment('mquery').distinct(); + }, /comment cannot be used with distinct/); + done(); + }) + + it('maxScan', function(done){ + assert.throws(function(){ + var m = mquery().maxScan(300).distinct(); + }, /maxScan cannot be used with distinct/); + done(); + }) + + it('snapshot', function(done){ + assert.throws(function(){ + var m = mquery().snapshot().distinct(); + }, /snapshot cannot be used with distinct/); + done(); + }) + + it('hint', function(done){ + assert.throws(function(){ + var m = mquery().hint({ x: 1 }).distinct(); + }, /hint cannot be used with distinct/); + done(); + }) + + it('tailable', function(done){ + assert.throws(function(){ + var m = mquery().tailable().distinct(); + }, /tailable cannot be used with distinct/); + done(); + }) + }) + }) + + describe('update', function(){ + describe('with no callback', function(){ + it('does not execute', function(){ + var m = mquery(); + assert.doesNotThrow(function () { + m.update({ name: 'old' }, { name: 'updated' }, { multi: true }) + }) + assert.doesNotThrow(function () { + m.update({ name: 'old' }, { name: 'updated' }) + }) + assert.doesNotThrow(function () { + m.update({ name: 'updated' }) + }) + assert.doesNotThrow(function () { + m.update() + }) + }) + }) + + it('is chainable', function(){ + var m = mquery({x:1}).update({ y: 2 }); + var n = m.where({y:2}); + assert.equal(m, n); + assert.deepEqual(n._conditions, {x:1, y:2}); + assert.deepEqual({ y: 2 }, n._update); + assert.equal('update', n.op); + }); + + it('merges update doc arg', function(){ + var a = [1,2]; + var m = mquery().where({ name: 'mquery' }).update({ x: 'stuff', a: a }); + m.update({ z: 'stuff' }); + assert.deepEqual(m._update, { z: 'stuff', x: 'stuff', a: a }); + assert.deepEqual(m._conditions, { name: 'mquery' }); + assert.ok(!m.options.overwrite); + m.update({}, { z: 'renamed' }, { overwrite: true }); + assert.ok(m.options.overwrite === true); + assert.deepEqual(m._conditions, { name: 'mquery' }); + assert.deepEqual(m._update, { z: 'renamed', x: 'stuff', a: a }); + a.push(3); + assert.notDeepEqual(m._update, { z: 'renamed', x: 'stuff', a: a }); + }) + + it('merges other options', function(){ + var m = mquery(); + m.setOptions({ overwrite: true }); + m.update({ age: 77 }, { name: 'pagemill' }, { multi: true }) + assert.deepEqual({ age: 77 }, m._conditions); + assert.deepEqual({ name: 'pagemill' }, m._update); + assert.deepEqual({ overwrite: true, multi: true }, m.options); + }) + + describe('executes', function(){ + var id; + before(function (done) { + // TODO refactor to not use id + id = new mongo.ObjectID; + col.insert({ _id: id, name: 'mquery update', age: 1 }, { safe: true }, done); + }); + + after(function(done){ + col.remove({ _id: id }, done); + }) + + describe('when conds + doc + opts + callback passed', function(){ + it('works', function(done){ + var m = mquery(col).where({ _id: id }) + m.update({}, { name: 'Sparky' }, { safe: true }, function (err, num) { + assert.ifError(err); + assert.ok(1 === num); + m.findOne(function (err, doc) { + assert.ifError(err); + assert.equal(doc.name, 'Sparky'); + done(); + }) + }) + }) + }) + + describe('when conds + doc + callback passed', function(){ + it('works', function (done) { + var m = mquery(col).update({ _id: id }, { name: 'fairgrounds' }, function (err, num, doc) { + assert.ifError(err); + assert.ok(1, num); + m.findOne(function (err, doc) { + assert.ifError(err); + assert.equal(doc.name, 'fairgrounds'); + done(); + }) + }) + }) + }) + + describe('when doc + callback passed', function(){ + it('works', function (done) { + var m = mquery(col).where({ _id: id }).update({ name: 'changed' }, function (err, num, doc) { + assert.ifError(err); + assert.ok(1, num); + m.findOne(function (err, doc) { + assert.ifError(err); + assert.equal(doc.name, 'changed'); + done(); + }) + }) + }) + }) + + describe('when just callback passed', function(){ + it('works', function (done) { + var m = mquery(col).where({ _id: id }); + m.setOptions({ safe: true }); + m.update({ name: 'Frankenweenie' }); + m.update(function (err, num) { + assert.ifError(err); + assert.ok(1 === num); + m.findOne(function (err, doc) { + assert.ifError(err); + assert.equal(doc.name, 'Frankenweenie'); + done(); + }) + }) + }) + }) + + describe('without a callback', function(){ + it('when forced by exec()', function(done){ + var m = mquery(col).where({ _id: id }); + m.setOptions({ safe: true, multi: true }); + m.update({ name: 'forced' }); + + var update = m._collection.update; + m._collection.update = function (conds, doc, opts, cb) { + m._collection.update = update; + + assert.ok(!opts.safe); + assert.ok(true === opts.multi); + assert.equal('forced', doc.$set.name); + done(); + } + + m.exec() + }) + }) + + describe('except when update doc is empty and missing overwrite flag', function(){ + it('works', function (done) { + var m = mquery(col).where({ _id: id }); + m.setOptions({ safe: true }); + m.update({ }, function (err, num) { + assert.ifError(err); + assert.ok(0 === num); + setTimeout(function(){ + m.findOne(function (err, doc) { + assert.ifError(err); + assert.equal(3, mquery.utils.keys(doc).length); + assert.equal(id, doc._id.toString()); + assert.equal('Frankenweenie', doc.name); + done(); + }) + }, 300); + }) + }) + }); + + describe('when update doc is set with overwrite flag', function(){ + it('works', function (done) { + var m = mquery(col).where({ _id: id }); + m.setOptions({ safe: true, overwrite: true }); + m.update({ all: 'yep', two: 2 }, function (err, num) { + assert.ifError(err); + assert.ok(1 === num); + m.findOne(function (err, doc) { + assert.ifError(err); + assert.equal(3, mquery.utils.keys(doc).length); + assert.equal('yep', doc.all); + assert.equal(2, doc.two); + assert.equal(id, doc._id.toString()); + done(); + }) + }) + }) + }) + + describe('when update doc is empty with overwrite flag', function(){ + it('works', function (done) { + var m = mquery(col).where({ _id: id }); + m.setOptions({ safe: true, overwrite: true }); + m.update({ }, function (err, num) { + assert.ifError(err); + assert.ok(1 === num); + m.findOne(function (err, doc) { + assert.ifError(err); + assert.equal(1, mquery.utils.keys(doc).length); + assert.equal(id, doc._id.toString()); + done(); + }) + }) + }) + }) + + describe('when boolean (true) - exec()', function(){ + it('works', function(done){ + var m = mquery(col).where({ _id: id }); + m.update({ name: 'bool' }).update(true); + setTimeout(function () { + m.findOne(function (err, doc) { + assert.ifError(err); + assert.ok(doc); + assert.equal('bool', doc.name); + done(); + }) + }, 300) + }) + }) + }) + }) + + describe('remove', function(){ + describe('with 0 args', function(){ + var name = 'remove: no args test' + before(function(done){ + col.insert({ name: name }, { safe: true }, done) + }) + after(function(done){ + col.remove({ name: name }, { safe: true }, done) + }) + + it('does not execute', function(done){ + var remove = col.remove; + col.remove = function () { + col.remove = remove; + done(new Error('remove executed!')); + } + + var m = mquery(col).where({ name: name }).remove() + setTimeout(function () { + col.remove = remove; + done(); + }, 10); + }) + + it('chains', function(){ + var m = mquery(); + assert.equal(m, m.remove()); + }) + }) + + describe('with 1 argument', function(){ + var name = 'remove: 1 arg test' + before(function(done){ + col.insert({ name: name }, { safe: true }, done) + }) + after(function(done){ + col.remove({ name: name }, { safe: true }, done) + }) + + describe('that is a', function(){ + it('plain object', function(){ + var m = mquery(col).remove({ name: 'Whiskers' }); + m.remove({ color: '#fff' }) + assert.deepEqual({ name: 'Whiskers', color: '#fff' }, m._conditions); + }) + + it('query', function(){ + var q = mquery({ color: '#fff' }); + var m = mquery(col).remove({ name: 'Whiskers' }); + m.remove(q) + assert.deepEqual({ name: 'Whiskers', color: '#fff' }, m._conditions); + }) + + it('function', function(done){ + mquery(col, { safe: true }).where({name: name}).remove(function (err) { + assert.ifError(err); + mquery(col).findOne({ name: name }, function (err, doc) { + assert.ifError(err); + assert.equal(null, doc); + done(); + }) + }); + }) + + it('boolean (true) - execute', function(done){ + col.insert({ name: name }, { safe: true }, function (err) { + assert.ifError(err); + mquery(col).findOne({ name: name }, function (err, doc) { + assert.ifError(err); + assert.ok(doc); + mquery(col).remove(true); + setTimeout(function () { + mquery(col).find(function (err, docs) { + assert.ifError(err); + assert.ok(docs); + assert.equal(0, docs.length); + done(); + }) + }, 300) + }) + }) + }) + }) + }) + + describe('with 2 arguments', function(){ + var name = 'remove: 2 arg test' + beforeEach(function(done){ + col.remove({}, { safe: true }, function (err) { + assert.ifError(err); + col.insert([{ name: 'shelly' }, { name: name }], { safe: true }, function (err) { + assert.ifError(err); + mquery(col).find(function (err, docs) { + assert.ifError(err); + assert.equal(2, docs.length); + done(); + }) + }) + }) + }) + + describe('plain object + callback', function(){ + it('works', function(done){ + mquery(col).remove({ name: name }, function (err) { + assert.ifError(err); + mquery(col).find(function (err, docs) { + assert.ifError(err); + assert.ok(docs); + assert.equal(1, docs.length); + assert.equal('shelly', docs[0].name); + done(); + }) + }); + }) + }) + + describe('mquery + callback', function(){ + it('works', function(done){ + var m = mquery({ name: name }); + mquery(col).remove(m, function (err) { + assert.ifError(err); + mquery(col).find(function (err, docs) { + assert.ifError(err); + assert.ok(docs); + assert.equal(1, docs.length); + assert.equal('shelly', docs[0].name); + done(); + }) + }); + }) + }) + }) + }) + + function validateFindAndModifyOptions (method) { + describe('validates its option', function(){ + it('sort', function(done){ + assert.doesNotThrow(function(){ + var m = mquery().sort('x')[method](); + }) + done(); + }) + + it('select', function(done){ + assert.doesNotThrow(function(){ + var m = mquery().select('x')[method](); + }) + done(); + }) + + it('limit', function(done){ + assert.throws(function(){ + var m = mquery().limit(3)[method](); + }, new RegExp('limit cannot be used with ' + method)); + done(); + }) + + it('skip', function(done){ + assert.throws(function(){ + var m = mquery().skip(3)[method](); + }, new RegExp('skip cannot be used with ' + method)); + done(); + }) + + it('batchSize', function(done){ + assert.throws(function(){ + var m = mquery({}, { batchSize: 3 })[method](); + }, new RegExp('batchSize cannot be used with ' + method)); + done(); + }) + + it('maxScan', function(done){ + assert.throws(function(){ + var m = mquery().maxScan(300)[method](); + }, new RegExp('maxScan cannot be used with ' + method)); + done(); + }) + + it('snapshot', function(done){ + assert.throws(function(){ + var m = mquery().snapshot()[method](); + }, new RegExp('snapshot cannot be used with ' + method)); + done(); + }) + + it('hint', function(done){ + assert.throws(function(){ + var m = mquery().hint({ x: 1 })[method](); + }, new RegExp('hint cannot be used with ' + method)); + done(); + }) + + it('tailable', function(done){ + assert.throws(function(){ + var m = mquery().tailable()[method](); + }, new RegExp('tailable cannot be used with ' + method)); + done(); + }) + + it('comment', function(done){ + assert.throws(function(){ + var m = mquery().comment('mquery')[method](); + }, new RegExp('comment cannot be used with ' + method)); + done(); + }) + }) + } + + describe('findOneAndUpdate', function(){ + var name = 'findOneAndUpdate + fn' + + validateFindAndModifyOptions('findOneAndUpdate'); + + describe('with 0 args', function(){ + it('makes no changes', function(){ + var m = mquery(); + var n = m.findOneAndUpdate(); + assert.deepEqual(m, n); + }) + }) + describe('with 1 arg', function(){ + describe('that is an object', function(){ + it('updates the doc', function(){ + var m = mquery(); + var n = m.findOneAndUpdate({ $set: { name: '1 arg' }}); + assert.deepEqual(n._update, { $set: { name: '1 arg' }}); + }) + }) + describe('that is a query', function(){ + it('updates the doc', function(){ + var m = mquery({ name: name }).update({ x: 1 }); + var n = mquery().findOneAndUpdate(m); + assert.deepEqual(n._update, { x: 1 }); + }) + }) + it('that is a function', function(done){ + col.insert({ name: name }, { safe: true }, function (err) { + assert.ifError(err); + var m = mquery({ name: name }).collection(col); + name = '1 arg'; + var n = m.update({ $set: { name: name }}); + n.findOneAndUpdate(function (err, doc) { + assert.ifError(err); + assert.ok(doc); + assert.equal(name, doc.name); + done(); + }); + }) + }) + }) + describe('with 2 args', function(){ + it('conditions + update', function(){ + var m = mquery(col); + m.findOneAndUpdate({ name: name }, { age: 100 }); + assert.deepEqual({ name: name }, m._conditions); + assert.deepEqual({ age: 100 }, m._update); + }) + it('query + update', function(){ + var n = mquery({ name: name }); + var m = mquery(col); + m.findOneAndUpdate(n, { age: 100 }); + assert.deepEqual({ name: name }, m._conditions); + assert.deepEqual({ age: 100 }, m._update); + }) + it('update + callback', function(done){ + var m = mquery(col).where({ name: name }); + m.findOneAndUpdate({ $inc: { age: 10 }}, function (err, doc) { + assert.ifError(err); + assert.equal(10, doc.age); + done(); + }); + }) + }) + describe('with 3 args', function(){ + it('conditions + update + options', function(){ + var m = mquery(); + var n = m.findOneAndUpdate({ name: name }, { works: true }, { new: false }); + assert.deepEqual({ name: name}, n._conditions); + assert.deepEqual({ works: true }, n._update); + assert.deepEqual({ new: false }, n.options); + }) + it('conditions + update + callback', function(done){ + var m = mquery(col); + m.findOneAndUpdate({ name: name }, { works: true }, function (err, doc) { + assert.ifError(err); + assert.ok(doc); + assert.equal(name, doc.name); + assert.ok(true === doc.works); + done(); + }); + }) + }) + describe('with 4 args', function(){ + it('conditions + update + options + callback', function(done){ + var m = mquery(col); + m.findOneAndUpdate({ name: name }, { works: false }, { new: false }, function (err, doc) { + assert.ifError(err); + assert.ok(doc); + assert.equal(name, doc.name); + assert.ok(true === doc.works); + done(); + }); + }) + }) + }) + + describe('findOneAndRemove', function(){ + var name = 'findOneAndRemove' + + validateFindAndModifyOptions('findOneAndRemove'); + + describe('with 0 args', function(){ + it('makes no changes', function(){ + var m = mquery(); + var n = m.findOneAndRemove(); + assert.deepEqual(m, n); + }) + }) + describe('with 1 arg', function(){ + describe('that is an object', function(){ + it('updates the doc', function(){ + var m = mquery(); + var n = m.findOneAndRemove({ name: '1 arg' }); + assert.deepEqual(n._conditions, { name: '1 arg' }); + }) + }) + describe('that is a query', function(){ + it('updates the doc', function(){ + var m = mquery({ name: name }); + var n = m.findOneAndRemove(m); + assert.deepEqual(n._conditions, { name: name }); + }) + }) + it('that is a function', function(done){ + col.insert({ name: name }, { safe: true }, function (err) { + assert.ifError(err); + var m = mquery({ name: name }).collection(col); + m.findOneAndRemove(function (err, doc) { + assert.ifError(err); + assert.ok(doc); + assert.equal(name, doc.name); + done(); + }); + }) + }) + }) + describe('with 2 args', function(){ + it('conditions + options', function(){ + var m = mquery(col); + m.findOneAndRemove({ name: name }, { new: false }); + assert.deepEqual({ name: name }, m._conditions); + assert.deepEqual({ new: false }, m.options); + }) + it('query + options', function(){ + var n = mquery({ name: name }); + var m = mquery(col); + m.findOneAndRemove(n, { sort: { x: 1 }}); + assert.deepEqual({ name: name }, m._conditions); + assert.deepEqual({ sort: { 'x': 1 }}, m.options); + }) + it('conditions + callback', function(done){ + col.insert({ name: name }, { safe: true }, function (err) { + assert.ifError(err); + var m = mquery(col); + m.findOneAndRemove({ name: name }, function (err, doc) { + assert.ifError(err); + assert.equal(name, doc.name); + done(); + }); + }); + }) + it('query + callback', function(done){ + col.insert({ name: name }, { safe: true }, function (err) { + assert.ifError(err); + var n = mquery({ name: name }) + var m = mquery(col); + m.findOneAndRemove(n, function (err, doc) { + assert.ifError(err); + assert.equal(name, doc.name); + done(); + }); + }); + }) + }) + describe('with 3 args', function(){ + it('conditions + options + callback', function(done){ + name = 'findOneAndRemove + conds + options + cb'; + col.insert([{ name: name }, { name: 'a' }], { safe: true }, function (err) { + assert.ifError(err); + var m = mquery(col); + m.findOneAndRemove({ name: name }, { sort: { name: 1 }}, function (err, doc) { + assert.ifError(err); + assert.ok(doc); + assert.equal(name, doc.name); + done(); + }); + }) + }) + }) + }) + + describe('exec', function(){ + beforeEach(function(done){ + col.insert([{ name: 'exec', age: 1 }, { name: 'exec', age: 2 }], done); + }) + + afterEach(function(done){ + mquery(col).remove(done); + }) + + it('requires an op', function(){ + assert.throws(function () { + mquery().exec() + }, /Missing query type/); + }) + + it('find', function(done){ + var m = mquery(col).find({ name: 'exec' }); + m.exec(function (err, docs) { + assert.ifError(err); + assert.equal(2, docs.length); + done(); + }) + }) + + it('findOne', function(done){ + var m = mquery(col).findOne({ age: 2 }); + m.exec(function (err, doc) { + assert.ifError(err); + assert.equal(2, doc.age); + done(); + }) + }) + + it('count', function(done){ + var m = mquery(col).count({ name: 'exec' }); + m.exec(function (err, count) { + assert.ifError(err); + assert.equal(2, count); + done(); + }) + }) + + it('distinct', function(done){ + var m = mquery({ name: 'exec' }); + m.collection(col); + m.distinct('age'); + m.exec(function (err, array) { + assert.ifError(err); + assert.ok(Array.isArray(array)); + assert.equal(2, array.length); + assert.equal(1, array[0]); + assert.equal(2, array[1]); + done(); + }); + }) + + describe('update', function(){ + var num; + + it('with a callback', function(done){ + var m = mquery(col); + m.where({ name: 'exec' }) + + m.count(function (err, _num) { + assert.ifError(err); + num = _num; + m.setOptions({ multi: true }) + m.update({ name: 'exec + update' }); + m.exec(function (err, res) { + assert.ifError(err); + assert.equal(num, res); + mquery(col).find({ name: 'exec + update' }, function (err, docs) { + assert.ifError(err); + assert.equal(num, docs.length); + done(); + }) + }) + }) + }) + + it('without a callback', function(done){ + var m = mquery(col) + m.where({ name: 'exec + update' }).setOptions({ multi: true }) + m.update({ name: 'exec' }); + + // unsafe write + m.exec(); + + setTimeout(function () { + mquery(col).find({ name: 'exec' }, function (err, docs) { + assert.ifError(err); + assert.equal(2, docs.length); + done(); + }) + }, 200) + }) + it('preserves key ordering', function(done) { + var m = mquery(col); + + var m2 = m.update({ _id : 'something' }, { '1' : 1, '2' : 2, '3' : 3}); + var doc = m2._updateForExec().$set; + var count = 0; + for (var i in doc) { + if (count == 0) { + assert.equal('1', i); + } else if (count == 1) { + assert.equal('2', i); + } else if (count ==2) { + assert.equal('3', i); + } + count++; + } + done(); + }); + }) + + describe('remove', function(){ + it('with a callback', function(done){ + var m = mquery(col).where({ age: 2 }).remove(); + m.exec(function (err, num) { + assert.ifError(err); + assert.equal(1, num); + done(); + }) + }) + + it('without a callback', function(done){ + var m = mquery(col).where({ age: 1 }).remove(); + m.exec(); + + setTimeout(function () { + mquery(col).where('name', 'exec').count(function(err, num) { + assert.equal(1, num); + done(); + }) + }, 200) + }) + }) + + describe('findOneAndUpdate', function(){ + it('with a callback', function(done){ + var m = mquery(col); + m.findOneAndUpdate({ name: 'exec', age: 1 }, { $set: { name: 'findOneAndUpdate' }}); + m.exec(function (err, doc) { + assert.ifError(err); + assert.equal('findOneAndUpdate', doc.name); + done(); + }); + }) + }) + + describe('findOneAndRemove', function(){ + it('with a callback', function(done){ + var m = mquery(col); + m.findOneAndRemove({ name: 'exec', age: 2 }); + m.exec(function (err, doc) { + assert.ifError(err); + assert.equal('exec', doc.name); + assert.equal(2, doc.age); + mquery(col).count({ name: 'exec' }, function (err, num) { + assert.ifError(err); + assert.equal(1, num); + done(); + }); + }); + }) + }) + }) + + function noDistinct (type) { + it('cannot be used with distinct()', function(done){ + assert.throws(function () { + mquery().distinct('name')[type](4); + }, new RegExp(type + ' cannot be used with distinct')); + done(); + }) + } + + function no (method, type) { + it('cannot be used with ' + method + '()', function(done){ + assert.throws(function () { + mquery()[method]()[type](4); + }, new RegExp(type + ' cannot be used with ' + method)); + done(); + }) + } + + // query internal + + describe('_updateForExec', function(){ + it('returns a clone of the update object with same key order #19', function(done){ + var update = {}; + update.$push = { n: { $each: [{x:10}], $slice: -1, $sort: {x:1}}}; + + var q = mquery().update({ x: 1 }, update); + + // capture original key order + var order = []; + for (var key in q._update.$push.n) { + order.push(key); + } + + // compare output + var doc = q._updateForExec(); + var i = 0; + for (var key in doc.$push.n) { + assert.equal(key, order[i]); + i++; + } + + done(); + }) + }) +}) diff --git a/node_modules/mongoose/node_modules/mquery/test/utils.js b/node_modules/mongoose/node_modules/mquery/test/utils.js new file mode 100644 index 0000000..c34b6e2 --- /dev/null +++ b/node_modules/mongoose/node_modules/mquery/test/utils.js @@ -0,0 +1,8 @@ + +var utils = require('../lib/utils'); + +describe('utils', function(){ + // TODO +}) + + diff --git a/node_modules/mongoose/node_modules/ms/.npmignore b/node_modules/mongoose/node_modules/ms/.npmignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/node_modules/mongoose/node_modules/ms/.npmignore @@ -0,0 +1 @@ +node_modules diff --git a/node_modules/mongoose/node_modules/ms/Makefile b/node_modules/mongoose/node_modules/ms/Makefile new file mode 100644 index 0000000..dded504 --- /dev/null +++ b/node_modules/mongoose/node_modules/ms/Makefile @@ -0,0 +1,8 @@ + +test: + ./node_modules/.bin/mocha test/test.js + +test-browser: + ./node_modules/.bin/serve test/ + +.PHONY: test diff --git a/node_modules/mongoose/node_modules/ms/README.md b/node_modules/mongoose/node_modules/ms/README.md new file mode 100644 index 0000000..c93d43f --- /dev/null +++ b/node_modules/mongoose/node_modules/ms/README.md @@ -0,0 +1,65 @@ + +# ms.js + +Ever find yourself doing math in your head or writing `1000 * 60 * 60 …`? +Don't want to add obstrusive `Number` prototype extensions to your reusable +/ distributable modules and projects? + +`ms` is a tiny utility that you can leverage when your application needs to +accept a number of miliseconds as a parameter. + +If a number is supplied to `ms`, it returns it immediately (e.g: +If a string that contains the number is supplied, it returns it immediately as +a number (e.g: it returns `100` for `'100'`). + +However, if you pass a string with a number and a valid unit, hte number of +equivalent ms is returned. + +```js +ms('1d') // 86400000 +ms('10h') // 36000000 +ms('2h') // 7200000 +ms('1m') // 60000 +ms('5ms') // 5000 +ms('100') // '100' +ms(100) // 100 +``` + +## How to use + +### Node + +```js +require('ms') +``` + +### Browser + +```html + +``` + +## Credits + +(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/node_modules/mongoose/node_modules/ms/ms.js b/node_modules/mongoose/node_modules/ms/ms.js new file mode 100644 index 0000000..b4621bc --- /dev/null +++ b/node_modules/mongoose/node_modules/ms/ms.js @@ -0,0 +1,35 @@ +/** + +# ms.js + +No more painful `setTimeout(fn, 60 * 4 * 3 * 2 * 1 * Infinity * NaN * '☃')`. + + ms('2d') // 172800000 + ms('1.5h') // 5400000 + ms('1h') // 3600000 + ms('1m') // 60000 + ms('5s') // 5000 + ms('500ms') // 500 + ms('100') // '100' + ms(100) // 100 + +**/ + +(function (g) { + var r = /(\d*.?\d+)([mshd]+)/ + , _ = {} + + _.ms = 1; + _.s = 1000; + _.m = _.s * 60; + _.h = _.m * 60; + _.d = _.h * 24; + + function ms (s) { + if (s == Number(s)) return Number(s); + r.exec(s.toLowerCase()); + return RegExp.$1 * _[RegExp.$2]; + } + + g.top ? g.ms = ms : module.exports = ms; +})(this); diff --git a/node_modules/mongoose/node_modules/ms/package.json b/node_modules/mongoose/node_modules/ms/package.json new file mode 100644 index 0000000..7935c05 --- /dev/null +++ b/node_modules/mongoose/node_modules/ms/package.json @@ -0,0 +1,19 @@ +{ + "name": "ms", + "version": "0.1.0", + "description": "Tiny ms conversion utility", + "main": "./ms", + "devDependencies": { + "mocha": "*", + "expect.js": "*", + "serve": "*" + }, + "readme": "\n# ms.js\n\nEver find yourself doing math in your head or writing `1000 * 60 * 60 …`?\nDon't want to add obstrusive `Number` prototype extensions to your reusable\n/ distributable modules and projects?\n\n`ms` is a tiny utility that you can leverage when your application needs to\naccept a number of miliseconds as a parameter.\n\nIf a number is supplied to `ms`, it returns it immediately (e.g:\nIf a string that contains the number is supplied, it returns it immediately as\na number (e.g: it returns `100` for `'100'`).\n\nHowever, if you pass a string with a number and a valid unit, hte number of\nequivalent ms is returned.\n\n```js\nms('1d') // 86400000\nms('10h') // 36000000\nms('2h') // 7200000\nms('1m') // 60000\nms('5ms') // 5000\nms('100') // '100'\nms(100) // 100\n```\n\n## How to use\n\n### Node\n\n```js\nrequire('ms')\n```\n\n### Browser\n\n```html\n\n```\n\n## Credits\n\n(The MIT License)\n\nCopyright (c) 2011 Guillermo Rauch <guillermo@learnboost.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "README.md", + "_id": "ms@0.1.0", + "dist": { + "shasum": "b9ab83f5d3dc1a5db17d2df77d7e69a63f38d0b9" + }, + "_from": "ms@0.1.0", + "_resolved": "https://registry.npmjs.org/ms/-/ms-0.1.0.tgz" +} diff --git a/node_modules/mongoose/node_modules/ms/test/index.html b/node_modules/mongoose/node_modules/ms/test/index.html new file mode 100644 index 0000000..79edc40 --- /dev/null +++ b/node_modules/mongoose/node_modules/ms/test/index.html @@ -0,0 +1,19 @@ + + + + ms.js tests + + + + + + + + + + + + +
    + + diff --git a/node_modules/mongoose/node_modules/ms/test/support/jquery.js b/node_modules/mongoose/node_modules/ms/test/support/jquery.js new file mode 100644 index 0000000..8ccd0ea --- /dev/null +++ b/node_modules/mongoose/node_modules/ms/test/support/jquery.js @@ -0,0 +1,9266 @@ +/*! + * jQuery JavaScript Library v1.7.1 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Mon Nov 21 21:11:03 2011 -0500 + */ +(function( window, undefined ) { + +// Use the correct document accordingly with window argument (sandbox) +var document = window.document, + navigator = window.navigator, + location = window.location; +var jQuery = (function() { + +// Define a local copy of jQuery +var jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // A central reference to the root jQuery(document) + rootjQuery, + + // A simple way to check for HTML strings or ID strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Matches dashed string for camelizing + rdashAlpha = /-([a-z]|[0-9])/ig, + rmsPrefix = /^-ms-/, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // The deferred used on DOM ready + readyList, + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = quickExpr.exec( selector ); + } + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = ( context ? context.ownerDocument || context : document ); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; + } + + return jQuery.merge( this, selector ); + + // HANDLE: $("#id") + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.7.1", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.add( fn ); + + return this; + }, + + eq: function( i ) { + i = +i; + return i === -1 ? + this.slice( i ) : + this.slice( i, i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.fireWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger( "ready" ).off( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyList ) { + return; + } + + readyList = jQuery.Callbacks( "once memory" ); + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + // A crude way of determining if an object is a window + isWindow: function( obj ) { + return obj && typeof obj === "object" && "setInterval" in obj; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + var xml, tmp; + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction( object ); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type( array ); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array, i ) { + var len; + + if ( array ) { + if ( indexOf ) { + return indexOf.call( array, elem, i ); + } + + len = array.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in array && array[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + if ( typeof context === "string" ) { + var tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + var args = slice.call( arguments, 2 ), + proxy = function() { + return fn.apply( context, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can optionally be executed if it's a function + access: function( elems, key, value, exec, fn, pass ) { + var length = elems.length; + + // Setting many attributes + if ( typeof key === "object" ) { + for ( var k in key ) { + jQuery.access( elems, k, key[k], exec, fn, value ); + } + return elems; + } + + // Setting one attribute + if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = !pass && exec && jQuery.isFunction(value); + + for ( var i = 0; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + + return elems; + } + + // Getting an attribute + return length ? fn( elems[0], key ) : undefined; + }, + + now: function() { + return ( new Date() ).getTime(); + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; + }, + + browser: {} +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +return jQuery; + +})(); + + +// String to Object flags format cache +var flagsCache = {}; + +// Convert String-formatted flags into Object-formatted ones and store in cache +function createFlags( flags ) { + var object = flagsCache[ flags ] = {}, + i, length; + flags = flags.split( /\s+/ ); + for ( i = 0, length = flags.length; i < length; i++ ) { + object[ flags[i] ] = true; + } + return object; +} + +/* + * Create a callback list using the following parameters: + * + * flags: an optional list of space-separated flags that will change how + * the callback list behaves + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible flags: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( flags ) { + + // Convert flags from String-formatted to Object-formatted + // (we check in cache first) + flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; + + var // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = [], + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Add one or several callbacks to the list + add = function( args ) { + var i, + length, + elem, + type, + actual; + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + // Inspect recursively + add( elem ); + } else if ( type === "function" ) { + // Add if not in unique mode and callback is not in + if ( !flags.unique || !self.has( elem ) ) { + list.push( elem ); + } + } + } + }, + // Fire callbacks + fire = function( context, args ) { + args = args || []; + memory = !flags.memory || [ context, args ]; + firing = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { + memory = true; // Mark as halted + break; + } + } + firing = false; + if ( list ) { + if ( !flags.once ) { + if ( stack && stack.length ) { + memory = stack.shift(); + self.fireWith( memory[ 0 ], memory[ 1 ] ); + } + } else if ( memory === true ) { + self.disable(); + } else { + list = []; + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + var length = list.length; + add( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away, unless previous + // firing was halted (stopOnFalse) + } else if ( memory && memory !== true ) { + firingStart = length; + fire( memory[ 0 ], memory[ 1 ] ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + var args = arguments, + argIndex = 0, + argLength = args.length; + for ( ; argIndex < argLength ; argIndex++ ) { + for ( var i = 0; i < list.length; i++ ) { + if ( args[ argIndex ] === list[ i ] ) { + // Handle firingIndex and firingLength + if ( firing ) { + if ( i <= firingLength ) { + firingLength--; + if ( i <= firingIndex ) { + firingIndex--; + } + } + } + // Remove the element + list.splice( i--, 1 ); + // If we have some unicity property then + // we only need to do this once + if ( flags.unique ) { + break; + } + } + } + } + } + return this; + }, + // Control if a given callback is in the list + has: function( fn ) { + if ( list ) { + var i = 0, + length = list.length; + for ( ; i < length; i++ ) { + if ( fn === list[ i ] ) { + return true; + } + } + } + return false; + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory || memory === true ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( stack ) { + if ( firing ) { + if ( !flags.once ) { + stack.push( [ context, args ] ); + } + } else if ( !( flags.once && memory ) ) { + fire( context, args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!memory; + } + }; + + return self; +}; + + + + +var // Static reference to slice + sliceDeferred = [].slice; + +jQuery.extend({ + + Deferred: function( func ) { + var doneList = jQuery.Callbacks( "once memory" ), + failList = jQuery.Callbacks( "once memory" ), + progressList = jQuery.Callbacks( "memory" ), + state = "pending", + lists = { + resolve: doneList, + reject: failList, + notify: progressList + }, + promise = { + done: doneList.add, + fail: failList.add, + progress: progressList.add, + + state: function() { + return state; + }, + + // Deprecated + isResolved: doneList.fired, + isRejected: failList.fired, + + then: function( doneCallbacks, failCallbacks, progressCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); + return this; + }, + always: function() { + deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); + return this; + }, + pipe: function( fnDone, fnFail, fnProgress ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ], + progress: [ fnProgress, "notify" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + obj = promise; + } else { + for ( var key in promise ) { + obj[ key ] = promise[ key ]; + } + } + return obj; + } + }, + deferred = promise.promise({}), + key; + + for ( key in lists ) { + deferred[ key ] = lists[ key ].fire; + deferred[ key + "With" ] = lists[ key ].fireWith; + } + + // Handle state + deferred.done( function() { + state = "resolved"; + }, failList.disable, progressList.lock ).fail( function() { + state = "rejected"; + }, doneList.disable, progressList.lock ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = sliceDeferred.call( arguments, 0 ), + i = 0, + length = args.length, + pValues = new Array( length ), + count = length, + pCount = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(), + promise = deferred.promise(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + deferred.resolveWith( deferred, args ); + } + }; + } + function progressFunc( i ) { + return function( value ) { + pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + deferred.notifyWith( promise, pValues ); + }; + } + if ( length > 1 ) { + for ( ; i < length; i++ ) { + if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return promise; + } +}); + + + + +jQuery.support = (function() { + + var support, + all, + a, + select, + opt, + input, + marginDiv, + fragment, + tds, + events, + eventName, + i, + isSupported, + div = document.createElement( "div" ), + documentElement = document.documentElement; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = "
    a"; + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return {}; + } + + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute("href") === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Tests for enctype support on a form(#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true + }; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent( "onclick" ); + } + + // Check if a radio maintains its value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; + + input.setAttribute("checked", "checked"); + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.lastChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + fragment.removeChild( input ); + fragment.appendChild( div ); + + div.innerHTML = ""; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( window.getComputedStyle ) { + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.style.width = "2px"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + // Technique from Juriy Zaytsev + // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for( i in { + submit: 1, + change: 1, + focusin: 1 + }) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + fragment.removeChild( div ); + + // Null elements to avoid leaks in IE + fragment = select = opt = marginDiv = div = input = null; + + // Run tests that need a body at doc ready + jQuery(function() { + var container, outer, inner, table, td, offsetSupport, + conMarginTop, ptlm, vb, style, html, + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + conMarginTop = 1; + ptlm = "position:absolute;top:0;left:0;width:1px;height:1px;margin:0;"; + vb = "visibility:hidden;border:0;"; + style = "style='" + ptlm + "border:5px solid #000;padding:0;'"; + html = "
    " + + "" + + "
    "; + + container = document.createElement("div"); + container.style.cssText = vb + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; + body.insertBefore( container, body.firstChild ); + + // Construct the test element + div = document.createElement("div"); + container.appendChild( div ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + div.innerHTML = "
    t
    "; + tds = div.getElementsByTagName( "td" ); + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE <= 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Figure out if the W3C box model works as expected + div.innerHTML = ""; + div.style.width = div.style.paddingLeft = "1px"; + jQuery.boxModel = support.boxModel = div.offsetWidth === 2; + + if ( typeof div.style.zoom !== "undefined" ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "
    "; + support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); + } + + div.style.cssText = ptlm + vb; + div.innerHTML = html; + + outer = div.firstChild; + inner = outer.firstChild; + td = outer.nextSibling.firstChild.firstChild; + + offsetSupport = { + doesNotAddBorder: ( inner.offsetTop !== 5 ), + doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) + }; + + inner.style.position = "fixed"; + inner.style.top = "20px"; + + // safari subtracts parent border width here which is 5px + offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); + inner.style.position = inner.style.top = ""; + + outer.style.overflow = "hidden"; + outer.style.position = "relative"; + + offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); + offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); + + body.removeChild( container ); + div = container = null; + + jQuery.extend( support, offsetSupport ); + }); + + return support; +})(); + + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([A-Z])/g; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var privateCache, thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey, + isEvents = name === "events"; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ internalKey ] = id = ++jQuery.uuid; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + privateCache = thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Users should not attempt to inspect the internal events object using jQuery.data, + // it is undocumented and subject to change. But does anyone listen? No. + if ( isEvents && !thisCache[ name ] ) { + return privateCache.events; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, l, + + // Reference to internal data cache key + internalKey = jQuery.expando, + + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + id = isNode ? elem[ internalKey ] : internalKey; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split( " " ); + } + } + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject(cache[ id ]) ) { + return; + } + } + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + // Ensure that `cache` is not a window object #10080 + if ( jQuery.support.deleteExpando || !cache.setInterval ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the cache and need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + if ( isNode ) { + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( jQuery.support.deleteExpando ) { + delete elem[ internalKey ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( internalKey ); + } else { + elem[ internalKey ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var parts, attr, name, + data = null; + + if ( typeof key === "undefined" ) { + if ( this.length ) { + data = jQuery.data( this[0] ); + + if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) { + attr = this[0].attributes; + for ( var i = 0, l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( this[0], name, data[ name ] ); + } + } + jQuery._data( this[0], "parsedAttrs", true ); + } + } + + return data; + + } else if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + // Try to fetch any internally stored data first + if ( data === undefined && this.length ) { + data = jQuery.data( this[0], key ); + data = dataAttr( this[0], key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + + } else { + return this.each(function() { + var self = jQuery( this ), + args = [ parts[0], value ]; + + self.triggerHandler( "setData" + parts[1] + "!", args ); + jQuery.data( this, key, value ); + self.triggerHandler( "changeData" + parts[1] + "!", args ); + }); + } + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + jQuery.isNumeric( data ) ? parseFloat( data ) : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + for ( var name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + + + + +function handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery._data( elem, deferDataKey ); + if ( defer && + ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && + ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery._data( elem, queueDataKey ) && + !jQuery._data( elem, markDataKey ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.fire(); + } + }, 0 ); + } +} + +jQuery.extend({ + + _mark: function( elem, type ) { + if ( elem ) { + type = ( type || "fx" ) + "mark"; + jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); + } + }, + + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); + if ( count ) { + jQuery._data( elem, key, count ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } + } + }, + + queue: function( elem, type, data ) { + var q; + if ( elem ) { + type = ( type || "fx" ) + "queue"; + q = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + q.push( data ); + } + } + return q || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(), + hooks = {}; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + jQuery._data( elem, type + ".run", hooks ); + fn.call( elem, function() { + jQuery.dequeue( elem, type ); + }, hooks ); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue " + type + ".run", true ); + handleQueueMarkDefer( elem, type, "queue" ); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + } + + if ( data === undefined ) { + return jQuery.queue( this[0], type ); + } + return this.each(function() { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { + count++; + tmp.add( resolve ); + } + } + resolve(); + return defer.promise(); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspace = /\s+/, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + nodeHook, boolHook, fixSpecified; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.attr ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.prop ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classNames, i, l, elem, className, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + classNames = ( value || "" ).split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + className = (" " + elem.className + " ").replace( rclass, " " ); + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[ c ] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var self = jQuery(this), val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, i, max, option, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + i = one ? index : 0; + max = one ? index + 1 : options.length; + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, "" + value ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var propName, attrNames, name, l, + i = 0; + + if ( value && elem.nodeType === 1 ) { + attrNames = value.toLowerCase().split( rspace ); + l = attrNames.length; + + for ( ; i < l; i++ ) { + name = attrNames[ i ]; + + if ( name ) { + propName = jQuery.propFix[ name ] || name; + + // See #9699 for explanation of this approach (setting first, then removal) + jQuery.attr( elem, name, "" ); + elem.removeAttribute( getSetAttribute ? name : propName ); + + // Set corresponding property to false for boolean attributes + if ( rboolean.test( name ) && propName in elem ) { + elem[ propName ] = false; + } + } + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) +jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode, + property = jQuery.prop( elem, name ); + return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + fixSpecified = { + name: true, + id: true + }; + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return ( ret.nodeValue = value + "" ); + } + }; + + // Apply the nodeHook to tabindex + jQuery.attrHooks.tabindex.set = nodeHook.set; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + if ( value === "" ) { + value = "false"; + } + nodeHook.set( elem, value, name ); + } + }; +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = "" + value ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); + + + + +var rformElems = /^(?:textarea|input|select)$/i, + rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, + rhoverHack = /\bhover(\.\S+)?\b/, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, + quickParse = function( selector ) { + var quick = rquickIs.exec( selector ); + if ( quick ) { + // 0 1 2 3 + // [ _, tag, id, class ] + quick[1] = ( quick[1] || "" ).toLowerCase(); + quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); + } + return quick; + }, + quickIs = function( elem, m ) { + var attrs = elem.attributes || {}; + return ( + (!m[1] || elem.nodeName.toLowerCase() === m[1]) && + (!m[2] || (attrs.id || {}).value === m[2]) && + (!m[3] || m[3].test( (attrs[ "class" ] || {}).value )) + ); + }, + hoverHack = function( events ) { + return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); + }; + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + add: function( elem, types, handler, data, selector ) { + + var elemData, eventHandle, events, + t, tns, type, namespaces, handleObj, + handleObjIn, quick, handlers, special; + + // Don't attach events to noData or text/comment nodes (allow plain objects tho) + if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + events = elemData.events; + if ( !events ) { + elemData.events = events = {}; + } + eventHandle = elemData.handle; + if ( !eventHandle ) { + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = jQuery.trim( hoverHack(types) ).split( " " ); + for ( t = 0; t < types.length; t++ ) { + + tns = rtypenamespace.exec( types[t] ) || []; + type = tns[1]; + namespaces = ( tns[2] || "" ).split( "." ).sort(); + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: tns[1], + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + quick: quickParse( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + handlers = events[ type ]; + if ( !handlers ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + t, tns, type, origType, namespaces, origCount, + j, events, special, handle, eventType, handleObj; + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = jQuery.trim( hoverHack( types || "" ) ).split(" "); + for ( t = 0; t < types.length; t++ ) { + tns = rtypenamespace.exec( types[t] ) || []; + type = origType = tns[1]; + namespaces = tns[2]; + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector? special.delegateType : special.bindType ) || type; + eventType = events[ type ] || []; + origCount = eventType.length; + namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + + // Remove matching events + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !namespaces || namespaces.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + eventType.splice( j--, 1 ); + + if ( handleObj.selector ) { + eventType.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( eventType.length === 0 && origCount !== eventType.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery.removeData( elem, [ "events", "handle" ], true ); + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Don't do events on text and comment nodes + if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { + return; + } + + // Event object or event type + var type = event.type || event, + namespaces = [], + cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "!" ) >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf( "." ) >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.isTrigger = true; + event.exclusive = exclusive; + event.namespace = namespaces.join( "." ); + event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; + + // Handle a global trigger + if ( !elem ) { + + // TODO: Stop taunting the data cache; remove global events and always attach to document + cache = jQuery.cache; + for ( i in cache ) { + if ( cache[ i ].events && cache[ i ].events[ type ] ) { + jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); + } + } + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + eventPath = [[ elem, special.bindType || type ]]; + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; + old = null; + for ( ; cur; cur = cur.parentNode ) { + eventPath.push([ cur, bubbleType ]); + old = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( old && old === elem.ownerDocument ) { + eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); + } + } + + // Fire handlers on the event path + for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { + + cur = eventPath[i][0]; + event.type = eventPath[i][1]; + + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + // Note that this is a bare JS function and not a jQuery handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + // IE<9 dies on focus/blur to hidden element (#1486) + if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( old ) { + elem[ ontype ] = old; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event || window.event ); + + var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), + delegateCount = handlers.delegateCount, + args = [].slice.call( arguments, 0 ), + run_all = !event.exclusive && !event.namespace, + handlerQueue = [], + i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Determine handlers that should run if there are delegated events + // Avoid disabled elements in IE (#6911) and non-left-click bubbling in Firefox (#3861) + if ( delegateCount && !event.target.disabled && !(event.button && event.type === "click") ) { + + // Pregenerate a single jQuery object for reuse with .is() + jqcur = jQuery(this); + jqcur.context = this.ownerDocument || this; + + for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { + selMatch = {}; + matches = []; + jqcur[0] = cur; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + sel = handleObj.selector; + + if ( selMatch[ sel ] === undefined ) { + selMatch[ sel ] = ( + handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel ) + ); + } + if ( selMatch[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, matches: matches }); + } + } + } + + // Add the remaining (directly-bound) handlers + if ( handlers.length > delegateCount ) { + handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); + } + + // Run delegates first; they may want to stop propagation beneath us + for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { + matched = handlerQueue[ i ]; + event.currentTarget = matched.elem; + + for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { + handleObj = matched.matches[ j ]; + + // Triggered event must either 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { + + event.data = handleObj.data; + event.handleObj = handleObj; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + return event.result; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** + props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, + originalEvent = event, + fixHook = jQuery.event.fixHooks[ event.type ] || {}, + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = jQuery.Event( originalEvent ); + + for ( i = copy.length; i; ) { + prop = copy[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Target should not be a text node (#504, Safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) + if ( event.metaKey === undefined ) { + event.metaKey = event.ctrlKey; + } + + return fixHook.filter? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady + }, + + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + + focus: { + delegateType: "focusin" + }, + blur: { + delegateType: "focusout" + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +// Some plugins are using, but it's undocumented/deprecated and will be removed. +// The 1.7 special event interface should provide all the hooks needed now. +jQuery.event.handle = jQuery.event.dispatch; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var target = this, + related = event.relatedTarget, + handleObj = event.handleObj, + selector = handleObj.selector, + ret; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !form._submit_attached ) { + jQuery.event.add( form, "submit._submit", function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + }); + form._submit_attached = true; + } + }); + // return undefined since we don't need an event listener + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + jQuery.event.simulate( "change", this, event, true ); + } + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + elem._change_attached = true; + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on.call( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + var handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace? handleObj.type + "." + handleObj.namespace : handleObj.type, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( var type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + live: function( types, data, fn ) { + jQuery( this.context ).on( types, this.selector, data, fn ); + return this; + }, + die: function( types, fn ) { + jQuery( this.context ).off( types, this.selector || "**", fn ); + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.on( name, null, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } + + if ( rkeyEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; + } + + if ( rmouseEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; + } +}); + + + +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + expando = "sizcache" + (Math.random() + '').replace('.', ''), + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true, + rBackslash = /\\/g, + rReturn = /\r\n/g, + rNonWord = /\W/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function() { + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function( selector, context, results, seed ) { + results = results || []; + context = context || document; + + var origContext = context; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var m, set, checkSet, extra, ret, cur, pop, i, + prune = true, + contextXML = Sizzle.isXML( context ), + parts = [], + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + do { + chunker.exec( "" ); + m = chunker.exec( soFar ); + + if ( m ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + } while ( m ); + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context, seed ); + + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set, seed ); + } + } + + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + + ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? + Sizzle.filter( ret.expr, ret.set )[0] : + ret.set[0]; + } + + if ( context ) { + ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + + set = ret.expr ? + Sizzle.filter( ret.expr, ret.set ) : + ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray( set ); + + } else { + prune = false; + } + + while ( parts.length ) { + cur = parts.pop(); + pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + + } else if ( context && context.nodeType === 1 ) { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + + } else { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function( results ) { + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[ i - 1 ] ) { + results.splice( i--, 1 ); + } + } + } + } + + return results; +}; + +Sizzle.matches = function( expr, set ) { + return Sizzle( expr, null, null, set ); +}; + +Sizzle.matchesSelector = function( node, expr ) { + return Sizzle( expr, null, null, [node] ).length > 0; +}; + +Sizzle.find = function( expr, context, isXML ) { + var set, i, len, match, type, left; + + if ( !expr ) { + return []; + } + + for ( i = 0, len = Expr.order.length; i < len; i++ ) { + type = Expr.order[i]; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + left = match[1]; + match.splice( 1, 1 ); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace( rBackslash, "" ); + set = Expr.find[ type ]( match, context, isXML ); + + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( "*" ) : + []; + } + + return { set: set, expr: expr }; +}; + +Sizzle.filter = function( expr, set, inplace, not ) { + var match, anyFound, + type, found, item, filter, left, + i, pass, + old = expr, + result = [], + curLoop = set, + isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); + + while ( expr && set.length ) { + for ( type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + filter = Expr.filter[ type ]; + left = match[1]; + + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + pass = not ^ found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + + } else { + curLoop[i] = false; + } + + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Utility function for retreiving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +var getText = Sizzle.getText = function( elem ) { + var i, node, + nodeType = elem.nodeType, + ret = ""; + + if ( nodeType ) { + if ( nodeType === 1 || nodeType === 9 ) { + // Use textContent || innerText for elements + if ( typeof elem.textContent === 'string' ) { + return elem.textContent; + } else if ( typeof elem.innerText === 'string' ) { + // Replace IE's carriage returns + return elem.innerText.replace( rReturn, '' ); + } else { + // Traverse it's children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + } else { + + // If no nodeType, this is expected to be an array + for ( i = 0; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + if ( node.nodeType !== 8 ) { + ret += getText( node ); + } + } + } + return ret; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + + match: { + ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + + leftMatch: {}, + + attrMap: { + "class": "className", + "for": "htmlFor" + }, + + attrHandle: { + href: function( elem ) { + return elem.getAttribute( "href" ); + }, + type: function( elem ) { + return elem.getAttribute( "type" ); + } + }, + + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !rNonWord.test( part ), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + + ">": function( checkSet, part ) { + var elem, + isPartStr = typeof part === "string", + i = 0, + l = checkSet.length; + + if ( isPartStr && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + + } else { + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + + "": function(checkSet, part, isXML){ + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); + }, + + "~": function( checkSet, part, isXML ) { + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); + } + }, + + find: { + ID: function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }, + + NAME: function( match, context ) { + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], + results = context.getElementsByName( match[1] ); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + + TAG: function( match, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( match[1] ); + } + } + }, + preFilter: { + CLASS: function( match, curLoop, inplace, result, not, isXML ) { + match = " " + match[1].replace( rBackslash, "" ) + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + + ID: function( match ) { + return match[1].replace( rBackslash, "" ); + }, + + TAG: function( match, curLoop ) { + return match[1].replace( rBackslash, "" ).toLowerCase(); + }, + + CHILD: function( match ) { + if ( match[1] === "nth" ) { + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + match[2] = match[2].replace(/^\+|\s*/g, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + + ATTR: function( match, curLoop, inplace, result, not, isXML ) { + var name = match[1] = match[1].replace( rBackslash, "" ); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + // Handle if an un-quoted value was used + match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + + PSEUDO: function( match, curLoop, inplace, result, not ) { + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + + if ( !inplace ) { + result.push.apply( result, ret ); + } + + return false; + } + + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + + POS: function( match ) { + match.unshift( true ); + + return match; + } + }, + + filters: { + enabled: function( elem ) { + return elem.disabled === false && elem.type !== "hidden"; + }, + + disabled: function( elem ) { + return elem.disabled === true; + }, + + checked: function( elem ) { + return elem.checked === true; + }, + + selected: function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + parent: function( elem ) { + return !!elem.firstChild; + }, + + empty: function( elem ) { + return !elem.firstChild; + }, + + has: function( elem, i, match ) { + return !!Sizzle( match[3], elem ).length; + }, + + header: function( elem ) { + return (/h\d/i).test( elem.nodeName ); + }, + + text: function( elem ) { + var attr = elem.getAttribute( "type" ), type = elem.type; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); + }, + + radio: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; + }, + + checkbox: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; + }, + + file: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; + }, + + password: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; + }, + + submit: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; + }, + + image: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; + }, + + reset: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; + }, + + button: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; + } + }, + setFilters: { + first: function( elem, i ) { + return i === 0; + }, + + last: function( elem, i, match, array ) { + return i === array.length - 1; + }, + + even: function( elem, i ) { + return i % 2 === 0; + }, + + odd: function( elem, i ) { + return i % 2 === 1; + }, + + lt: function( elem, i, match ) { + return i < match[3] - 0; + }, + + gt: function( elem, i, match ) { + return i > match[3] - 0; + }, + + nth: function( elem, i, match ) { + return match[3] - 0 === i; + }, + + eq: function( elem, i, match ) { + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function( elem, match, i, array ) { + var name = match[1], + filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; + + } else if ( name === "not" ) { + var not = match[3]; + + for ( var j = 0, l = not.length; j < l; j++ ) { + if ( not[j] === elem ) { + return false; + } + } + + return true; + + } else { + Sizzle.error( name ); + } + }, + + CHILD: function( elem, match ) { + var first, last, + doneName, parent, cache, + count, diff, + type = match[1], + node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + + case "nth": + first = match[2]; + last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + doneName = match[0]; + parent = elem.parentNode; + + if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { + count = 0; + + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + + parent[ expando ] = doneName; + } + + diff = elem.nodeIndex - last; + + if ( first === 0 ) { + return diff === 0; + + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + + ID: function( elem, match ) { + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + + TAG: function( elem, match ) { + return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; + }, + + CLASS: function( elem, match ) { + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + + ATTR: function( elem, match ) { + var name = match[1], + result = Sizzle.attr ? + Sizzle.attr( elem, name ) : + Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + !type && Sizzle.attr ? + result != null : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + + POS: function( elem, match, i, array ) { + var name = match[2], + filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS, + fescape = function(all, num){ + return "\\" + (num - 0 + 1); + }; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); +} + +var makeArray = function( array, results ) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch( e ) { + makeArray = function( array, results ) { + var i = 0, + ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + + } else { + if ( typeof array.length === "number" ) { + for ( var l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + + } else { + for ( ; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder, siblingCheck; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + return a.compareDocumentPosition ? -1 : 1; + } + + return a.compareDocumentPosition(b) & 4 ? -1 : 1; + }; + +} else { + sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + + siblingCheck = function( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; + }; +} + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + + return m ? + m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? + [m] : + undefined : + []; + } + }; + + Expr.filter.ID = function( elem, match ) { + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

    "; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id === match[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + var oldContext = context, + old = context.getAttribute( "id" ), + nid = old || id, + hasParent = context.parentNode, + relativeHierarchySelector = /^\s*[+~]/.test( query ); + + if ( !old ) { + context.setAttribute( "id", nid ); + } else { + nid = nid.replace( /'/g, "\\$&" ); + } + if ( relativeHierarchySelector && hasParent ) { + context = context.parentNode; + } + + try { + if ( !relativeHierarchySelector || hasParent ) { + return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); + } + + } catch(pseudoError) { + } finally { + if ( !old ) { + oldContext.removeAttribute( "id" ); + } + } + } + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; + + if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
    "; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function( match, context, isXML ) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + // release memory in IE + div = null; +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem[ expando ] === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem[ expando ] = doneName; + elem.sizset = i; + } + + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +if ( document.documentElement.contains ) { + Sizzle.contains = function( a, b ) { + return a !== b && (a.contains ? a.contains(b) : true); + }; + +} else if ( document.documentElement.compareDocumentPosition ) { + Sizzle.contains = function( a, b ) { + return !!(a.compareDocumentPosition(b) & 16); + }; + +} else { + Sizzle.contains = function() { + return false; + }; +} + +Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function( selector, context, seed ) { + var match, + tmpSet = [], + later = "", + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet, seed ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +Sizzle.selectors.attrMap = {}; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.POS, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var self = this, + i, l; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + var ret = this.pushStack( "", "find", selector ), + length, n, r; + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + POS.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + // Array (deprecated as of jQuery 1.7) + if ( jQuery.isArray( selectors ) ) { + var level = 1; + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( i = 0; i < selectors.length; i++ ) { + + if ( jQuery( cur ).is( selectors[ i ] ) ) { + ret.push({ selector: selectors[ i ], elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + + return ret; + } + + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( elem.parentNode.firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, slice.call( arguments ).join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} + + + + +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /", "" ], + legend: [ 1, "
    ", "
    " ], + thead: [ 1, "", "
    " ], + tr: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + col: [ 2, "", "
    " ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }, + safeFragment = createSafeFragment( document ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and + diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/README.md b/node_modules/nib/node_modules/stylus/node_modules/sax/README.md new file mode 100644 index 0000000..c965242 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/README.md @@ -0,0 +1,216 @@ +# sax js + +A sax-style parser for XML and HTML. + +Designed with [node](http://nodejs.org/) in mind, but should work fine in +the browser or other CommonJS implementations. + +## What This Is + +* A very simple tool to parse through an XML string. +* A stepping stone to a streaming HTML parser. +* A handy way to deal with RSS and other mostly-ok-but-kinda-broken XML + docs. + +## What This Is (probably) Not + +* An HTML Parser - That's a fine goal, but this isn't it. It's just + XML. +* A DOM Builder - You can use it to build an object model out of XML, + but it doesn't do that out of the box. +* XSLT - No DOM = no querying. +* 100% Compliant with (some other SAX implementation) - Most SAX + implementations are in Java and do a lot more than this does. +* An XML Validator - It does a little validation when in strict mode, but + not much. +* A Schema-Aware XSD Thing - Schemas are an exercise in fetishistic + masochism. +* A DTD-aware Thing - Fetching DTDs is a much bigger job. + +## Regarding `Hello, world!').close(); + + // stream usage + // takes the same options as the parser + var saxStream = require("sax").createStream(strict, options) + saxStream.on("error", function (e) { + // unhandled errors will throw, since this is a proper node + // event emitter. + console.error("error!", e) + // clear the error + this._parser.error = null + this._parser.resume() + }) + saxStream.on("opentag", function (node) { + // same object as above + }) + // pipe is supported, and it's readable/writable + // same chunks coming in also go out. + fs.createReadStream("file.xml") + .pipe(saxStream) + .pipe(fs.createWriteStream("file-copy.xml")) + + + +## Arguments + +Pass the following arguments to the parser function. All are optional. + +`strict` - Boolean. Whether or not to be a jerk. Default: `false`. + +`opt` - Object bag of settings regarding string formatting. All default to `false`. + +Settings supported: + +* `trim` - Boolean. Whether or not to trim text and comment nodes. +* `normalize` - Boolean. If true, then turn any whitespace into a single + space. +* `lowercase` - Boolean. If true, then lowercase tag names and attribute names + in loose mode, rather than uppercasing them. +* `xmlns` - Boolean. If true, then namespaces are supported. +* `position` - Boolean. If false, then don't track line/col/position. + +## Methods + +`write` - Write bytes onto the stream. You don't have to do this all at +once. You can keep writing as much as you want. + +`close` - Close the stream. Once closed, no more data may be written until +it is done processing the buffer, which is signaled by the `end` event. + +`resume` - To gracefully handle errors, assign a listener to the `error` +event. Then, when the error is taken care of, you can call `resume` to +continue parsing. Otherwise, the parser will not continue while in an error +state. + +## Members + +At all times, the parser object will have the following members: + +`line`, `column`, `position` - Indications of the position in the XML +document where the parser currently is looking. + +`startTagPosition` - Indicates the position where the current tag starts. + +`closed` - Boolean indicating whether or not the parser can be written to. +If it's `true`, then wait for the `ready` event to write again. + +`strict` - Boolean indicating whether or not the parser is a jerk. + +`opt` - Any options passed into the constructor. + +`tag` - The current tag being dealt with. + +And a bunch of other stuff that you probably shouldn't touch. + +## Events + +All events emit with a single argument. To listen to an event, assign a +function to `on`. Functions get executed in the this-context of +the parser object. The list of supported events are also in the exported +`EVENTS` array. + +When using the stream interface, assign handlers using the EventEmitter +`on` function in the normal fashion. + +`error` - Indication that something bad happened. The error will be hanging +out on `parser.error`, and must be deleted before parsing can continue. By +listening to this event, you can keep an eye on that kind of stuff. Note: +this happens *much* more in strict mode. Argument: instance of `Error`. + +`text` - Text node. Argument: string of text. + +`doctype` - The ``. Argument: +object with `name` and `body` members. Attributes are not parsed, as +processing instructions have implementation dependent semantics. + +`sgmldeclaration` - Random SGML declarations. Stuff like `` +would trigger this kind of event. This is a weird thing to support, so it +might go away at some point. SAX isn't intended to be used to parse SGML, +after all. + +`opentag` - An opening tag. Argument: object with `name` and `attributes`. +In non-strict mode, tag names are uppercased, unless the `lowercase` +option is set. If the `xmlns` option is set, then it will contain +namespace binding information on the `ns` member, and will have a +`local`, `prefix`, and `uri` member. + +`closetag` - A closing tag. In loose mode, tags are auto-closed if their +parent closes. In strict mode, well-formedness is enforced. Note that +self-closing tags will have `closeTag` emitted immediately after `openTag`. +Argument: tag name. + +`attribute` - An attribute node. Argument: object with `name` and `value`. +In non-strict mode, attribute names are uppercased, unless the `lowercase` +option is set. If the `xmlns` option is set, it will also contains namespace +information. + +`comment` - A comment node. Argument: the string of the comment. + +`opencdata` - The opening tag of a ``) of a `` tags trigger a `"script"` +event, and their contents are not checked for special xml characters. +If you pass `noscript: true`, then this behavior is suppressed. + +## Reporting Problems + +It's best to write a failing test if you find an issue. I will always +accept pull requests with failing tests if they demonstrate intended +behavior, but it is very hard to figure out what issue you're describing +without a test. Writing a test is also the best way for you yourself +to figure out if you really understand the issue you think you have with +sax-js. diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/component.json b/node_modules/nib/node_modules/stylus/node_modules/sax/component.json new file mode 100644 index 0000000..96b5d73 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/component.json @@ -0,0 +1,12 @@ +{ + "name": "sax", + "description": "An evented streaming XML parser in JavaScript", + "author": "Isaac Z. Schlueter (http://blog.izs.me/)", + "version": "0.5.2", + "main": "lib/sax.js", + "license": "BSD", + "scripts": [ + "lib/sax.js" + ], + "repository": "git://github.com/isaacs/sax-js.git" +} diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/examples/big-not-pretty.xml b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/big-not-pretty.xml new file mode 100644 index 0000000..fb5265d --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/big-not-pretty.xml @@ -0,0 +1,8002 @@ + + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/examples/example.js b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/example.js new file mode 100644 index 0000000..7b0246e --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/example.js @@ -0,0 +1,29 @@ + +var fs = require("fs"), + util = require("util"), + path = require("path"), + xml = fs.readFileSync(path.join(__dirname, "test.xml"), "utf8"), + sax = require("../lib/sax"), + strict = sax.parser(true), + loose = sax.parser(false, {trim:true}), + inspector = function (ev) { return function (data) { + console.error("%s %s %j", this.line+":"+this.column, ev, data); + }}; + +sax.EVENTS.forEach(function (ev) { + loose["on"+ev] = inspector(ev); +}); +loose.onend = function () { + console.error("end"); + console.error(loose); +}; + +// do this in random bits at a time to verify that it works. +(function () { + if (xml) { + var c = Math.ceil(Math.random() * 1000) + loose.write(xml.substr(0,c)); + xml = xml.substr(c); + process.nextTick(arguments.callee); + } else loose.close(); +})(); diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/examples/get-products.js b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/get-products.js new file mode 100644 index 0000000..9e8d74a --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/get-products.js @@ -0,0 +1,58 @@ +// pull out /GeneralSearchResponse/categories/category/items/product tags +// the rest we don't care about. + +var sax = require("../lib/sax.js") +var fs = require("fs") +var path = require("path") +var xmlFile = path.resolve(__dirname, "shopping.xml") +var util = require("util") +var http = require("http") + +fs.readFile(xmlFile, function (er, d) { + http.createServer(function (req, res) { + if (er) throw er + var xmlstr = d.toString("utf8") + + var parser = sax.parser(true) + var products = [] + var product = null + var currentTag = null + + parser.onclosetag = function (tagName) { + if (tagName === "product") { + products.push(product) + currentTag = product = null + return + } + if (currentTag && currentTag.parent) { + var p = currentTag.parent + delete currentTag.parent + currentTag = p + } + } + + parser.onopentag = function (tag) { + if (tag.name !== "product" && !product) return + if (tag.name === "product") { + product = tag + } + tag.parent = currentTag + tag.children = [] + tag.parent && tag.parent.children.push(tag) + currentTag = tag + } + + parser.ontext = function (text) { + if (currentTag) currentTag.children.push(text) + } + + parser.onend = function () { + var out = util.inspect(products, false, 3, true) + res.writeHead(200, {"content-type":"application/json"}) + res.end("{\"ok\":true}") + // res.end(JSON.stringify(products)) + } + + parser.write(xmlstr).end() + }).listen(1337) +}) diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/examples/hello-world.js b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/hello-world.js new file mode 100644 index 0000000..cbfa518 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/hello-world.js @@ -0,0 +1,4 @@ +require("http").createServer(function (req, res) { + res.writeHead(200, {"content-type":"application/json"}) + res.end(JSON.stringify({ok: true})) +}).listen(1337) diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/examples/not-pretty.xml b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/not-pretty.xml new file mode 100644 index 0000000..9592852 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/not-pretty.xml @@ -0,0 +1,8 @@ + + something blerm a bit down here diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/examples/pretty-print.js b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/pretty-print.js new file mode 100644 index 0000000..cd6aca9 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/pretty-print.js @@ -0,0 +1,74 @@ +var sax = require("../lib/sax") + , printer = sax.createStream(false, {lowercasetags:true, trim:true}) + , fs = require("fs") + +function entity (str) { + return str.replace('"', '"') +} + +printer.tabstop = 2 +printer.level = 0 +printer.indent = function () { + print("\n") + for (var i = this.level; i > 0; i --) { + for (var j = this.tabstop; j > 0; j --) { + print(" ") + } + } +} +printer.on("opentag", function (tag) { + this.indent() + this.level ++ + print("<"+tag.name) + for (var i in tag.attributes) { + print(" "+i+"=\""+entity(tag.attributes[i])+"\"") + } + print(">") +}) + +printer.on("text", ontext) +printer.on("doctype", ontext) +function ontext (text) { + this.indent() + print(text) +} + +printer.on("closetag", function (tag) { + this.level -- + this.indent() + print("") +}) + +printer.on("cdata", function (data) { + this.indent() + print("") +}) + +printer.on("comment", function (comment) { + this.indent() + print("") +}) + +printer.on("error", function (error) { + console.error(error) + throw error +}) + +if (!process.argv[2]) { + throw new Error("Please provide an xml file to prettify\n"+ + "TODO: read from stdin or take a file") +} +var xmlfile = require("path").join(process.cwd(), process.argv[2]) +var fstr = fs.createReadStream(xmlfile, { encoding: "utf8" }) + +function print (c) { + if (!process.stdout.write(c)) { + fstr.pause() + } +} + +process.stdout.on("drain", function () { + fstr.resume() +}) + +fstr.pipe(printer) diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/examples/shopping.xml b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/shopping.xml new file mode 100644 index 0000000..223c6c6 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/shopping.xml @@ -0,0 +1,2 @@ + +sandbox3.1 r31.Kadu4DC.phase357782011.10.06 15:37:23 PSTp2.a121bc2aaf029435dce62011-10-21T18:38:45.982-04:00P0Y0M0DT0H0M0.169S1112You are currently using the SDC API sandbox environment! No clicks to merchant URLs from this response will be paid. Please change the host of your API requests to 'publisher.api.shopping.com' when you have finished development and testinghttp://statTest.dealtime.com/pixel/noscript?PV_EvnTyp=APPV&APPV_APITSP=10%2F21%2F11_06%3A38%3A45_PM&APPV_DSPRQSID=p2.a121bc2aaf029435dce6&APPV_IMGURL=http://img.shopping.com/sc/glb/sdc_logo_106x19.gif&APPV_LI_LNKINID=7000610&APPV_LI_SBMKYW=nikon&APPV_MTCTYP=1000&APPV_PRTID=2002&APPV_BrnID=14804http://www.shopping.com/digital-cameras/productsDigital CamerasDigital CamerasElectronicshttp://www.shopping.com/xCH-electronics-nikon~linkin_id-7000610?oq=nikonCameras and Photographyhttp://www.shopping.com/xCH-cameras_and_photography-nikon~linkin_id-7000610?oq=nikonDigital Camerashttp://www.shopping.com/digital-cameras/nikon/products?oq=nikon&linkin_id=7000610nikonnikonDigital Camerashttp://www.shopping.com/digital-cameras/nikon/products?oq=nikon&linkin_id=7000610Nikon D3100 Digital Camera14.2 Megapixel, SLR Camera, 3 in. LCD Screen, With High Definition Video, Weight: 1 lb.The Nikon D3100 digital SLR camera speaks to the growing ranks of enthusiastic D-SLR users and aspiring photographers by providing an easy-to-use and affordable entrance to the world of Nikon D-SLR’s. The 14.2-megapixel D3100 has powerful features, such as the enhanced Guide Mode that makes it easy to unleash creative potential and capture memories with still images and full HD video. Like having a personal photo tutor at your fingertips, this unique feature provides a simple graphical interface on the camera’s LCD that guides users by suggesting and/or adjusting camera settings to achieve the desired end result images. The D3100 is also the world’s first D-SLR to introduce full time auto focus (AF) in Live View and D-Movie mode to effortlessly achieve the critical focus needed when shooting Full HD 1080p video.http://di1.shopping.com/images/pi/93/bc/04/101677489-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=1http://di1.shopping.com/images/pi/93/bc/04/101677489-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=1http://di1.shopping.com/images/pi/93/bc/04/101677489-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=1http://di1.shopping.com/images/pi/93/bc/04/101677489-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=1http://di1.shopping.com/images/pi/93/bc/04/101677489-606x500-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=194.56http://img.shopping.com/sc/pr/sdc_stars_sm_4.5.gifhttp://www.shopping.com/Nikon-D3100/reviews~linkin_id-7000610429.001360.00http://www.shopping.com/Nikon-D3100/prices~linkin_id-7000610http://www.shopping.com/Nikon-D3100/info~linkin_id-7000610Nikon D3100 Digital SLR Camera with 18-55mm NIKKOR VR LensThe Nikon D3100 Digital SLR Camera is an affordable compact and lightweight photographic power-house. It features the all-purpose 18-55mm VR lens a high-resolution 14.2 MP CMOS sensor along with a feature set that's comprehensive yet easy to navigate - the intuitive onboard learn-as-you grow guide mode allows the photographer to understand what the 3100 can do quickly and easily. Capture beautiful pictures and amazing Full HD 1080p movies with sound and full-time autofocus. Availabilty: In Stock!7185Nikonhttp://di102.shopping.com/images/di/2d/5a/57/36424d5a717a366662532d61554c7767615f67-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di102.shopping.com/images/di/2d/5a/57/36424d5a717a366662532d61554c7767615f67-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di102.shopping.com/images/di/2d/5a/57/36424d5a717a366662532d61554c7767615f67-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di102.shopping.com/images/di/2d/5a/57/36424d5a717a366662532d61554c7767615f67-350x350-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1in-stockFree Shipping with Any Purchase!529.000.00799.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=647&BEFID=7185&aon=%5E1&MerchantID=475674&crawler_id=475674&dealId=-ZW6BMZqz6fbS-aULwga_g%3D%3D&url=http%3A%2F%2Fwww.fumfie.com%2Fproduct%2F343.5%2Fshopping-com%3F&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D3100+Digital+SLR+Camera+with+18-55mm+NIKKOR+VR+Lens&dlprc=529.0&crn=&istrsmrc=1&isathrsl=0&AR=1&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=101677489&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=1&cid=&semid1=&semid2=&IsLps=0&CC=1&SL=1&FS=1&code=&acode=658&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=FumFiehttp://img.shopping.com/cctool/merch_logos/475674.gif866 666 91985604.27http://img.shopping.com/sc/mr/sdc_checks_45.gifhttp://www.shopping.com/xMR-store_fumfie~MRD-475674~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUSF343C5Nikon Nikon D3100 14.2MP Digital SLR Camera with 18-55mm f/3.5-5.6 AF-S DX VR, CamerasNikon D3100 14.2MP Digital SLR Camera with 18-55mm f/3.5-5.6 AF-S DX VR7185Nikonhttp://di109.shopping.com/images/di/6d/64/31/65396c443876644f7534464851664a714b6e67-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di109.shopping.com/images/di/6d/64/31/65396c443876644f7534464851664a714b6e67-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di109.shopping.com/images/di/6d/64/31/65396c443876644f7534464851664a714b6e67-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di109.shopping.com/images/di/6d/64/31/65396c443876644f7534464851664a714b6e67-385x352-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2in-stock549.000.00549.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=779&BEFID=7185&aon=%5E1&MerchantID=305814&crawler_id=305814&dealId=md1e9lD8vdOu4FHQfJqKng%3D%3D&url=http%3A%2F%2Fwww.electronics-expo.com%2Findex.php%3Fpage%3Ditem%26id%3DNIKD3100%26source%3DSideCar%26scpid%3D8%26scid%3Dscsho318727%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+Nikon+D3100+14.2MP+Digital+SLR+Camera+with+18-55mm+f%2F3.5-5.6+AF-S+DX+VR%2C+Cameras&dlprc=549.0&crn=&istrsmrc=1&isathrsl=0&AR=9&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=101677489&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=9&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=771&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Electronics Expohttp://img.shopping.com/cctool/merch_logos/305814.gif1-888-707-EXPO3713.90http://img.shopping.com/sc/mr/sdc_checks_4.gifhttp://www.shopping.com/xMR-store_electronics_expo~MRD-305814~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUSNIKD3100Nikon D3100 14.2-Megapixel Digital SLR Camera With 18-55mm Zoom-Nikkor Lens, BlackSplit-second shutter response captures shots other cameras may have missed Helps eliminate the frustration of shutter delay! 14.2-megapixels for enlargements worth framing and hanging. Takes breathtaking 1080p HD movies. ISO sensitivity from 100-1600 for bright or dimly lit settings. 3.0in. color LCD for beautiful, wide-angle framing and viewing. In-camera image editing lets you retouch with no PC. Automatic scene modes include Child, Sports, Night Portrait and more. Accepts SDHC memory cards. Nikon D3100 14.2-Megapixel Digital SLR Camera With 18-55mm Zoom-Nikkor Lens, Black is one of many Digital SLR Cameras available through Office Depot. Made by Nikon.7185Nikonhttp://di109.shopping.com/images/di/79/59/75/61586e4446744359377244556a6b5932616177-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di109.shopping.com/images/di/79/59/75/61586e4446744359377244556a6b5932616177-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di109.shopping.com/images/di/79/59/75/61586e4446744359377244556a6b5932616177-250x250-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3in-stock549.990.00699.99http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=698&BEFID=7185&aon=%5E1&MerchantID=467671&crawler_id=467671&dealId=yYuaXnDFtCY7rDUjkY2aaw%3D%3D&url=http%3A%2F%2Flink.mercent.com%2Fredirect.ashx%3Fmr%3AmerchantID%3DOfficeDepot%26mr%3AtrackingCode%3DCEC9669E-6ABC-E011-9F24-0019B9C043EB%26mr%3AtargetUrl%3Dhttp%3A%2F%2Fwww.officedepot.com%2Fa%2Fproducts%2F486292%2FNikon-D3100-142-Megapixel-Digital-SLR%2F%253fcm_mmc%253dMercent-_-Shopping-_-Cameras_and_Camcorders-_-486292&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D3100+14.2-Megapixel+Digital+SLR+Camera+With+18-55mm+Zoom-Nikkor+Lens%2C+Black&dlprc=549.99&crn=&istrsmrc=1&isathrsl=0&AR=10&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=101677489&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=10&cid=&semid1=&semid2=&IsLps=0&CC=1&SL=1&FS=1&code=&acode=690&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Office Depothttp://img.shopping.com/cctool/merch_logos/467671.gif1-800-GO-DEPOT1352.37http://img.shopping.com/sc/mr/sdc_checks_25.gifhttp://www.shopping.com/xMR-store_office_depot_4158555~MRD-467671~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS486292Nikon® D3100™ 14.2MP Digital SLR with 18-55mm LensThe Nikon D3100 DSLR will surprise you with its simplicity and impress you with superb results.7185Nikonhttp://di103.shopping.com/images/di/52/6c/35/36553743756954597348344d475a30326c7851-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di103.shopping.com/images/di/52/6c/35/36553743756954597348344d475a30326c7851-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di103.shopping.com/images/di/52/6c/35/36553743756954597348344d475a30326c7851-220x220-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4in-stock549.996.05549.99http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=504&BEFID=7185&aon=%5E1&MerchantID=332477&crawler_id=332477&dealId=Rl56U7CuiTYsH4MGZ02lxQ%3D%3D&url=http%3A%2F%2Ftracking.searchmarketing.com%2Fgsic.asp%3Faid%3D903483107%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon%C2%AE+D3100%E2%84%A2+14.2MP+Digital+SLR+with+18-55mm+Lens&dlprc=549.99&crn=&istrsmrc=0&isathrsl=0&AR=11&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=101677489&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=11&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=0&code=&acode=496&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=RadioShackhttp://img.shopping.com/cctool/merch_logos/332477.gif242.25http://img.shopping.com/sc/mr/sdc_checks_25.gifhttp://www.shopping.com/xMR-store_radioshack_9689~MRD-332477~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS9614867Nikon D3100 SLR w/Nikon 18-55mm VR & 55-200mm VR Lenses14.2 Megapixels3" LCDLive ViewHD 1080p Video w/ Sound & Autofocus11-point Autofocus3 Frames per Second ShootingISO 100 to 3200 (Expand to 12800-Hi2)Self Cleaning SensorEXPEED 2, Image Processing EngineScene Recognition System7185Nikonhttp://di105.shopping.com/images/di/68/75/53/36785a4b444b614b4d544d5037316549364441-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di105.shopping.com/images/di/68/75/53/36785a4b444b614b4d544d5037316549364441-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di105.shopping.com/images/di/68/75/53/36785a4b444b614b4d544d5037316549364441-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di105.shopping.com/images/di/68/75/53/36785a4b444b614b4d544d5037316549364441-345x345-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5in-stock695.000.00695.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=371&BEFID=7185&aon=%5E1&MerchantID=487342&crawler_id=487342&dealId=huS6xZKDKaKMTMP71eI6DA%3D%3D&url=http%3A%2F%2Fwww.rythercamera.com%2Fcatalog%2Fproduct_info.php%3Fcsv%3Dsh%26products_id%3D32983%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D3100+SLR+w%2FNikon+18-55mm+VR+%26+55-200mm+VR+Lenses&dlprc=695.0&crn=&istrsmrc=0&isathrsl=0&AR=15&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=101677489&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=15&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=379&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=RytherCamera.comhttp://img.shopping.com/cctool/merch_logos/487342.gif1-877-644-75930http://img.shopping.com/sc/glb/flag/US.gifUS32983Nikon COOLPIX S203 Digital Camera10 Megapixel, Ultra-Compact Camera, 2.5 in. LCD Screen, 3x Optical Zoom, With Video Capability, Weight: 0.23 lb.With 10.34 mega pixel, electronic VR vibration reduction, 5-level brightness adjustment, 3x optical zoom, and TFT LCD, Nikon Coolpix s203 fulfills all the demands of any photographer. The digital camera has an inbuilt memory of 44MB and an external memory slot made for all kinds of SD (Secure Digital) cards.http://di1.shopping.com/images/pi/c4/ef/1b/95397883-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=2http://di1.shopping.com/images/pi/c4/ef/1b/95397883-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=2http://di1.shopping.com/images/pi/c4/ef/1b/95397883-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=2http://di1.shopping.com/images/pi/c4/ef/1b/95397883-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=2http://di1.shopping.com/images/pi/c4/ef/1b/95397883-500x499-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=20139.00139.00http://www.shopping.com/Nikon-Coolpix-S203/prices~linkin_id-7000610http://www.shopping.com/Nikon-Coolpix-S203/info~linkin_id-7000610Nikon Coolpix S203 Digital Camera (Red)With 10.34 mega pixel, electronic VR vibration reduction, 5-level brightness adjustment, 3x optical zoom, and TFT LCD, Nikon Coolpix s203 fulfills all the demands of any photographer. The digital camera has an inbuilt memory of 44MB and an external memory slot made for all kinds of SD (Secure Digital) cards.7185Nikonhttp://di108.shopping.com/images/di/73/42/64/324a6e4945504d2d415f6c42414d31525a6751-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di108.shopping.com/images/di/73/42/64/324a6e4945504d2d415f6c42414d31525a6751-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di108.shopping.com/images/di/73/42/64/324a6e4945504d2d415f6c42414d31525a6751-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di108.shopping.com/images/di/73/42/64/324a6e4945504d2d415f6c42414d31525a6751-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di108.shopping.com/images/di/73/42/64/324a6e4945504d2d415f6c42414d31525a6751-500x500-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1in-stockFantastic prices with ease & comfort of Amazon.com!139.009.50139.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=566&BEFID=7185&aon=%5E1&MerchantID=301531&crawler_id=1903313&dealId=sBd2JnIEPM-A_lBAM1RZgQ%3D%3D&url=http%3A%2F%2Fwww.amazon.com%2Fdp%2FB002T964IM%2Fref%3Dasc_df_B002T964IM1751618%3Fsmid%3DA22UHVNXG98FAT%26tag%3Ddealtime-ce-mp01feed-20%26linkCode%3Dasn%26creative%3D395105%26creativeASIN%3DB002T964IM&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+Coolpix+S203+Digital+Camera+%28Red%29&dlprc=139.0&crn=&istrsmrc=0&isathrsl=0&AR=63&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=95397883&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=63&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=0&code=&acode=518&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Amazon Marketplacehttp://img.shopping.com/cctool/merch_logos/301531.gif2132.73http://img.shopping.com/sc/mr/sdc_checks_25.gifhttp://www.shopping.com/xMR-store_amazon_marketplace_9689~MRD-301531~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUSB002T964IMNikon S3100 Digital Camera14.5 Megapixel, Compact Camera, 2.7 in. LCD Screen, 5x Optical Zoom, With High Definition Video, Weight: 0.23 lb.This digital camera features a wide-angle optical Zoom-NIKKOR glass lens that allows you to capture anything from landscapes to portraits to action shots. The high-definition movie mode with one-touch recording makes it easy to capture video clips.http://di1.shopping.com/images/pi/66/2d/33/106834268-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=3http://di1.shopping.com/images/pi/66/2d/33/106834268-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=3http://di1.shopping.com/images/pi/66/2d/33/106834268-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=3http://di1.shopping.com/images/pi/66/2d/33/106834268-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=3http://di1.shopping.com/images/pi/66/2d/33/106834268-507x387-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=312.00http://img.shopping.com/sc/pr/sdc_stars_sm_2.gifhttp://www.shopping.com/nikon-s3100/reviews~linkin_id-700061099.95134.95http://www.shopping.com/nikon-s3100/prices~linkin_id-7000610http://www.shopping.com/nikon-s3100/info~linkin_id-7000610CoolPix S3100 14 Megapixel Compact Digital Camera- RedNikon Coolpix S3100 - Digital camera - compact - 14.0 Mpix - optical zoom: 5 x - supported memory: SD, SDXC, SDHC - red7185Nikonhttp://di111.shopping.com/images/di/55/55/79/476f71563872302d78726b6e2d726e474e6267-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di111.shopping.com/images/di/55/55/79/476f71563872302d78726b6e2d726e474e6267-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di111.shopping.com/images/di/55/55/79/476f71563872302d78726b6e2d726e474e6267-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di111.shopping.com/images/di/55/55/79/476f71563872302d78726b6e2d726e474e6267-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1in-stockGet 30 days FREE SHIPPING w/ ShipVantage119.956.95139.95http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=578&BEFID=7185&aon=%5E1&MerchantID=485615&crawler_id=485615&dealId=UUyGoqV8r0-xrkn-rnGNbg%3D%3D&url=http%3A%2F%2Fsears.rdr.channelintelligence.com%2Fgo.asp%3FfVhzOGNRAAQIASNiE1NbQBJpFHJ3Yx0CTAICI2BbH1lEFmgKP3QvUVpEREdlfUAUHAQPLVpFTVdtJzxAHUNYW3AhQBM0QhFvEXAbYh8EAAVmDAJeU1oyGG0GcBdhGwUGCAVqYF9SO0xSN1sZdmA7dmMdBQAJB24qX1NbQxI6AjA2ME5dVFULPDsGPFcQTTdaLTA6SR0OFlQvPAwMDxYcYlxIVkcoLTcCDA%3D%3D%26nAID%3D13736960%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=CoolPix+S3100+14+Megapixel+Compact+Digital+Camera-+Red&dlprc=119.95&crn=&istrsmrc=1&isathrsl=0&AR=28&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=106834268&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=28&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=1&FS=0&code=&acode=583&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Searshttp://img.shopping.com/cctool/merch_logos/485615.gif1-800-349-43588882.85http://img.shopping.com/sc/mr/sdc_checks_3.gifhttp://www.shopping.com/xMR-store_sears_4189479~MRD-485615~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS00337013000COOLPIX S3100 PinkNikon Coolpix S3100 - Digital camera - compact - 14.0 Mpix - optical zoom: 5 x - supported memory: SD, SDXC, SDHC - pink7185Nikonhttp://di111.shopping.com/images/di/58/38/37/4177586c573164586f4d586b34515144546f51-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di111.shopping.com/images/di/58/38/37/4177586c573164586f4d586b34515144546f51-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di111.shopping.com/images/di/58/38/37/4177586c573164586f4d586b34515144546f51-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di111.shopping.com/images/di/58/38/37/4177586c573164586f4d586b34515144546f51-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2in-stockGet 30 days FREE SHIPPING w/ ShipVantage119.956.95139.95http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=578&BEFID=7185&aon=%5E1&MerchantID=485615&crawler_id=485615&dealId=X87AwXlW1dXoMXk4QQDToQ%3D%3D&url=http%3A%2F%2Fsears.rdr.channelintelligence.com%2Fgo.asp%3FfVhzOGNRAAQIASNiE1NbQBJpFHJxYx0CTAICI2BbH1lEFmgKP3QvUVpEREdlfUAUHAQPLVpFTVdtJzxAHUNYW3AhQBM0QhFvEXAbYh8EAAVmb2JcUFxDEGsPc3QDEkFZVQ0WFhdRW0MWbgYWDlxzdGMdAVQWRi0xDAwPFhw9TSobb05eWVVYKzsLTFVVQi5RICs3SA8MU1s2MQQKD1wf%26nAID%3D13736960%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=COOLPIX+S3100+Pink&dlprc=119.95&crn=&istrsmrc=1&isathrsl=0&AR=31&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=106834268&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=31&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=1&FS=0&code=&acode=583&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Searshttp://img.shopping.com/cctool/merch_logos/485615.gif1-800-349-43588882.85http://img.shopping.com/sc/mr/sdc_checks_3.gifhttp://www.shopping.com/xMR-store_sears_4189479~MRD-485615~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS00337015000Nikon Coolpix S3100 14.0 MP Digital Camera - SilverNikon Coolpix S3100 14.0 MP Digital Camera - Silver7185Nikonhttp://di109.shopping.com/images/di/6e/76/46/776e70664134726c413144626b736473613077-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di109.shopping.com/images/di/6e/76/46/776e70664134726c413144626b736473613077-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di109.shopping.com/images/di/6e/76/46/776e70664134726c413144626b736473613077-270x270-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3in-stock109.970.00109.97http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=803&BEFID=7185&aon=%5E&MerchantID=475774&crawler_id=475774&dealId=nvFwnpfA4rlA1Dbksdsa0w%3D%3D&url=http%3A%2F%2Fwww.thewiz.com%2Fcatalog%2Fproduct.jsp%3FmodelNo%3DS3100SILVER%26gdftrk%3DgdfV2677_a_7c996_a_7c4049_a_7c26262&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+Coolpix+S3100+14.0+MP+Digital+Camera+-+Silver&dlprc=109.97&crn=&istrsmrc=0&isathrsl=0&AR=33&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=106834268&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=33&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=797&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=TheWiz.comhttp://img.shopping.com/cctool/merch_logos/475774.gif877-542-69880http://img.shopping.com/sc/glb/flag/US.gifUS26262Nikon� COOLPIX� S3100 14MP Digital Camera (Silver)The Nikon COOLPIX S3100 is the easy way to share your life and stay connected.7185Nikonhttp://di102.shopping.com/images/di/35/47/74/614e324e6572794b7770732d5365326c2d3467-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di102.shopping.com/images/di/35/47/74/614e324e6572794b7770732d5365326c2d3467-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di102.shopping.com/images/di/35/47/74/614e324e6572794b7770732d5365326c2d3467-220x220-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4in-stock119.996.05119.99http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=504&BEFID=7185&aon=%5E1&MerchantID=332477&crawler_id=332477&dealId=5GtaN2NeryKwps-Se2l-4g%3D%3D&url=http%3A%2F%2Ftracking.searchmarketing.com%2Fgsic.asp%3Faid%3D848064082%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon%C3%AF%C2%BF%C2%BD+COOLPIX%C3%AF%C2%BF%C2%BD+S3100+14MP+Digital+Camera+%28Silver%29&dlprc=119.99&crn=&istrsmrc=0&isathrsl=0&AR=37&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=106834268&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=37&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=0&code=&acode=509&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=RadioShackhttp://img.shopping.com/cctool/merch_logos/332477.gif242.25http://img.shopping.com/sc/mr/sdc_checks_25.gifhttp://www.shopping.com/xMR-store_radioshack_9689~MRD-332477~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS10101095COOLPIX S3100 YellowNikon Coolpix S3100 - Digital camera - compact - 14.0 Mpix - optical zoom: 5 x - supported memory: SD, SDXC, SDHC - yellow7185Nikonhttp://di107.shopping.com/images/di/61/34/33/6d305258756c5833387a436e516a5535396a77-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di107.shopping.com/images/di/61/34/33/6d305258756c5833387a436e516a5535396a77-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di107.shopping.com/images/di/61/34/33/6d305258756c5833387a436e516a5535396a77-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di107.shopping.com/images/di/61/34/33/6d305258756c5833387a436e516a5535396a77-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5in-stockGet 30 days FREE SHIPPING w/ ShipVantage119.956.95139.95http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=578&BEFID=7185&aon=%5E1&MerchantID=485615&crawler_id=485615&dealId=a43m0RXulX38zCnQjU59jw%3D%3D&url=http%3A%2F%2Fsears.rdr.channelintelligence.com%2Fgo.asp%3FfVhzOGNRAAQIASNiE1NbQBJpFHJwYx0CTAICI2BbH1lEFmgKP3QvUVpEREdlfUAUHAQPLVpFTVdtJzxAHUNYW3AhQBM0QhFvEXAbYh8EAAVmb2JcUFxDEGoPc3QDEkFZVQ0WFhdRW0MWbgYWDlxzdGMdAVQWRi0xDAwPFhw9TSobb05eWVVYKzsLTFVVQi5RICs3SA8MU1s2MQQKD1wf%26nAID%3D13736960%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=COOLPIX+S3100+Yellow&dlprc=119.95&crn=&istrsmrc=1&isathrsl=0&AR=38&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=106834268&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=38&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=1&FS=0&code=&acode=583&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Searshttp://img.shopping.com/cctool/merch_logos/485615.gif1-800-349-43588882.85http://img.shopping.com/sc/mr/sdc_checks_3.gifhttp://www.shopping.com/xMR-store_sears_4189479~MRD-485615~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS00337014000Nikon D90 Digital Camera12.3 Megapixel, Point and Shoot Camera, 3 in. LCD Screen, With Video Capability, Weight: 1.36 lb.Untitled Document Nikon D90 SLR Digital Camera With 28-80mm 75-300mm Lens Kit The Nikon D90 SLR Digital Camera, with its 12.3-megapixel DX-format CMOS, 3" High resolution LCD display, Scene Recognition System, Picture Control, Active D-Lighting, and one-button Live View, provides photo enthusiasts with the image quality and performance they need to pursue their own vision while still being intuitive enough for use as an everyday camera.http://di1.shopping.com/images/pi/52/fb/d3/99671132-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=4http://di1.shopping.com/images/pi/52/fb/d3/99671132-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=4http://di1.shopping.com/images/pi/52/fb/d3/99671132-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=4http://di1.shopping.com/images/pi/52/fb/d3/99671132-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=4http://di1.shopping.com/images/pi/52/fb/d3/99671132-499x255-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=475.00http://img.shopping.com/sc/pr/sdc_stars_sm_5.gifhttp://www.shopping.com/Nikon-D90-with-18-270mm-Lens/reviews~linkin_id-7000610689.002299.00http://www.shopping.com/Nikon-D90-with-18-270mm-Lens/prices~linkin_id-7000610http://www.shopping.com/Nikon-D90-with-18-270mm-Lens/info~linkin_id-7000610Nikon® D90 12.3MP Digital SLR Camera (Body Only)The Nikon D90 will make you rethink what a digital SLR camera can achieve.7185Nikonhttp://di106.shopping.com/images/di/47/55/35/4a4a6b70554178653548756a4237666b774141-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di106.shopping.com/images/di/47/55/35/4a4a6b70554178653548756a4237666b774141-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di106.shopping.com/images/di/47/55/35/4a4a6b70554178653548756a4237666b774141-220x220-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1in-stock1015.996.051015.99http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=504&BEFID=7185&aon=%5E1&MerchantID=332477&crawler_id=332477&dealId=GU5JJkpUAxe5HujB7fkwAA%3D%3D&url=http%3A%2F%2Ftracking.searchmarketing.com%2Fgsic.asp%3Faid%3D851830266%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon%C2%AE+D90+12.3MP+Digital+SLR+Camera+%28Body+Only%29&dlprc=1015.99&crn=&istrsmrc=0&isathrsl=0&AR=14&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=99671132&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=14&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=0&code=&acode=496&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=RadioShackhttp://img.shopping.com/cctool/merch_logos/332477.gif242.25http://img.shopping.com/sc/mr/sdc_checks_25.gifhttp://www.shopping.com/xMR-store_radioshack_9689~MRD-332477~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS10148659Nikon D90 SLR Digital Camera (Camera Body)The Nikon D90 SLR Digital Camera with its 12.3-megapixel DX-format CCD 3" High resolution LCD display Scene Recognition System Picture Control Active D-Lighting and one-button Live View provides photo enthusiasts with the image quality and performance they need to pursue their own vision while still being intuitive enough for use as an everyday camera. In addition the D90 introduces the D-Movie mode allowing for the first time an interchangeable lens SLR camera that is capable of recording 720p HD movie clips. Availabilty: In Stock7185Nikonhttp://di109.shopping.com/images/di/58/68/55/527553432d73704262544944666f3471667a51-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di109.shopping.com/images/di/58/68/55/527553432d73704262544944666f3471667a51-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di109.shopping.com/images/di/58/68/55/527553432d73704262544944666f3471667a51-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di109.shopping.com/images/di/58/68/55/527553432d73704262544944666f3471667a51-350x350-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2in-stockFree Shipping with Any Purchase!689.000.00900.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=647&BEFID=7185&aon=%5E1&MerchantID=475674&crawler_id=475674&dealId=XhURuSC-spBbTIDfo4qfzQ%3D%3D&url=http%3A%2F%2Fwww.fumfie.com%2Fproduct%2F169.5%2Fshopping-com%3F&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D90+SLR+Digital+Camera+%28Camera+Body%29&dlprc=689.0&crn=&istrsmrc=1&isathrsl=0&AR=16&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=99671132&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=16&cid=&semid1=&semid2=&IsLps=0&CC=1&SL=1&FS=1&code=&acode=658&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=FumFiehttp://img.shopping.com/cctool/merch_logos/475674.gif866 666 91985604.27http://img.shopping.com/sc/mr/sdc_checks_45.gifhttp://www.shopping.com/xMR-store_fumfie~MRD-475674~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUSF169C5Nikon D90 SLR w/Nikon 18-105mm VR & 55-200mm VR Lenses12.3 MegapixelDX Format CMOS Sensor3" VGA LCD DisplayLive ViewSelf Cleaning SensorD-Movie ModeHigh Sensitivity (ISO 3200)4.5 fps BurstIn-Camera Image Editing7185Nikonhttp://di101.shopping.com/images/di/6f/30/50/785f584c5744627278415952793372436d7951-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di101.shopping.com/images/di/6f/30/50/785f584c5744627278415952793372436d7951-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di101.shopping.com/images/di/6f/30/50/785f584c5744627278415952793372436d7951-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di101.shopping.com/images/di/6f/30/50/785f584c5744627278415952793372436d7951-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di101.shopping.com/images/di/6f/30/50/785f584c5744627278415952793372436d7951-500x500-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3in-stock1189.000.001189.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=371&BEFID=7185&aon=%5E1&MerchantID=487342&crawler_id=487342&dealId=o0Px_XLWDbrxAYRy3rCmyQ%3D%3D&url=http%3A%2F%2Fwww.rythercamera.com%2Fcatalog%2Fproduct_info.php%3Fcsv%3Dsh%26products_id%3D30619%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D90+SLR+w%2FNikon+18-105mm+VR+%26+55-200mm+VR+Lenses&dlprc=1189.0&crn=&istrsmrc=0&isathrsl=0&AR=20&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=99671132&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=20&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=379&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=RytherCamera.comhttp://img.shopping.com/cctool/merch_logos/487342.gif1-877-644-75930http://img.shopping.com/sc/glb/flag/US.gifUS30619Nikon D90 12.3 Megapixel Digital SLR Camera (Body Only)Fusing 12.3 megapixel image quality and a cinematic 24fps D-Movie Mode, the Nikon D90 exceeds the demands of passionate photographers. Coupled with Nikon's EXPEED image processing technologies and NIKKOR optics, breathtaking image fidelity is assured. Combined with fast 0.15ms power-up and split-second 65ms shooting lag, dramatic action and decisive moments are captured easily. Effective 4-frequency, ultrasonic sensor cleaning frees image degrading dust particles from the sensor's optical low pass filter.7185Nikonhttp://di110.shopping.com/images/di/34/48/67/62574a534a3873736749663842304d58497741-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di110.shopping.com/images/di/34/48/67/62574a534a3873736749663842304d58497741-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di110.shopping.com/images/di/34/48/67/62574a534a3873736749663842304d58497741-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4in-stockFREE FEDEX 2-3 DAY DELIVERY899.950.00899.95http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=269&BEFID=7185&aon=%5E&MerchantID=9296&crawler_id=811558&dealId=4HgbWJSJ8ssgIf8B0MXIwA%3D%3D&url=http%3A%2F%2Fwww.pcnation.com%2Foptics-gallery%2Fdetails.asp%3Faffid%3D305%26item%3D2N145P&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D90+12.3+Megapixel+Digital+SLR+Camera+%28Body+Only%29&dlprc=899.95&crn=&istrsmrc=1&isathrsl=0&AR=21&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=99671132&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=21&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=257&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=PCNationhttp://img.shopping.com/cctool/merch_logos/9296.gif800-470-707916224.43http://img.shopping.com/sc/mr/sdc_checks_45.gifhttp://www.shopping.com/xMR-store_pcnation_9689~MRD-9296~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS2N145PNikon D90 12.3MP Digital SLR Camera (Body Only)Fusing 12.3-megapixel image quality inherited from the award-winning D300 with groundbreaking features, the D90's breathtaking, low-noise image quality is further advanced with EXPEED image processing. Split-second shutter response and continuous shooting at up to 4.5 frames-per-second provide the power to capture fast action and precise moments perfectly, while Nikon's exclusive Scene Recognition System contributes to faster 11-area autofocus performance, finer white balance detection and more. The D90 delivers the control passionate photographers demand, utilizing comprehensive exposure functions and the intelligence of 3D Color Matrix Metering II. Stunning results come to life on a 3-inch 920,000-dot color LCD monitor, providing accurate image review, Live View composition and brilliant playback of the D90's cinematic-quality 24-fps HD D-Movie mode.7185Nikonhttp://di102.shopping.com/images/di/55/4e/44/6133754d445a584f6e76445f377354494c5967-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di102.shopping.com/images/di/55/4e/44/6133754d445a584f6e76445f377354494c5967-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di102.shopping.com/images/di/55/4e/44/6133754d445a584f6e76445f377354494c5967-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di102.shopping.com/images/di/55/4e/44/6133754d445a584f6e76445f377354494c5967-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di102.shopping.com/images/di/55/4e/44/6133754d445a584f6e76445f377354494c5967-500x500-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5in-stockFantastic prices with ease & comfort of Amazon.com!780.000.00780.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=566&BEFID=7185&aon=%5E1&MerchantID=301531&crawler_id=1903313&dealId=UNDa3uMDZXOnvD_7sTILYg%3D%3D&url=http%3A%2F%2Fwww.amazon.com%2Fdp%2FB001ET5U92%2Fref%3Dasc_df_B001ET5U921751618%3Fsmid%3DAHF4SYKP09WBH%26tag%3Ddealtime-ce-mp01feed-20%26linkCode%3Dasn%26creative%3D395105%26creativeASIN%3DB001ET5U92&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D90+12.3MP+Digital+SLR+Camera+%28Body+Only%29&dlprc=780.0&crn=&istrsmrc=0&isathrsl=0&AR=29&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=99671132&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=29&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=520&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Amazon Marketplacehttp://img.shopping.com/cctool/merch_logos/301531.gif2132.73http://img.shopping.com/sc/mr/sdc_checks_25.gifhttp://www.shopping.com/xMR-store_amazon_marketplace_9689~MRD-301531~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUSB001ET5U92Nikon D90 Digital Camera with 18-105mm lens12.9 Megapixel, SLR Camera, 3 in. LCD Screen, 5.8x Optical Zoom, With Video Capability, Weight: 2.3 lb.Its 12.3 megapixel DX-format CMOS image sensor and EXPEED image processing system offer outstanding image quality across a wide ISO light sensitivity range. Live View mode lets you compose and shoot via the high-resolution 3-inch LCD monitor, and an advanced Scene Recognition System and autofocus performance help capture images with astounding accuracy. Movies can be shot in Motion JPEG format using the D-Movie function. The camera’s large image sensor ensures exceptional movie image quality and you can create dramatic effects by shooting with a wide range of interchangeable NIKKOR lenses, from wide-angle to macro to fisheye, or by adjusting the lens aperture and experimenting with depth-of-field. The D90 – designed to fuel your passion for photography.http://di1.shopping.com/images/pi/57/6a/4f/70621646-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=5http://di1.shopping.com/images/pi/57/6a/4f/70621646-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=5http://di1.shopping.com/images/pi/57/6a/4f/70621646-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=5http://di1.shopping.com/images/pi/57/6a/4f/70621646-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=5http://di1.shopping.com/images/pi/57/6a/4f/70621646-490x489-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=5324.81http://img.shopping.com/sc/pr/sdc_stars_sm_5.gifhttp://www.shopping.com/Nikon-D90-with-18-105mm-lens/reviews~linkin_id-7000610849.951599.95http://www.shopping.com/Nikon-D90-with-18-105mm-lens/prices~linkin_id-7000610http://www.shopping.com/Nikon-D90-with-18-105mm-lens/info~linkin_id-7000610Nikon D90 18-105mm VR LensThe Nikon D90 SLR Digital Camera with its 12.3-megapixel DX-format CMOS 3" High resolution LCD display Scene Recognition System Picture Control Active D-Lighting and one-button Live View prov7185Nikonhttp://di111.shopping.com/images/di/33/6f/35/6531566768674a5066684c7654314a464b5441-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di111.shopping.com/images/di/33/6f/35/6531566768674a5066684c7654314a464b5441-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di111.shopping.com/images/di/33/6f/35/6531566768674a5066684c7654314a464b5441-260x260-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1in-stock849.950.00849.95http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=419&BEFID=7185&aon=%5E1&MerchantID=9390&crawler_id=1905054&dealId=3o5e1VghgJPfhLvT1JFKTA%3D%3D&url=http%3A%2F%2Fwww.ajrichard.com%2FNikon-D90-18-105mm-VR-Lens%2Fp-292%3Frefid%3DShopping%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D90+18-105mm+VR+Lens&dlprc=849.95&crn=&istrsmrc=0&isathrsl=0&AR=2&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=70621646&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=2&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=425&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=AJRichardhttp://img.shopping.com/cctool/merch_logos/9390.gif1-888-871-125631244.48http://img.shopping.com/sc/mr/sdc_checks_45.gifhttp://www.shopping.com/xMR-store_ajrichard~MRD-9390~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS292Nikon D90 SLR w/Nikon 18-105mm VR Lens12.3 MegapixelDX Format CMOS Sensor3" VGA LCD DisplayLive ViewSelf Cleaning SensorD-Movie ModeHigh Sensitivity (ISO 3200)4.5 fps BurstIn-Camera Image Editing7185Nikonhttp://di108.shopping.com/images/di/5f/6c/59/576a5f6a62776673536b666377556344757777-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di108.shopping.com/images/di/5f/6c/59/576a5f6a62776673536b666377556344757777-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di108.shopping.com/images/di/5f/6c/59/576a5f6a62776673536b666377556344757777-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di108.shopping.com/images/di/5f/6c/59/576a5f6a62776673536b666377556344757777-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di108.shopping.com/images/di/5f/6c/59/576a5f6a62776673536b666377556344757777-500x500-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2in-stock909.000.00909.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=371&BEFID=7185&aon=%5E1&MerchantID=487342&crawler_id=487342&dealId=_lYWj_jbwfsSkfcwUcDuww%3D%3D&url=http%3A%2F%2Fwww.rythercamera.com%2Fcatalog%2Fproduct_info.php%3Fcsv%3Dsh%26products_id%3D30971%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D90+SLR+w%2FNikon+18-105mm+VR+Lens&dlprc=909.0&crn=&istrsmrc=0&isathrsl=0&AR=3&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=70621646&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=3&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=379&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=RytherCamera.comhttp://img.shopping.com/cctool/merch_logos/487342.gif1-877-644-75930http://img.shopping.com/sc/glb/flag/US.gifUS3097125448/D90 12.3 Megapixel Digital Camera 18-105mm Zoom Lens w/ 3" Screen - BlackNikon D90 - Digital camera - SLR - 12.3 Mpix - Nikon AF-S DX 18-105mm lens - optical zoom: 5.8 x - supported memory: SD, SDHC7185Nikonhttp://di110.shopping.com/images/di/31/4b/43/636c4347755776747932584b5539736b616467-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di110.shopping.com/images/di/31/4b/43/636c4347755776747932584b5539736b616467-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di110.shopping.com/images/di/31/4b/43/636c4347755776747932584b5539736b616467-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di110.shopping.com/images/di/31/4b/43/636c4347755776747932584b5539736b616467-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3in-stockGet 30 days FREE SHIPPING w/ ShipVantage1199.008.201199.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=578&BEFID=7185&aon=%5E1&MerchantID=485615&crawler_id=485615&dealId=1KCclCGuWvty2XKU9skadg%3D%3D&url=http%3A%2F%2Fsears.rdr.channelintelligence.com%2Fgo.asp%3FfVhzOGNRAAQIASNiE1NbQBRtFXpzYx0CTAICI2BbH1lEFmgKP3QvUVpEREdlfUAUHAQPLVpFTVdtJzxAHUNYW3AhQBM0QhFvEXAbYh8EAAVmb2JcVlhCGGkPc3QDEkFZVQ0WFhdRW0MWbgYWDlxzdGMdAVQWRi0xDAwPFhw9TSobb05eWVVYKzsLTFVVQi5RICs3SA8MU1s2MQQKD1wf%26nAID%3D13736960%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=25448%2FD90+12.3+Megapixel+Digital+Camera+18-105mm+Zoom+Lens+w%2F+3%22+Screen+-+Black&dlprc=1199.0&crn=&istrsmrc=1&isathrsl=0&AR=4&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=70621646&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=4&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=0&code=&acode=586&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Searshttp://img.shopping.com/cctool/merch_logos/485615.gif1-800-349-43588882.85http://img.shopping.com/sc/mr/sdc_checks_3.gifhttp://www.shopping.com/xMR-store_sears_4189479~MRD-485615~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS00353197000Nikon® D90 12.3MP Digital SLR with 18-105mm LensThe Nikon D90 will make you rethink what a digital SLR camera can achieve.7185Nikonhttp://di101.shopping.com/images/di/33/2d/56/4f53665656354a6f37486c41346b4a74616e41-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di101.shopping.com/images/di/33/2d/56/4f53665656354a6f37486c41346b4a74616e41-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di101.shopping.com/images/di/33/2d/56/4f53665656354a6f37486c41346b4a74616e41-220x220-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4in-stock1350.996.051350.99http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=504&BEFID=7185&aon=%5E1&MerchantID=332477&crawler_id=332477&dealId=3-VOSfVV5Jo7HlA4kJtanA%3D%3D&url=http%3A%2F%2Ftracking.searchmarketing.com%2Fgsic.asp%3Faid%3D982673361%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon%C2%AE+D90+12.3MP+Digital+SLR+with+18-105mm+Lens&dlprc=1350.99&crn=&istrsmrc=0&isathrsl=0&AR=5&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=70621646&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=5&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=0&code=&acode=496&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=RadioShackhttp://img.shopping.com/cctool/merch_logos/332477.gif242.25http://img.shopping.com/sc/mr/sdc_checks_25.gifhttp://www.shopping.com/xMR-store_radioshack_9689~MRD-332477~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS11148905Nikon D90 Kit 12.3-megapixel Digital SLR with 18-105mm VR LensPhotographers, take your passion further!Now is the time for new creativity, and to rethink what a digital SLR camera can achieve. It's time for the D90, a camera with everything you would expect from Nikon's next-generation D-SLRs, and some unexpected surprises, as well. The stunning image quality is inherited from the D300, Nikon's DX-format flagship. The D90 also has Nikon's unmatched ergonomics and high performance, and now takes high-quality movies with beautifully cinematic results. The world of photography has changed, and with the D90 in your hands, it's time to make your own rules.AF-S DX NIKKOR 18-105mm f/3.5-5.6G ED VR LensWide-ratio 5.8x zoom Compact, versatile and ideal for a broad range of shooting situations, ranging from interiors and landscapes to beautiful portraits� a perfect everyday zoom. Nikon VR (Vibration Reduction) image stabilization Vibration Reduction is engineered specifically for each VR NIKKOR lens and enables handheld shooting at up to 3 shutter speeds slower than would7185Nikonhttp://di110.shopping.com/images/di/6b/51/6e/4236725334416a4e3564783568325f36333167-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di110.shopping.com/images/di/6b/51/6e/4236725334416a4e3564783568325f36333167-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di110.shopping.com/images/di/6b/51/6e/4236725334416a4e3564783568325f36333167-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di110.shopping.com/images/di/6b/51/6e/4236725334416a4e3564783568325f36333167-300x232-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5in-stockShipping Included!1050.000.001199.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=135&BEFID=7185&aon=%5E1&MerchantID=313162&crawler_id=313162&dealId=kQnB6rS4AjN5dx5h2_631g%3D%3D&url=http%3A%2F%2Fonecall.rdr.channelintelligence.com%2Fgo.asp%3FfVhzOGNRAAQIASNiE1pZSxNoWHFwLx8GTAICa2ZeH1sPXTZLNzRpAh1HR0BxPQEGCBJNMhFHUElsFCFCVkVTTHAcBggEHQ4aHXNpGERGH3RQODsbAgdechJtbBt8fx8JAwhtZFAzJj1oGgIWCxRlNyFOUV9UUGIxBgo0T0IyTSYqJ0RWHw4QPCIBAAQXRGMDICg6TllZVBhh%26nAID%3D13736960&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D90+Kit+12.3-megapixel+Digital+SLR+with+18-105mm+VR+Lens&dlprc=1050.0&crn=&istrsmrc=1&isathrsl=0&AR=6&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=70621646&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=6&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=1&FS=1&code=&acode=143&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=OneCallhttp://img.shopping.com/cctool/merch_logos/313162.gif1.800.398.07661804.44http://img.shopping.com/sc/mr/sdc_checks_45.gifhttp://www.shopping.com/xMR-store_onecall_9689~MRD-313162~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS92826Price rangehttp://www.shopping.com/digital-cameras/nikon/products?oq=nikon&linkin_id=7000610$24 - $4012http://www.shopping.com/digital-cameras/nikon/products?minPrice=24&maxPrice=4012&linkin_id=7000610$4012 - $7999http://www.shopping.com/digital-cameras/nikon/products?minPrice=4012&maxPrice=7999&linkin_id=7000610Brandhttp://www.shopping.com/digital-cameras/nikon/products~all-9688-brand~MS-1?oq=nikon&linkin_id=7000610Nikonhttp://www.shopping.com/digital-cameras/nikon+brand-nikon/products~linkin_id-7000610Cranehttp://www.shopping.com/digital-cameras/nikon+9688-brand-crane/products~linkin_id-7000610Ikelitehttp://www.shopping.com/digital-cameras/nikon+ikelite/products~linkin_id-7000610Bowerhttp://www.shopping.com/digital-cameras/nikon+bower/products~linkin_id-7000610FUJIFILMhttp://www.shopping.com/digital-cameras/nikon+brand-fuji/products~linkin_id-7000610Storehttp://www.shopping.com/digital-cameras/nikon/products~all-store~MS-1?oq=nikon&linkin_id=7000610Amazon Marketplacehttp://www.shopping.com/digital-cameras/nikon+store-amazon-marketplace-9689/products~linkin_id-7000610Amazonhttp://www.shopping.com/digital-cameras/nikon+store-amazon/products~linkin_id-7000610Adoramahttp://www.shopping.com/digital-cameras/nikon+store-adorama/products~linkin_id-7000610J&R Music and Computer Worldhttp://www.shopping.com/digital-cameras/nikon+store-j-r-music-and-computer-world/products~linkin_id-7000610RytherCamera.comhttp://www.shopping.com/digital-cameras/nikon+store-rythercamera-com/products~linkin_id-7000610Resolutionhttp://www.shopping.com/digital-cameras/nikon/products~all-21885-resolution~MS-1?oq=nikon&linkin_id=7000610Under 4 Megapixelhttp://www.shopping.com/digital-cameras/nikon+under-4-megapixel/products~linkin_id-7000610At least 5 Megapixelhttp://www.shopping.com/digital-cameras/nikon+5-megapixel-digital-cameras/products~linkin_id-7000610At least 6 Megapixelhttp://www.shopping.com/digital-cameras/nikon+6-megapixel-digital-cameras/products~linkin_id-7000610At least 7 Megapixelhttp://www.shopping.com/digital-cameras/nikon+7-megapixel-digital-cameras/products~linkin_id-7000610At least 8 Megapixelhttp://www.shopping.com/digital-cameras/nikon+8-megapixel-digital-cameras/products~linkin_id-7000610Featureshttp://www.shopping.com/digital-cameras/nikon/products~all-32804-features~MS-1?oq=nikon&linkin_id=7000610Shockproofhttp://www.shopping.com/digital-cameras/nikon+32804-features-shockproof/products~linkin_id-7000610Waterproofhttp://www.shopping.com/digital-cameras/nikon+32804-features-waterproof/products~linkin_id-7000610Freezeproofhttp://www.shopping.com/digital-cameras/nikon+32804-features-freezeproof/products~linkin_id-7000610Dust proofhttp://www.shopping.com/digital-cameras/nikon+32804-features-dust-proof/products~linkin_id-7000610Image Stabilizationhttp://www.shopping.com/digital-cameras/nikon+32804-features-image-stabilization/products~linkin_id-7000610hybriddigital camerag1sonycameracanonnikonkodak digital camerakodaksony cybershotkodak easyshare digital cameranikon coolpixolympuspink digital cameracanon powershot \ No newline at end of file diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/examples/strict.dtd b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/strict.dtd new file mode 100644 index 0000000..b274559 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/strict.dtd @@ -0,0 +1,870 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +%HTMLlat1; + + +%HTMLsymbol; + + +%HTMLspecial; + + + + + + + + + + + + + +]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/examples/test.html b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/test.html new file mode 100644 index 0000000..61f8f1a --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/test.html @@ -0,0 +1,15 @@ + + + + + testing the parser + + + +

    hello + + + + diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/examples/test.xml b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/test.xml new file mode 100644 index 0000000..801292d --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/examples/test.xml @@ -0,0 +1,1254 @@ + + +]> + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + \ No newline at end of file diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/lib/sax.js b/node_modules/nib/node_modules/stylus/node_modules/sax/lib/sax.js new file mode 100644 index 0000000..77e20ae --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/lib/sax.js @@ -0,0 +1,1329 @@ +// wrapper for non-node envs +;(function (sax) { + +sax.parser = function (strict, opt) { return new SAXParser(strict, opt) } +sax.SAXParser = SAXParser +sax.SAXStream = SAXStream +sax.createStream = createStream + +// When we pass the MAX_BUFFER_LENGTH position, start checking for buffer overruns. +// When we check, schedule the next check for MAX_BUFFER_LENGTH - (max(buffer lengths)), +// since that's the earliest that a buffer overrun could occur. This way, checks are +// as rare as required, but as often as necessary to ensure never crossing this bound. +// Furthermore, buffers are only tested at most once per write(), so passing a very +// large string into write() might have undesirable effects, but this is manageable by +// the caller, so it is assumed to be safe. Thus, a call to write() may, in the extreme +// edge case, result in creating at most one complete copy of the string passed in. +// Set to Infinity to have unlimited buffers. +sax.MAX_BUFFER_LENGTH = 64 * 1024 + +var buffers = [ + "comment", "sgmlDecl", "textNode", "tagName", "doctype", + "procInstName", "procInstBody", "entity", "attribName", + "attribValue", "cdata", "script" +] + +sax.EVENTS = // for discoverability. + [ "text" + , "processinginstruction" + , "sgmldeclaration" + , "doctype" + , "comment" + , "attribute" + , "opentag" + , "closetag" + , "opencdata" + , "cdata" + , "closecdata" + , "error" + , "end" + , "ready" + , "script" + , "opennamespace" + , "closenamespace" + ] + +function SAXParser (strict, opt) { + if (!(this instanceof SAXParser)) return new SAXParser(strict, opt) + + var parser = this + clearBuffers(parser) + parser.q = parser.c = "" + parser.bufferCheckPosition = sax.MAX_BUFFER_LENGTH + parser.opt = opt || {} + parser.opt.lowercase = parser.opt.lowercase || parser.opt.lowercasetags + parser.looseCase = parser.opt.lowercase ? "toLowerCase" : "toUpperCase" + parser.tags = [] + parser.closed = parser.closedRoot = parser.sawRoot = false + parser.tag = parser.error = null + parser.strict = !!strict + parser.noscript = !!(strict || parser.opt.noscript) + parser.state = S.BEGIN + parser.ENTITIES = Object.create(sax.ENTITIES) + parser.attribList = [] + + // namespaces form a prototype chain. + // it always points at the current tag, + // which protos to its parent tag. + if (parser.opt.xmlns) parser.ns = Object.create(rootNS) + + // mostly just for error reporting + parser.trackPosition = parser.opt.position !== false + if (parser.trackPosition) { + parser.position = parser.line = parser.column = 0 + } + emit(parser, "onready") +} + +if (!Object.create) Object.create = function (o) { + function f () { this.__proto__ = o } + f.prototype = o + return new f +} + +if (!Object.getPrototypeOf) Object.getPrototypeOf = function (o) { + return o.__proto__ +} + +if (!Object.keys) Object.keys = function (o) { + var a = [] + for (var i in o) if (o.hasOwnProperty(i)) a.push(i) + return a +} + +function checkBufferLength (parser) { + var maxAllowed = Math.max(sax.MAX_BUFFER_LENGTH, 10) + , maxActual = 0 + for (var i = 0, l = buffers.length; i < l; i ++) { + var len = parser[buffers[i]].length + if (len > maxAllowed) { + // Text/cdata nodes can get big, and since they're buffered, + // we can get here under normal conditions. + // Avoid issues by emitting the text node now, + // so at least it won't get any bigger. + switch (buffers[i]) { + case "textNode": + closeText(parser) + break + + case "cdata": + emitNode(parser, "oncdata", parser.cdata) + parser.cdata = "" + break + + case "script": + emitNode(parser, "onscript", parser.script) + parser.script = "" + break + + default: + error(parser, "Max buffer length exceeded: "+buffers[i]) + } + } + maxActual = Math.max(maxActual, len) + } + // schedule the next check for the earliest possible buffer overrun. + parser.bufferCheckPosition = (sax.MAX_BUFFER_LENGTH - maxActual) + + parser.position +} + +function clearBuffers (parser) { + for (var i = 0, l = buffers.length; i < l; i ++) { + parser[buffers[i]] = "" + } +} + +SAXParser.prototype = + { end: function () { end(this) } + , write: write + , resume: function () { this.error = null; return this } + , close: function () { return this.write(null) } + } + +try { + var Stream = require("stream").Stream +} catch (ex) { + var Stream = function () {} +} + + +var streamWraps = sax.EVENTS.filter(function (ev) { + return ev !== "error" && ev !== "end" +}) + +function createStream (strict, opt) { + return new SAXStream(strict, opt) +} + +function SAXStream (strict, opt) { + if (!(this instanceof SAXStream)) return new SAXStream(strict, opt) + + Stream.apply(this) + + this._parser = new SAXParser(strict, opt) + this.writable = true + this.readable = true + + + var me = this + + this._parser.onend = function () { + me.emit("end") + } + + this._parser.onerror = function (er) { + me.emit("error", er) + + // if didn't throw, then means error was handled. + // go ahead and clear error, so we can write again. + me._parser.error = null + } + + this._decoder = null; + + streamWraps.forEach(function (ev) { + Object.defineProperty(me, "on" + ev, { + get: function () { return me._parser["on" + ev] }, + set: function (h) { + if (!h) { + me.removeAllListeners(ev) + return me._parser["on"+ev] = h + } + me.on(ev, h) + }, + enumerable: true, + configurable: false + }) + }) +} + +SAXStream.prototype = Object.create(Stream.prototype, + { constructor: { value: SAXStream } }) + +SAXStream.prototype.write = function (data) { + if (typeof Buffer === 'function' && + typeof Buffer.isBuffer === 'function' && + Buffer.isBuffer(data)) { + if (!this._decoder) { + var SD = require('string_decoder').StringDecoder + this._decoder = new SD('utf8') + } + data = this._decoder.write(data); + } + + this._parser.write(data.toString()) + this.emit("data", data) + return true +} + +SAXStream.prototype.end = function (chunk) { + if (chunk && chunk.length) this.write(chunk) + else if (this.leftovers) this._parser.write(this.leftovers.toString()) + this._parser.end() + return true +} + +SAXStream.prototype.on = function (ev, handler) { + var me = this + if (!me._parser["on"+ev] && streamWraps.indexOf(ev) !== -1) { + me._parser["on"+ev] = function () { + var args = arguments.length === 1 ? [arguments[0]] + : Array.apply(null, arguments) + args.splice(0, 0, ev) + me.emit.apply(me, args) + } + } + + return Stream.prototype.on.call(me, ev, handler) +} + + + +// character classes and tokens +var whitespace = "\r\n\t " + // this really needs to be replaced with character classes. + // XML allows all manner of ridiculous numbers and digits. + , number = "0124356789" + , letter = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + // (Letter | "_" | ":") + , quote = "'\"" + , entity = number+letter+"#" + , attribEnd = whitespace + ">" + , CDATA = "[CDATA[" + , DOCTYPE = "DOCTYPE" + , XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace" + , XMLNS_NAMESPACE = "http://www.w3.org/2000/xmlns/" + , rootNS = { xml: XML_NAMESPACE, xmlns: XMLNS_NAMESPACE } + +// turn all the string character sets into character class objects. +whitespace = charClass(whitespace) +number = charClass(number) +letter = charClass(letter) + +// http://www.w3.org/TR/REC-xml/#NT-NameStartChar +// This implementation works on strings, a single character at a time +// as such, it cannot ever support astral-plane characters (10000-EFFFF) +// without a significant breaking change to either this parser, or the +// JavaScript language. Implementation of an emoji-capable xml parser +// is left as an exercise for the reader. +var nameStart = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/ + +var nameBody = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040\.\d-]/ + +quote = charClass(quote) +entity = charClass(entity) +attribEnd = charClass(attribEnd) + +function charClass (str) { + return str.split("").reduce(function (s, c) { + s[c] = true + return s + }, {}) +} + +function isRegExp (c) { + return Object.prototype.toString.call(c) === '[object RegExp]' +} + +function is (charclass, c) { + return isRegExp(charclass) ? !!c.match(charclass) : charclass[c] +} + +function not (charclass, c) { + return !is(charclass, c) +} + +var S = 0 +sax.STATE = +{ BEGIN : S++ +, TEXT : S++ // general stuff +, TEXT_ENTITY : S++ // & and such. +, OPEN_WAKA : S++ // < +, SGML_DECL : S++ // +, SCRIPT : S++ // " + , expect : + [ [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ] + , [ "opentag", { name: "script", attributes: {}, isSelfClosing: false } ] + , [ "text", "hello world" ] + , [ "closetag", "script" ] + , [ "closetag", "xml" ] + ] + , strict : false + , opt : { lowercasetags: true, noscript: true } + } + ) + +require(__dirname).test + ( { xml : "" + , expect : + [ [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ] + , [ "opentag", { name: "script", attributes: {}, isSelfClosing: false } ] + , [ "opencdata", undefined ] + , [ "cdata", "hello world" ] + , [ "closecdata", undefined ] + , [ "closetag", "script" ] + , [ "closetag", "xml" ] + ] + , strict : false + , opt : { lowercasetags: true, noscript: true } + } + ) + diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/issue-84.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/issue-84.js new file mode 100644 index 0000000..0e7ee69 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/issue-84.js @@ -0,0 +1,13 @@ +// https://github.com/isaacs/sax-js/issues/49 +require(__dirname).test + ( { xml : "body" + , expect : + [ [ "processinginstruction", { name: "has", body: "unbalanced \"quotes" } ], + [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ] + , [ "text", "body" ] + , [ "closetag", "xml" ] + ] + , strict : false + , opt : { lowercasetags: true, noscript: true } + } + ) diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/parser-position.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/parser-position.js new file mode 100644 index 0000000..e4a68b1 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/parser-position.js @@ -0,0 +1,28 @@ +var sax = require("../lib/sax"), + assert = require("assert") + +function testPosition(chunks, expectedEvents) { + var parser = sax.parser(); + expectedEvents.forEach(function(expectation) { + parser['on' + expectation[0]] = function() { + for (var prop in expectation[1]) { + assert.equal(parser[prop], expectation[1][prop]); + } + } + }); + chunks.forEach(function(chunk) { + parser.write(chunk); + }); +}; + +testPosition(['

    abcdefgh
    '], + [ ['opentag', { position: 5, startTagPosition: 1 }] + , ['text', { position: 19, startTagPosition: 14 }] + , ['closetag', { position: 19, startTagPosition: 14 }] + ]); + +testPosition(['
    abcde','fgh
    '], + [ ['opentag', { position: 5, startTagPosition: 1 }] + , ['text', { position: 19, startTagPosition: 14 }] + , ['closetag', { position: 19, startTagPosition: 14 }] + ]); diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/script-close-better.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/script-close-better.js new file mode 100644 index 0000000..f4887b9 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/script-close-better.js @@ -0,0 +1,12 @@ +require(__dirname).test({ + xml : "", + expect : [ + ["opentag", {"name": "HTML","attributes": {}, isSelfClosing: false}], + ["opentag", {"name": "HEAD","attributes": {}, isSelfClosing: false}], + ["opentag", {"name": "SCRIPT","attributes": {}, isSelfClosing: false}], + ["script", "'
    foo
    ", + expect : [ + ["opentag", {"name": "HTML","attributes": {}, "isSelfClosing": false}], + ["opentag", {"name": "HEAD","attributes": {}, "isSelfClosing": false}], + ["opentag", {"name": "SCRIPT","attributes": {}, "isSelfClosing": false}], + ["script", "if (1 < 0) { console.log('elo there'); }"], + ["closetag", "SCRIPT"], + ["closetag", "HEAD"], + ["closetag", "HTML"] + ] +}); diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/self-closing-child-strict.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/self-closing-child-strict.js new file mode 100644 index 0000000..3d6e985 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/self-closing-child-strict.js @@ -0,0 +1,44 @@ + +require(__dirname).test({ + xml : + ""+ + "" + + "" + + "" + + "" + + "=(|)" + + "" + + "", + expect : [ + ["opentag", { + "name": "root", + "attributes": {}, + "isSelfClosing": false + }], + ["opentag", { + "name": "child", + "attributes": {}, + "isSelfClosing": false + }], + ["opentag", { + "name": "haha", + "attributes": {}, + "isSelfClosing": true + }], + ["closetag", "haha"], + ["closetag", "child"], + ["opentag", { + "name": "monkey", + "attributes": {}, + "isSelfClosing": false + }], + ["text", "=(|)"], + ["closetag", "monkey"], + ["closetag", "root"], + ["end"], + ["ready"] + ], + strict : true, + opt : {} +}); + diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/self-closing-child.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/self-closing-child.js new file mode 100644 index 0000000..f31c366 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/self-closing-child.js @@ -0,0 +1,44 @@ + +require(__dirname).test({ + xml : + ""+ + "" + + "" + + "" + + "" + + "=(|)" + + "" + + "", + expect : [ + ["opentag", { + "name": "ROOT", + "attributes": {}, + "isSelfClosing": false + }], + ["opentag", { + "name": "CHILD", + "attributes": {}, + "isSelfClosing": false + }], + ["opentag", { + "name": "HAHA", + "attributes": {}, + "isSelfClosing": true + }], + ["closetag", "HAHA"], + ["closetag", "CHILD"], + ["opentag", { + "name": "MONKEY", + "attributes": {}, + "isSelfClosing": false + }], + ["text", "=(|)"], + ["closetag", "MONKEY"], + ["closetag", "ROOT"], + ["end"], + ["ready"] + ], + strict : false, + opt : {} +}); + diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/self-closing-tag.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/self-closing-tag.js new file mode 100644 index 0000000..d1d8b7c --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/self-closing-tag.js @@ -0,0 +1,25 @@ + +require(__dirname).test({ + xml : + " "+ + " "+ + " "+ + " "+ + "=(|) "+ + ""+ + " ", + expect : [ + ["opentag", {name:"ROOT", attributes:{}, isSelfClosing: false}], + ["opentag", {name:"HAHA", attributes:{}, isSelfClosing: true}], + ["closetag", "HAHA"], + ["opentag", {name:"HAHA", attributes:{}, isSelfClosing: true}], + ["closetag", "HAHA"], + // ["opentag", {name:"HAHA", attributes:{}}], + // ["closetag", "HAHA"], + ["opentag", {name:"MONKEY", attributes:{}, isSelfClosing: false}], + ["text", "=(|)"], + ["closetag", "MONKEY"], + ["closetag", "ROOT"] + ], + opt : { trim : true } +}); \ No newline at end of file diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/stray-ending.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/stray-ending.js new file mode 100644 index 0000000..bec467b --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/stray-ending.js @@ -0,0 +1,17 @@ +// stray ending tags should just be ignored in non-strict mode. +// https://github.com/isaacs/sax-js/issues/32 +require(__dirname).test + ( { xml : + "" + , expect : + [ [ "opentag", { name: "A", attributes: {}, isSelfClosing: false } ] + , [ "opentag", { name: "B", attributes: {}, isSelfClosing: false } ] + , [ "text", "" ] + , [ "closetag", "B" ] + , [ "closetag", "A" ] + ] + , strict : false + , opt : {} + } + ) + diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/trailing-attribute-no-value.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/trailing-attribute-no-value.js new file mode 100644 index 0000000..222837f --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/trailing-attribute-no-value.js @@ -0,0 +1,10 @@ + +require(__dirname).test({ + xml : + "", + expect : [ + ["attribute", {name:"ATTRIB", value:"attrib"}], + ["opentag", {name:"ROOT", attributes:{"ATTRIB":"attrib"}, isSelfClosing: false}] + ], + opt : { trim : true } +}); diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/trailing-non-whitespace.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/trailing-non-whitespace.js new file mode 100644 index 0000000..619578b --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/trailing-non-whitespace.js @@ -0,0 +1,18 @@ + +require(__dirname).test({ + xml : "Welcome, to monkey land", + expect : [ + ["opentag", { + "name": "SPAN", + "attributes": {}, + isSelfClosing: false + }], + ["text", "Welcome,"], + ["closetag", "SPAN"], + ["text", " to monkey land"], + ["end"], + ["ready"] + ], + strict : false, + opt : {} +}); diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/unclosed-root.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/unclosed-root.js new file mode 100644 index 0000000..f4eeac6 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/unclosed-root.js @@ -0,0 +1,11 @@ +require(__dirname).test + ( { xml : "" + + , expect : + [ [ "opentag", { name: "root", attributes: {}, isSelfClosing: false } ] + , [ "error", "Unclosed root tag\nLine: 0\nColumn: 6\nChar: " ] + ] + , strict : true + , opt : {} + } + ) diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/unquoted.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/unquoted.js new file mode 100644 index 0000000..b3a9a81 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/unquoted.js @@ -0,0 +1,18 @@ +// unquoted attributes should be ok in non-strict mode +// https://github.com/isaacs/sax-js/issues/31 +require(__dirname).test + ( { xml : + "" + , expect : + [ [ "attribute", { name: "CLASS", value: "test" } ] + , [ "attribute", { name: "HELLO", value: "world" } ] + , [ "opentag", { name: "SPAN", + attributes: { CLASS: "test", HELLO: "world" }, + isSelfClosing: false } ] + , [ "closetag", "SPAN" ] + ] + , strict : false + , opt : {} + } + ) + diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/utf8-split.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/utf8-split.js new file mode 100644 index 0000000..e22bc10 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/utf8-split.js @@ -0,0 +1,32 @@ +var assert = require('assert') +var saxStream = require('../lib/sax').createStream() + +var b = new Buffer('误') + +saxStream.on('text', function(text) { + assert.equal(text, b.toString()) +}) + +saxStream.write(new Buffer('')) +saxStream.write(b.slice(0, 1)) +saxStream.write(b.slice(1)) +saxStream.write(new Buffer('')) +saxStream.write(b.slice(0, 2)) +saxStream.write(b.slice(2)) +saxStream.write(new Buffer('')) +saxStream.write(b) +saxStream.write(new Buffer('')) +saxStream.write(Buffer.concat([new Buffer(''), b.slice(0, 1)])) +saxStream.end(Buffer.concat([b.slice(1), new Buffer('')])) + +var saxStream2 = require('../lib/sax').createStream() + +saxStream2.on('text', function(text) { + assert.equal(text, '�') +}); + +saxStream2.write(new Buffer('')); +saxStream2.write(new Buffer([0xC0])); +saxStream2.write(new Buffer('')); +saxStream2.write(Buffer.concat([new Buffer(''), b.slice(0,1)])); +saxStream2.end(); diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-issue-41.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-issue-41.js new file mode 100644 index 0000000..17ab45a --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-issue-41.js @@ -0,0 +1,68 @@ +var t = require(__dirname) + + , xmls = // should be the same both ways. + [ "" + , "" ] + + , ex1 = + [ [ "opennamespace" + , { prefix: "a" + , uri: "http://ATTRIBUTE" + } + ] + , [ "attribute" + , { name: "xmlns:a" + , value: "http://ATTRIBUTE" + , prefix: "xmlns" + , local: "a" + , uri: "http://www.w3.org/2000/xmlns/" + } + ] + , [ "attribute" + , { name: "a:attr" + , local: "attr" + , prefix: "a" + , uri: "http://ATTRIBUTE" + , value: "value" + } + ] + , [ "opentag" + , { name: "parent" + , uri: "" + , prefix: "" + , local: "parent" + , attributes: + { "a:attr": + { name: "a:attr" + , local: "attr" + , prefix: "a" + , uri: "http://ATTRIBUTE" + , value: "value" + } + , "xmlns:a": + { name: "xmlns:a" + , local: "a" + , prefix: "xmlns" + , uri: "http://www.w3.org/2000/xmlns/" + , value: "http://ATTRIBUTE" + } + } + , ns: {"a": "http://ATTRIBUTE"} + , isSelfClosing: true + } + ] + , ["closetag", "parent"] + , ["closenamespace", { prefix: "a", uri: "http://ATTRIBUTE" }] + ] + + // swap the order of elements 2 and 1 + , ex2 = [ex1[0], ex1[2], ex1[1]].concat(ex1.slice(3)) + , expected = [ex1, ex2] + +xmls.forEach(function (x, i) { + t.test({ xml: x + , expect: expected[i] + , strict: true + , opt: { xmlns: true } + }) +}) diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-rebinding.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-rebinding.js new file mode 100644 index 0000000..07e0425 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-rebinding.js @@ -0,0 +1,63 @@ + +require(__dirname).test + ( { xml : + ""+ + ""+ + ""+ + ""+ + ""+ + "" + + , expect : + [ [ "opennamespace", { prefix: "x", uri: "x1" } ] + , [ "opennamespace", { prefix: "y", uri: "y1" } ] + , [ "attribute", { name: "xmlns:x", value: "x1", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "x" } ] + , [ "attribute", { name: "xmlns:y", value: "y1", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "y" } ] + , [ "attribute", { name: "x:a", value: "x1", uri: "x1", prefix: "x", local: "a" } ] + , [ "attribute", { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } ] + , [ "opentag", { name: "root", uri: "", prefix: "", local: "root", + attributes: { "xmlns:x": { name: "xmlns:x", value: "x1", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "x" } + , "xmlns:y": { name: "xmlns:y", value: "y1", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "y" } + , "x:a": { name: "x:a", value: "x1", uri: "x1", prefix: "x", local: "a" } + , "y:a": { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } }, + ns: { x: 'x1', y: 'y1' }, + isSelfClosing: false } ] + + , [ "opennamespace", { prefix: "x", uri: "x2" } ] + , [ "attribute", { name: "xmlns:x", value: "x2", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "x" } ] + , [ "opentag", { name: "rebind", uri: "", prefix: "", local: "rebind", + attributes: { "xmlns:x": { name: "xmlns:x", value: "x2", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "x" } }, + ns: { x: 'x2' }, + isSelfClosing: false } ] + + , [ "attribute", { name: "x:a", value: "x2", uri: "x2", prefix: "x", local: "a" } ] + , [ "attribute", { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } ] + , [ "opentag", { name: "check", uri: "", prefix: "", local: "check", + attributes: { "x:a": { name: "x:a", value: "x2", uri: "x2", prefix: "x", local: "a" } + , "y:a": { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } }, + ns: { x: 'x2' }, + isSelfClosing: true } ] + + , [ "closetag", "check" ] + + , [ "closetag", "rebind" ] + , [ "closenamespace", { prefix: "x", uri: "x2" } ] + + , [ "attribute", { name: "x:a", value: "x1", uri: "x1", prefix: "x", local: "a" } ] + , [ "attribute", { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } ] + , [ "opentag", { name: "check", uri: "", prefix: "", local: "check", + attributes: { "x:a": { name: "x:a", value: "x1", uri: "x1", prefix: "x", local: "a" } + , "y:a": { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } }, + ns: { x: 'x1', y: 'y1' }, + isSelfClosing: true } ] + , [ "closetag", "check" ] + + , [ "closetag", "root" ] + , [ "closenamespace", { prefix: "x", uri: "x1" } ] + , [ "closenamespace", { prefix: "y", uri: "y1" } ] + ] + , strict : true + , opt : { xmlns: true } + } + ) + diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-strict.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-strict.js new file mode 100644 index 0000000..b5e3e51 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-strict.js @@ -0,0 +1,74 @@ + +require(__dirname).test + ( { xml : + ""+ + ""+ + ""+ + ""+ + ""+ + ""+ + ""+ + ""+ + ""+ + "" + + , expect : + [ [ "opentag", { name: "root", prefix: "", local: "root", uri: "", + attributes: {}, ns: {}, isSelfClosing: false } ] + + , [ "attribute", { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } ] + , [ "opentag", { name: "plain", prefix: "", local: "plain", uri: "", + attributes: { "attr": { name: "attr", value: "normal", uri: "", prefix: "", local: "attr", uri: "" } }, + ns: {}, isSelfClosing: true } ] + , [ "closetag", "plain" ] + + , [ "opennamespace", { prefix: "", uri: "uri:default" } ] + + , [ "attribute", { name: "xmlns", value: "uri:default", prefix: "xmlns", local: "", uri: "http://www.w3.org/2000/xmlns/" } ] + , [ "opentag", { name: "ns1", prefix: "", local: "ns1", uri: "uri:default", + attributes: { "xmlns": { name: "xmlns", value: "uri:default", prefix: "xmlns", local: "", uri: "http://www.w3.org/2000/xmlns/" } }, + ns: { "": "uri:default" }, isSelfClosing: false } ] + + , [ "attribute", { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } ] + , [ "opentag", { name: "plain", prefix: "", local: "plain", uri: "uri:default", ns: { '': 'uri:default' }, + attributes: { "attr": { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } }, + isSelfClosing: true } ] + , [ "closetag", "plain" ] + + , [ "closetag", "ns1" ] + + , [ "closenamespace", { prefix: "", uri: "uri:default" } ] + + , [ "opennamespace", { prefix: "a", uri: "uri:nsa" } ] + + , [ "attribute", { name: "xmlns:a", value: "uri:nsa", prefix: "xmlns", local: "a", uri: "http://www.w3.org/2000/xmlns/" } ] + + , [ "opentag", { name: "ns2", prefix: "", local: "ns2", uri: "", + attributes: { "xmlns:a": { name: "xmlns:a", value: "uri:nsa", prefix: "xmlns", local: "a", uri: "http://www.w3.org/2000/xmlns/" } }, + ns: { a: "uri:nsa" }, isSelfClosing: false } ] + + , [ "attribute", { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } ] + , [ "opentag", { name: "plain", prefix: "", local: "plain", uri: "", + attributes: { "attr": { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } }, + ns: { a: 'uri:nsa' }, + isSelfClosing: true } ] + , [ "closetag", "plain" ] + + , [ "attribute", { name: "a:attr", value: "namespaced", prefix: "a", local: "attr", uri: "uri:nsa" } ] + , [ "opentag", { name: "a:ns", prefix: "a", local: "ns", uri: "uri:nsa", + attributes: { "a:attr": { name: "a:attr", value: "namespaced", prefix: "a", local: "attr", uri: "uri:nsa" } }, + ns: { a: 'uri:nsa' }, + isSelfClosing: true } ] + , [ "closetag", "a:ns" ] + + , [ "closetag", "ns2" ] + + , [ "closenamespace", { prefix: "a", uri: "uri:nsa" } ] + + , [ "closetag", "root" ] + ] + , strict : true + , opt : { xmlns: true } + } + ) + diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-unbound-element.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-unbound-element.js new file mode 100644 index 0000000..9d031a2 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-unbound-element.js @@ -0,0 +1,33 @@ +require(__dirname).test( + { strict : true + , opt : { xmlns: true } + , expect : + [ [ "error", "Unbound namespace prefix: \"unbound:root\"\nLine: 0\nColumn: 15\nChar: >"] + , [ "opentag", { name: "unbound:root", uri: "unbound", prefix: "unbound", local: "root" + , attributes: {}, ns: {}, isSelfClosing: true } ] + , [ "closetag", "unbound:root" ] + ] + } +).write(""); + +require(__dirname).test( + { strict : true + , opt : { xmlns: true } + , expect : + [ [ "opennamespace", { prefix: "unbound", uri: "someuri" } ] + , [ "attribute", { name: 'xmlns:unbound', value: 'someuri' + , prefix: 'xmlns', local: 'unbound' + , uri: 'http://www.w3.org/2000/xmlns/' } ] + , [ "opentag", { name: "unbound:root", uri: "someuri", prefix: "unbound", local: "root" + , attributes: { 'xmlns:unbound': { + name: 'xmlns:unbound' + , value: 'someuri' + , prefix: 'xmlns' + , local: 'unbound' + , uri: 'http://www.w3.org/2000/xmlns/' } } + , ns: { "unbound": "someuri" }, isSelfClosing: true } ] + , [ "closetag", "unbound:root" ] + , [ "closenamespace", { prefix: 'unbound', uri: 'someuri' }] + ] + } +).write(""); diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-unbound.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-unbound.js new file mode 100644 index 0000000..b740e26 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-unbound.js @@ -0,0 +1,15 @@ + +require(__dirname).test( + { strict : true + , opt : { xmlns: true } + , expect : + [ ["error", "Unbound namespace prefix: \"unbound\"\nLine: 0\nColumn: 28\nChar: >"] + + , [ "attribute", { name: "unbound:attr", value: "value", uri: "unbound", prefix: "unbound", local: "attr" } ] + , [ "opentag", { name: "root", uri: "", prefix: "", local: "root", + attributes: { "unbound:attr": { name: "unbound:attr", value: "value", uri: "unbound", prefix: "unbound", local: "attr" } }, + ns: {}, isSelfClosing: true } ] + , [ "closetag", "root" ] + ] + } +).write("") diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-ns.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-ns.js new file mode 100644 index 0000000..b1984d2 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-ns.js @@ -0,0 +1,31 @@ +var xmlns_attr = +{ + name: "xmlns", value: "http://foo", prefix: "xmlns", + local: "", uri : "http://www.w3.org/2000/xmlns/" +}; + +var attr_attr = +{ + name: "attr", value: "bar", prefix: "", + local : "attr", uri : "" +}; + + +require(__dirname).test + ( { xml : + "" + , expect : + [ [ "opennamespace", { prefix: "", uri: "http://foo" } ] + , [ "attribute", xmlns_attr ] + , [ "attribute", attr_attr ] + , [ "opentag", { name: "elm", prefix: "", local: "elm", uri : "http://foo", + ns : { "" : "http://foo" }, + attributes: { xmlns: xmlns_attr, attr: attr_attr }, + isSelfClosing: true } ] + , [ "closetag", "elm" ] + , [ "closenamespace", { prefix: "", uri: "http://foo"} ] + ] + , strict : true + , opt : {xmlns: true} + } + ) diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-prefix-attribute.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-prefix-attribute.js new file mode 100644 index 0000000..e41f218 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-prefix-attribute.js @@ -0,0 +1,36 @@ +require(__dirname).test( + { xml : "" + , expect : + [ [ "attribute" + , { name: "xml:lang" + , local: "lang" + , prefix: "xml" + , uri: "http://www.w3.org/XML/1998/namespace" + , value: "en" + } + ] + , [ "opentag" + , { name: "root" + , uri: "" + , prefix: "" + , local: "root" + , attributes: + { "xml:lang": + { name: "xml:lang" + , local: "lang" + , prefix: "xml" + , uri: "http://www.w3.org/XML/1998/namespace" + , value: "en" + } + } + , ns: {} + , isSelfClosing: true + } + ] + , ["closetag", "root"] + ] + , strict : true + , opt : { xmlns: true } + } +) + diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-prefix.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-prefix.js new file mode 100644 index 0000000..a85b478 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-prefix.js @@ -0,0 +1,21 @@ +require(__dirname).test( + { xml : "" + , expect : + [ + [ "opentag" + , { name: "xml:root" + , uri: "http://www.w3.org/XML/1998/namespace" + , prefix: "xml" + , local: "root" + , attributes: {} + , ns: {} + , isSelfClosing: true + } + ] + , ["closetag", "xml:root"] + ] + , strict : true + , opt : { xmlns: true } + } +) + diff --git a/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-redefine.js b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-redefine.js new file mode 100644 index 0000000..d35d5a0 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-redefine.js @@ -0,0 +1,41 @@ +require(__dirname).test( + { xml : "" + , expect : + [ ["error" + , "xml: prefix must be bound to http://www.w3.org/XML/1998/namespace\n" + + "Actual: ERROR\n" + + "Line: 0\nColumn: 27\nChar: '" + ] + , [ "attribute" + , { name: "xmlns:xml" + , local: "xml" + , prefix: "xmlns" + , uri: "http://www.w3.org/2000/xmlns/" + , value: "ERROR" + } + ] + , [ "opentag" + , { name: "xml:root" + , uri: "http://www.w3.org/XML/1998/namespace" + , prefix: "xml" + , local: "root" + , attributes: + { "xmlns:xml": + { name: "xmlns:xml" + , local: "xml" + , prefix: "xmlns" + , uri: "http://www.w3.org/2000/xmlns/" + , value: "ERROR" + } + } + , ns: {} + , isSelfClosing: true + } + ] + , ["closetag", "xml:root"] + ] + , strict : true + , opt : { xmlns: true } + } +) + diff --git a/node_modules/nib/node_modules/stylus/package.json b/node_modules/nib/node_modules/stylus/package.json new file mode 100644 index 0000000..2c152c0 --- /dev/null +++ b/node_modules/nib/node_modules/stylus/package.json @@ -0,0 +1,54 @@ +{ + "name": "stylus", + "description": "Robust, expressive, and feature-rich CSS superset", + "version": "0.35.1", + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "keywords": [ + "css", + "parser", + "style", + "stylesheets", + "jade", + "language" + ], + "repository": { + "type": "git", + "url": "git://github.com/LearnBoost/stylus" + }, + "main": "./index.js", + "browserify": "./lib/browserify.js", + "engines": { + "node": "*" + }, + "bin": { + "stylus": "./bin/stylus" + }, + "scripts": { + "prepublish": "npm prune", + "test": "make test" + }, + "dependencies": { + "cssom": "0.2.x", + "mkdirp": "0.3.x", + "debug": "*", + "sax": "0.5.x" + }, + "devDependencies": { + "should": "*", + "mocha": "*" + }, + "readme": "# Stylus\n\n Stylus is a revolutionary new language, providing an efficient, dynamic, and expressive way to generate CSS. Supporting both an indented syntax and regular CSS style.\n\n## Installation\n\n```bash\n$ npm install stylus\n```\n\n### Example\n\n```\nborder-radius()\n -webkit-border-radius: arguments\n -moz-border-radius: arguments\n border-radius: arguments\n\nbody a\n font: 12px/1.4 \"Lucida Grande\", Arial, sans-serif\n background: black\n color: #ccc\n\nform input\n padding: 5px\n border: 1px solid\n border-radius: 5px\n```\n\ncompiles to:\n\n```css\nbody a {\n font: 12px/1.4 \"Lucida Grande\", Arial, sans-serif;\n background: #000;\n color: #ccc;\n}\nform input {\n padding: 5px;\n border: 1px solid;\n -webkit-border-radius: 5px;\n -moz-border-radius: 5px;\n border-radius: 5px;\n}\n```\n\nthe following is equivalent to the indented version of Stylus source, using the CSS syntax instead:\n\n```\nborder-radius() {\n -webkit-border-radius: arguments\n -moz-border-radius: arguments\n border-radius: arguments\n}\n\nbody a {\n font: 12px/1.4 \"Lucida Grande\", Arial, sans-serif;\n background: black;\n color: #ccc;\n}\n\nform input {\n padding: 5px;\n border: 1px solid;\n border-radius: 5px;\n}\n```\n\n### Features\n\n Stylus has _many_ features. Detailed documentation links follow:\n\n - [css syntax](docs/css-style.md) support\n - [mixins](docs/mixins.md)\n - [keyword arguments](docs/kwargs.md)\n - [variables](docs/variables.md)\n - [interpolation](docs/interpolation.md)\n - arithmetic, logical, and equality [operators](docs/operators.md)\n - [importing](docs/import.md) of other stylus sheets\n - [introspection api](docs/introspection.md)\n - type coercion\n - [@extend](docs/extend.md)\n - [conditionals](docs/conditionals.md)\n - [iteration](docs/iteration.md)\n - nested [selectors](docs/selectors.md)\n - parent reference\n - in-language [functions](docs/functions.md)\n - [variable arguments](docs/vargs.md)\n - built-in [functions](docs/bifs.md) (over 25)\n - optional [image inlining](docs/functions.url.md)\n - optional compression\n - JavaScript [API](docs/js.md)\n - extremely terse syntax\n - stylus [executable](docs/executable.md)\n - [error reporting](docs/error-reporting.md)\n - single-line and multi-line [comments](docs/comments.md)\n - css [literal](docs/literal.md)\n - character [escaping](docs/escape.md)\n - [@keyframes](docs/keyframes.md) support & expansion\n - [@font-face](docs/font-face.md) support\n - [@media](docs/media.md) support\n - Connect [Middleware](docs/middleware.md)\n - TextMate [bundle](docs/textmate.md)\n - Coda/SubEtha Edit [Syntax mode](https://github.com/atljeremy/Stylus.mode)\n - gedit [language-spec](docs/gedit.md)\n - VIM [Syntax](https://github.com/wavded/vim-stylus)\n - [Firebug extension](docs/firebug.md)\n - heroku [web service](http://styl.heroku.com) for compiling stylus\n - [style guide](https://github.com/lepture/ganam) parser and generator\n - transparent vendor-specific function expansion\n\n### Community modules\n\n - https://github.com/LearnBoost/stylus/wiki\n\n### Framework Support\n\n - [Connect](docs/middleware.md)\n - [Play! 2.0](https://github.com/patiencelabs/play-stylus)\n - [Ruby On Rails](https://github.com/lucasmazza/ruby-stylus)\n\n### CMS Support\n\n - [DocPad](https://github.com/bevry/docpad)\n - [Punch](https://github.com/laktek/punch-stylus-compiler)\n\n### Screencasts\n\n - [Stylus Intro](http://screenr.com/bNY)\n - [CSS Syntax & Postfix Conditionals](http://screenr.com/A8v)\n\n### Authors\n\n - [TJ Holowaychuk (visionmedia)](http://github.com/visionmedia)\n\n### More Information\n\n - Language [comparisons](docs/compare.md)\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2010 LearnBoost <dev@learnboost.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/LearnBoost/stylus/issues" + }, + "_id": "stylus@0.35.1", + "dist": { + "shasum": "83f207501cdbbedd6e761bf0f35be4e463475ce0" + }, + "_from": "stylus@~0.35.1", + "_resolved": "https://registry.npmjs.org/stylus/-/stylus-0.35.1.tgz" +} diff --git a/node_modules/nib/package.json b/node_modules/nib/package.json new file mode 100644 index 0000000..8a37661 --- /dev/null +++ b/node_modules/nib/package.json @@ -0,0 +1,41 @@ +{ + "name": "nib", + "description": "Stylus mixins and utilities", + "version": "1.0.1", + "repository": { + "type": "git", + "url": "git://github.com/visionmedia/nib.git" + }, + "dependencies": { + "stylus": "~0.35.1" + }, + "devDependencies": { + "connect": "1.x", + "jade": "0.22.0", + "mocha": "*", + "should": "*" + }, + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "main": "lib/nib.js", + "engines": { + "node": "*" + }, + "scripts": { + "test": "mocha", + "test-server": "node test/server.js" + }, + "readme": "[![Build Status](https://travis-ci.org/visionmedia/nib.png?branch=master)](https://travis-ci.org/visionmedia/nib)\n\n# Nib\n\n Stylus mixins, utilities, components, and gradient image generation. Don't forget to check out the [documentation](http://visionmedia.github.com/nib/).\n\n## Installation\n\n```bash\n$ npm install nib\n```\n\n If the image generation features of Nib are desired, such as generating the linear gradient images, install [node-canvas](http://github.com/learnboost/node-canvas):\n \n```bash \n$ npm install canvas\n```\n\n## JavaScript API\n\n Below is an example of how to utilize nib and stylus with the connect framework (or express).\n\n```javascript\nvar connect = require('connect')\n , stylus = require('stylus')\n , nib = require('nib');\n\nvar server = connect();\n\nfunction compile(str, path) {\n return stylus(str)\n\t.set('filename', path)\n\t.set('compress', true)\n\t.use(nib());\n}\n\nserver.use(stylus.middleware({\n\tsrc: __dirname\n , compile: compile\n}));\n```\n\n## Stylus API\n\n To gain access to everything nib has to offer, simply add:\n\n ```css\n @import 'nib'\n ```\n \n Or you may also pick and choose based on the directory structure in `./lib`, for example:\n \n ```css\n @import 'nib/gradients'\n @import 'nib/overflow'\n ```\n \nto be continued....\n\n## More Information\n\n - Introduction [screencast](http://www.screenr.com/M6a)\n\n## Testing\n\n You will first need to install the dependencies:\n \n ```bash\n $ npm install -d\n ```\n \n Run the automated test cases:\n \n ```bash\n $ npm test\n ```\n \n For visual testing run the test server:\n \n ```bash\n $ npm run-script test-server\n ```\n \n Then visit `localhost:3000` in your browser.\n\n## Contributors\n\nI would love more contributors. And if you have helped out, you are awesome! I want to give a huge thanks to these people:\n\n - [TJ Holowaychuk](https://github.com/visionmedia) (Original Creator)\n - [Sean Lang](https://github.com/slang800) (Current Maintainer)\n - [Isaac Johnston](https://github.com/superstructor)\n - [Everyone Else](https://github.com/visionmedia/nib/contributors)\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/nib/issues" + }, + "_id": "nib@1.0.1", + "dist": { + "shasum": "665265181801a37b1cfb4880ddc699f3b6bdef33" + }, + "_from": "nib@1.0.x", + "_resolved": "https://registry.npmjs.org/nib/-/nib-1.0.1.tgz" +} diff --git a/node_modules/node-redis/.npmignore b/node_modules/node-redis/.npmignore new file mode 100644 index 0000000..95923ab --- /dev/null +++ b/node_modules/node-redis/.npmignore @@ -0,0 +1 @@ +bench* diff --git a/node_modules/node-redis/README b/node_modules/node-redis/README new file mode 100644 index 0000000..50bcf53 --- /dev/null +++ b/node_modules/node-redis/README @@ -0,0 +1,26 @@ +node-redis +========== + +A redis client. + +Usage +----- + + var redis = require('node-redis') + + var client = redis.createClient(port, host, auth) + + client.get('key', function (error, buffer) { ... }) + + client.multi() + client.lrange('key', 0, -1) + client.lrange('key', [0, -1]) + client.exec(function (error, result) { result[0]; result[1] }) + + client.subscribe('channel') + client.on('message', function (buffer) { ... }) + client.on('message:channel', function (buffer) { ... }) + client.unsubscribe('channel') + + client.end() + diff --git a/node_modules/node-redis/index.js b/node_modules/node-redis/index.js new file mode 100644 index 0000000..be65294 --- /dev/null +++ b/node_modules/node-redis/index.js @@ -0,0 +1,419 @@ +// The MIT License +// +// Copyright (c) 2013 Tim Smart +// +// 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. + +var net = require('net'), + utils = require('./utils'), + Parser = require('./parser'); + +var RedisClient = function RedisClient(port, host, auth) { + this.host = host; + this.port = port; + this.auth = auth; + this.stream = net.createConnection(port, host); + this.connected = false; + // Pub/sub monitor etc. + this.blocking = false; + // Command queue. + this.max_size = 1300; + this.command = ''; + this.commands = new utils.Queue(); + // For the retry timer. + this.retry = false; + this.retry_attempts = 0; + this.retry_delay = 250; + this.retry_backoff = 1.7; + // If we want to quit. + this.quitting = false; + // For when we have a full send buffer. + this.paused = false; + this.send_buffer = []; + this.flushing = false; + // channels / patterns for disconnects + this.pubsub = { pattern : {}, channel : {} } + + var self = this; + + this.stream.on("connect", function () { + // Reset the retry backoff. + self.retry = false; + self.retry_delay = 250; + self.retry_attempts = 0; + self.stream.setNoDelay(); + self.stream.setTimeout(0); + self.connected = true; + + // Resend commands if we need to. + var command, + commands = self.commands.array.slice(self.commands.offset); + + // Send auth. + if (self.auth) { + commands.unshift(['AUTH', [self.auth], null]); + } + + self.commands = new utils.Queue(); + + for (var i = 0, il = commands.length; i < il; i++) { + command = commands[i]; + self.sendCommand(command[0], command[1], command[2]); + } + + // pubsub? + var patterns = Object.keys(self.pubsub.pattern) + var channels = Object.keys(self.pubsub.channel) + + for (var i = 0, il = patterns.length; i < il; i++) { + self.psubscribe(patterns[i]) + } + for (var i = 0, il = channels.length; i < il; i++) { + self.subscribe(channels[i]) + } + + // give connect listeners a chance to run first in case they need to auth + self.emit("connect"); + }); + + this.stream.on("data", function (buffer) { + try { + self.parser.onIncoming(buffer); + } catch (err) { + self.emit("error", err); + // Reset state. + self.parser.resetState(); + } + }); + + // _write + // So we can pipeline requests. + this._flush = function () { + if ('' !== self.command) { + self.send_buffer.push(self.command); + self.command = ''; + } + + for (var i = 0, il = self.send_buffer.length; i < il; i++) { + if (!self.stream.writable || false === self.stream.write(self.send_buffer[i])) { + return self.send_buffer = self.send_buffer.slice(i + 1); + } + } + + self.send_buffer.length = 0; + self.paused = self.flushing = false; + }; + + // When we can write more. + this.stream.on('drain', this._flush); + + this.stream.on("error", function (error) { + if ('ECONNREFUSED' === error.code) self.onDisconnect() + self.emit("error", error); + }); + + var onClose = function onClose () { + // Ignore if we are already retrying. Or we want to quit. + if (self.retry) return; + self.emit('end'); + self.emit('close'); + if (self.quitting) { + for (var i = 0, il = self.commands.length; i < il; i++) { + self.parser.emit('reply'); + } + return; + } + + self.onDisconnect(); + }; + + this.stream.on("end", onClose); + this.stream.on("close", onClose); + + // Setup the parser. + this.parser = new Parser(); + + this.parser.on('reply', function onReply (reply) { + if (false !== self.blocking) { + if ('pubsub' === self.blocking) { + var type = reply[0].toString(); + + switch (type) { + case 'psubscribe': + case 'punsubscribe': + case 'subscribe': + case 'unsubscribe': + var channel = reply[1].toString(), + count = reply[2]; + + if (0 === count) { + self.blocking = false; + + if ('punsubscribe' === type) { + delete self.pubsub.pattern[channel] + } else if ('unsubscribe' === type) { + delete self.pubsub.channel[channel] + } + } + + if ('psubscribe' === type) { + self.pubsub.pattern[channel] = true + } else if ('subscribe' === type) { + self.pubsub.channel[channel] = true + } + + self.emit(type, channel, count); + self.emit(type + ':' + channel, count); + break; + case 'message': + var key = reply[1].toString(), + data = reply[2]; + self.emit('message', key, data); + self.emit('message:' + key, data); + break; + case 'pmessage': + var pattern = reply[1].toString(), + key = reply[2].toString(), + data = reply[3]; + self.emit('pmessage', pattern, key, data); + self.emit('pmessage:' + pattern, key, data); + break; + } + } else { + self.emit('data', reply); + } + return; + } + + var command = self.commands.shift(); + if (command) { + switch (command[0]) { + case 'MONITOR': + self.blocking = true; + break; + case 'SUBSCRIBE': + case 'PSUBSCRIBE': + self.blocking = 'pubsub'; + onReply(reply); + return; + } + + if (command[2]) { + command[2](null, reply); + } + } + }); + + // DB error + this.parser.on('error', function (error) { + var command = self.commands.shift(); + error = new Error(error); + if (command && command[2]) command[2](error); + else self.emit('error', error); + }); + + process.EventEmitter.call(this); +}; + +RedisClient.prototype = Object.create(process.EventEmitter.prototype); + +// Exports +exports.RedisClient = RedisClient; + +// createClient +exports.createClient = function createClient (port, host, auth) { + return new RedisClient(port || 6379, host, auth); +}; + +RedisClient.prototype.connect = function () { + return this.stream.connect(); +}; + +RedisClient.prototype.onDisconnect = function (error) { + var self = this; + + // Make sure the stream is reset. + this.connected = false; + this.stream.destroy(); + this.parser.resetState(); + + // Increment the attempts, so we know what to set the timeout to. + this.retry_attempts++; + + // Set the retry timer. + setTimeout(function () { + self.stream.connect(self.port, self.host); + }, this.retry_delay); + + this.retry_delay *= this.retry_backoff; + this.retry = true; +}; + +RedisClient.prototype._write = function (data) { + if (!this.paused) { + if (false === this.stream.write(data)) { + this.paused = true; + } + } else { + this.send_buffer.push(data); + } +}; + +// We use this so we can watch for a full send buffer. +RedisClient.prototype.write = function write (data, buffer) { + if (true !== buffer) { + this.command += data; + if (this.max_size <= this.command.length) { + this._write(this.command); + this.command = ''; + } + } else { + if ('' !== this.command) { + this._write(this.command); + this.command = ''; + } + this._write(data); + } + + if (!this.flushing) { + process.nextTick(this._flush); + this.flushing = true; + } +}; + +// We make some assumptions: +// +// * command WILL be uppercase and valid. +// * args IS an array +RedisClient.prototype.sendCommand = function (command, args, callback) { + // Push the command to the stack. + if (false === this.blocking) { + this.commands.push([command, args, callback]); + } + + // Writable? + if (false === this.connected) return; + + // Do we have to send a multi bulk command? + // Assume it is a valid command for speed reasons. + var args_length; + + if (args && 0 < (args_length = args.length)) { + var arg, arg_type, last, + previous = ['*', (args_length + 1), '\r\n', '$', command.length, '\r\n', command, '\r\n']; + + for (i = 0, il = args_length; i < il; i++) { + arg = args[i]; + arg_type = typeof arg; + + if ('string' === arg_type) { + // We can send this in one go. + previous.push('$', Buffer.byteLength(arg), '\r\n', arg, '\r\n'); + } else if ('number' === arg_type) { + // We can send this in one go. + previous.push('$', ('' + arg).length, '\r\n', arg, '\r\n'); + } else if (null === arg || 'undefined' === arg_type) { + // Send NIL + previous.push('$\r\b\r\b') + this.write(previous.join('')); + previous = []; + } else { + // Assume we are a buffer. + previous.push('$', arg.length, '\r\n'); + this.write(previous.join('')); + this.write(arg, true); + previous = ['\r\n']; + } + } + + // Anything left? + this.write(previous.join('')); + } else { + // We are just sending a stand alone command. + this.write(command_buffers[command]); + } +}; + +RedisClient.prototype.destroy = function () { + this.quitting = true; + return this.stream.destroy(); +}; + +// http://redis.io/commands.json +exports.commands = [ + 'APPEND', 'AUTH', 'BGREWRITEAOF', 'BGSAVE', 'BLPOP', 'BRPOP', 'BRPOPLPUSH', 'CONFIG GET', + 'CONFIG SET', 'CONFIG RESETSTAT', 'DBSIZE', 'DEBUG OBJECT', 'DEBUG SEGFAULT', 'DECR', + 'DECRBY', 'DEL', 'DISCARD', 'ECHO', 'EXEC', 'EXISTS', 'EXPIRE', 'EXPIREAT', 'FLUSHALL', + 'FLUSHDB', 'GET', 'GETBIT', 'GETRANGE', 'GETSET', 'HDEL', 'HEXISTS', 'HGET', 'HGETALL', + 'HINCRBY', 'HKEYS', 'HLEN', 'HMGET', 'HMSET', 'HSET', 'HSETNX', 'HVALS', 'INCR', 'INCRBY', + 'INFO', 'KEYS', 'LASTSAVE', 'LINDEX', 'LINSERT', 'LLEN', 'LPOP', 'LPUSH', 'LPUSHX', 'LRANGE', + 'LREM', 'LSET', 'LTRIM', 'MGET', 'MONITOR', 'MOVE', 'MSET', 'MSETNX', 'MULTI', 'PERSIST', + 'PING', 'PSUBSCRIBE', 'PUBLISH', 'PUNSUBSCRIBE', 'QUIT', 'RANDOMKEY', 'RENAME', 'RENAMENX', + 'RPOP', 'RPOPLPUSH', 'RPUSH', 'RPUSHX', 'SADD', 'SAVE', 'SCARD', 'SDIFF', 'SDIFFSTORE', 'SELECT', + 'SET', 'SETBIT', 'SETEX', 'SETNX', 'SETRANGE', 'SHUTDOWN', 'SINTER', 'SINTERSTORE', 'SISMEMBER', + 'SLAVEOF', 'SMEMBERS', 'SMOVE', 'SORT', 'SPOP', 'SRANDMEMBER', 'SREM', 'STRLEN', 'SUBSCRIBE', + 'SUNION', 'SUNIONSTORE', 'SYNC', 'TTL', 'TYPE', 'UNSUBSCRIBE', 'UNWATCH', 'WATCH', 'ZADD', + 'ZCARD', 'ZCOUNT', 'ZINCRBY', 'ZINTERSTORE', 'ZRANGE', 'ZRANGEBYSCORE', 'ZRANK', 'ZREM', + 'ZREMRANGEBYRANK', 'ZREMRANGEBYSCORE', 'ZREVRANGE', 'ZREVRANGEBYSCORE', 'ZREVRANK', 'ZSCORE', + 'ZUNIONSTORE' +]; + +this.blocking_commands = ["MONITOR"]; + +// For each command, make a buffer for it. +var command_buffers = {}; + +exports.commands.forEach(function (command) { + // Pre-alloc buffers for non-multi commands. + //command_buffers[command] = new Buffer('*1\r\n$' + command.length + '\r\n' + command + '\r\n'); + command_buffers[command] = '*1\r\n$' + command.length + '\r\n' + command + '\r\n'; + + // Don't override stuff. + if (!RedisClient.prototype[command.toLowerCase()]) { + RedisClient.prototype[command.toLowerCase()] = function (array, callback) { + // An array of args. + // Assume we only have two args. + if (Array.isArray(array)) { + return this.sendCommand(command, array, callback); + } + + // Arbitary amount of arguments. + var args = []; + args.push.apply(args, arguments); + callback = 'function' === typeof args[args.length - 1]; + + if (callback) { + callback = args.pop(); + } else { + callback = null; + } + + this.sendCommand(command, args, callback); + }; + } +}); + +// Overwrite quit +RedisClient.prototype.quit = RedisClient.prototype.end = +function (callback) { + this.quitting = true; + return this.sendCommand('QUIT', null, callback); +}; + diff --git a/node_modules/node-redis/package.json b/node_modules/node-redis/package.json new file mode 100644 index 0000000..f4ed96b --- /dev/null +++ b/node_modules/node-redis/package.json @@ -0,0 +1,32 @@ +{ + "name": "node-redis", + "description": "Lightweight, fast, Redis client.", + "version": "0.1.7", + "author": { + "name": "Tim Smart" + }, + "contributors": [ + { + "name": "Matt Ranney" + } + ], + "repository": { + "type": "git", + "url": "http://github.com/Tim-Smart/node-redis.git" + }, + "engine": [ + "node >=0.8" + ], + "main": "./", + "readme": "node-redis\n==========\n\nA redis client.\n\nUsage\n-----\n\n var redis = require('node-redis')\n\n var client = redis.createClient(port, host, auth)\n\n client.get('key', function (error, buffer) { ... })\n\n client.multi()\n client.lrange('key', 0, -1)\n client.lrange('key', [0, -1])\n client.exec(function (error, result) { result[0]; result[1] })\n\n client.subscribe('channel')\n client.on('message', function (buffer) { ... })\n client.on('message:channel', function (buffer) { ... })\n client.unsubscribe('channel')\n\n client.end()\n\n", + "readmeFilename": "README", + "bugs": { + "url": "https://github.com/Tim-Smart/node-redis/issues" + }, + "_id": "node-redis@0.1.7", + "dist": { + "shasum": "b62d8c4fcbcdbf1137e1fa7dfd9148ebb6376ea8" + }, + "_from": "node-redis@0.1.x", + "_resolved": "https://registry.npmjs.org/node-redis/-/node-redis-0.1.7.tgz" +} diff --git a/node_modules/node-redis/parser.js b/node_modules/node-redis/parser.js new file mode 100644 index 0000000..5a65cfb --- /dev/null +++ b/node_modules/node-redis/parser.js @@ -0,0 +1,379 @@ +// The MIT License +// +// Copyright (c) 2013 Tim Smart +// +// 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. + +var utils = require('./utils'); + +var RedisParser = function RedisParser () { + this.resetState(); + + process.EventEmitter.call(this); + + return this; +}; + +module.exports = RedisParser; + +RedisParser.prototype = Object.create(process.EventEmitter.prototype); + +// Reset state, no matter where we are at. +RedisParser.prototype.resetState = function resetState () { + this.reply = null; + this.expected = null; + this.multi = null; + this.replies = null; + this.pos = null; + this.flag = 'TYPE'; + this.data = null; + this.last_data = null; + this.remaining = null; +}; + +// Handle an incoming buffer. +RedisParser.prototype.onIncoming = function onIncoming (buffer) { + var char_code, + pos = this.pos || 0, + length = buffer.length; + + // Make sure the buffer is joint properly. + if ('TYPE' !== this.flag && 'BULK' !== this.flag && null !== this.data) { + // We need to wind back a step. + // If we have CR now, it would break the parser. + if (0 !== this.data.length) { + char_code = this.data.charCodeAt(this.data.length - 1); + this.data = this.data.slice(0, -1); + --pos; + } else { + char_code = buffer[pos]; + } + } + + for (; length > pos;) { + switch (this.flag) { + case 'TYPE': + // What are we doing next? + switch (buffer[pos++]) { + // Single line status reply. + case 43: // + SINGLE + this.flag = 'SINGLE'; + break; + + // Tells us the length of upcoming data. + case 36: // $ LENGTH + this.flag = 'BULK_LENGTH'; + break; + + // Tells us how many args are coming up. + case 42: // * MULTI + this.flag = 'MULTI_BULK'; + break; + + case 58: // : INTEGER + this.flag = 'INTEGER'; + break; + + // Errors + case 45: // - ERROR + this.flag = 'ERROR'; + break; + } + // Fast forward a char. + char_code = buffer[pos]; + this.data = ''; + break; + + // Single line status replies. + case 'SINGLE': + case 'ERROR': + // Add char to the data + this.data += String.fromCharCode(char_code); + pos++; + + // Optimize for the common use case. + if ('O' === this.data && 75 === buffer[pos]) { // OK + // Send off the reply. + this.data = 'OK'; + this.onData(); + + pos += 3; // Skip the `K\r\n` + + // break early. + break; + } + + // Otherwise check for CR + char_code = buffer[pos]; + if (13 === char_code) { // \r CR + // Send the reply. + if ('SINGLE' === this.flag) { + this.onData(); + } else { + this.onError(); + } + + // Skip \r\n + pos += 2; + } + break; + + // We have a integer coming up. Look for a CR + // then assume that is the end. + case 'BULK_LENGTH': + // We are still looking for more digits. + // char_code already set by TYPE state. + this.data += String.fromCharCode(char_code); + pos++; + + // Is the next char the end? Set next char_code while + // we are at it. + char_code = buffer[pos]; + if (13 === char_code) { // \r CR + // Cast to int + this.data = +this.data; + + // Null reply? + if (-1 !== this.data) { + this.flag = 'BULK'; + this.last_data = this.data; + this.data = null; + } else { + this.data = null; + this.onData(); + } + + // Skip the \r\n + pos += 2; + } + break; + + // Short bulk reply. + case 'BULK': + if (null === this.data && length >= (pos + this.last_data)) { + // Slow slice is slow. + if (14 > this.last_data) { + this.data = new Buffer(this.last_data); + for (var i = 0; i < this.last_data; i++) { + this.data[i] = buffer[i + pos]; + } + } else { + this.data = buffer.slice(pos, this.last_data + pos); + } + + // Fast forward past data. + pos += this.last_data + 2; + + // Send it off. + this.onData(); + } else if (this.data) { + // Still joining. pos = amount left to go. + if (this.remaining <= length) { + // End is within this buffer. + if (13 < this.remaining) { + buffer.copy(this.data, this.last_data - this.remaining, 0, this.remaining) + } else { + utils.copyBuffer(buffer, this.data, this.last_data - this.remaining, 0, this.remaining); + } + + // Fast forward past data. + pos = this.remaining + 2; + this.remaining = null; + + this.onData(); + } else { + // We have more to come. Copy what we got then move on, + // decrementing the amount we have copied from this.remaining + if (13 < (this.remaining - length)) { + utils.copyBuffer(buffer, this.data, this.last_data - this.remaining, 0, length); + } else { + buffer.copy(this.data, this.last_data - this.remaining, 0, length); + } + + // More to go. + this.remaining -= length; + pos = length; + } + } else { + // We will have to do a join. + this.data = new Buffer(this.last_data); + + // Fast copy if small. + if (15 > this.last_data) { + utils.copyBuffer(buffer, this.data, 0, pos); + } else { + buffer.copy(this.data, 0, pos) + } + + // Point pos to the amount we need. + this.remaining = this.last_data - (length - pos); + pos = length; + } + break; + + // How many bulk's are coming? + case 'MULTI_BULK': + // We are still looking for more digits. + // char_code already set by TYPE state. + this.data += String.fromCharCode(char_code); + pos++; + + // Is the next char the end? Set next char_code while + // we are at it. + char_code = buffer[pos]; + if (13 === char_code) { // \r CR + // Cast to int + this.last_data = +this.data; + this.data = null; + + // Are we multi? + if (null === this.expected) { + this.expected = this.last_data; + this.reply = []; + } else if (null === this.multi) { + this.multi = this.expected; + this.expected = null; + this.replies = []; + } + + // Skip the \r\n + pos += 2; + this.flag = 'TYPE'; + + // Zero length replies. + if (0 === this.last_data) { + this.expected = this.reply = null; + this.data = []; + this.onData(); + break; + } else if (-1 === this.last_data) { + // NIL reply. + this.expected = this.reply = null; + this.data = null; + this.onData(); + break; + } + + char_code = buffer[pos]; + + // Will have to look ahead to check for another MULTI in case + // we are a multi transaction. + if (36 === char_code) { // $ - BULK_LENGTH + // We are bulk data. + this.flag = 'BULK_LENGTH'; + + // We are skipping the TYPE check. Skip the $ + pos++; + // We need to set char code and data. + char_code = buffer[pos]; + this.data = ''; + } else if (null === this.multi && char_code) { + // Multi trans time. + this.multi = this.expected; + this.expected = null; + this.replies = []; + } + } + break; + + case 'INTEGER': + // We are still looking for more digits. + // char_code already set by TYPE state. + this.data += String.fromCharCode(char_code); + pos++; + + // Is the next char the end? Set next char_code while + // we are at it. + char_code = buffer[pos]; + if (13 === char_code) { // \r CR + // Cast to int + this.data = +this.data; + this.onData(); + + // Skip the \r\n + pos += 2; + } + break; + } + } + + // In case we have multiple packets. + this.pos = pos - length; +}; + +// When we have recieved a chunk of response data. +RedisParser.prototype.onData = function onData () { + if (null !== this.expected) { + // Decrement the expected data replies and add the data. + this.reply.push(this.data); + this.expected--; + + // Finished? Send it off. + if (0 === this.expected) { + if (null !== this.multi) { + this.replies.push(this.reply); + this.multi--; + + if (0 === this.multi) { + this.emit('reply', this.replies); + this.replies = this.multi = null; + } + } else { + this.emit('reply', this.reply); + } + this.reply = this.expected = null; + } + } else { + if (null === this.multi) { + this.emit('reply', this.data); + } else { + this.replies.push(this.data); + this.multi--; + + if (0 === this.multi) { + this.emit('reply', this.replies); + this.replies = this.multi = null; + } + } + } + + this.last_data = null; + this.data = null; + this.flag = 'TYPE'; +}; + +// Found an error. +RedisParser.prototype.onError = function onError () { + if (null === this.multi) { + this.emit('error', this.data); + } else { + this.replies.push(this.data); + this.multi--; + + if (0 === this.multi) { + this.emit('reply', this.replies); + this.replies = this.multi = null; + } + } + + this.last_data = null; + this.data = null; + this.flag = 'TYPE'; +}; diff --git a/node_modules/node-redis/test/disconnect-pubsub.js b/node_modules/node-redis/test/disconnect-pubsub.js new file mode 100644 index 0000000..2fc855b --- /dev/null +++ b/node_modules/node-redis/test/disconnect-pubsub.js @@ -0,0 +1,6 @@ +var c = require('../').createClient() + +c.on('error', console.error) + +c.subscribe('channel') +c.psubscribe('pattern:*') diff --git a/node_modules/node-redis/test/main.js b/node_modules/node-redis/test/main.js new file mode 100644 index 0000000..a522131 --- /dev/null +++ b/node_modules/node-redis/test/main.js @@ -0,0 +1,94 @@ +var c = require('../').createClient(null, null, 'test'), + c2 = require('../').createClient(), + assert = require('assert'); + +var buffer = new Buffer(new Array(1025).join('x')); + +module.exports = { + "test basic commands": function (done) { + c.set('1', 'test'); + c.get('1', function (error, value) { + assert.ok(!error); + assert.equal(value, 'test'); + }); + + c.del('1', function (error) { + assert.ok(!error); + }); + + c.get('1', function (error, value) { + assert.ok(!error); + assert.isNull(value); + done(); + }); + + }, + "test stress": function (done) { + var n = 0, + o = 0; + + for (var i = 0; i < 10000; i++) { + c.set('2' + i, buffer, function (error) { + assert.ok(!error); + ++n; + }); + } + + for (i = 0; i < 10000; i++) { + c.del('2' + i, function (error) { + assert.ok(!error); + ++o; + }); + } + + c.ping(function (error) { + assert.ok(!error) + done() + }) + + process.on('exit', function () { + assert.equal(10000, n); + assert.equal(10000, o); + }); + }, + "test pubsub": function (done) { + c.subscribe('test'); + c.on('subscribe:test', function (count) { + assert.equal(1, count); + c2.publish('test', '123', function (error) { + assert.ok(!error); + }); + }); + c.on('message:test', function (data) { + assert.equal('123', data.toString()); + c.unsubscribe('test'); + }); + c.on('unsubscribe:test', function (count) { + assert.equal(0, count); + assert.equal(false, c.blocking); + c.ping(function (error) { + assert.ok(!error); + done(); + }); + }); + }, + "test monitor": function (done) { + c.monitor(); + c.once('data', function (data) { + assert.ok(/MONITOR/.test(data)); + c.once('data', function (data) { + assert.ok(/SET/.test(data)); + c.once('data', function (data) { + assert.ok(/DEL/.test(data)); + done(); + }); + }); + }); + c2.set('test', 123); + c2.del('test'); + }, + after: function () { + c.quit(); + c2.quit(); + } +}; diff --git a/node_modules/node-redis/utils.js b/node_modules/node-redis/utils.js new file mode 100644 index 0000000..52eb029 --- /dev/null +++ b/node_modules/node-redis/utils.js @@ -0,0 +1,113 @@ +// The MIT License +// +// Copyright (c) 2013 Tim Smart +// +// 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. + +// noop to keep references low. +exports.noop = function () {}; + +// Logger function. +exports.log = function log (error, results) { + if (error) return console.error(error); + + var ret; + + if (results instanceof Array) { + var result; + ret = []; + + for (var i = 0, il = results.length; i < il; i++) { + result = results[i]; + + if (result instanceof Buffer) { + ret.push(result.toString()); + } else { + ret.push(result); + } + } + } else if (results instanceof Buffer) { + ret = results.toString(); + } else ret = results; + + console.log(ret); +}; + +// Fast copyBuffer method for small buffers. +exports.copyBuffer = function copyBuffer (source, target, start, s_start, s_end) { + s_end || (s_end = source.length); + + for (var i = s_start; i < s_end; i++) { + target[i - s_start + start] = source[i]; + } + + return target; +}; + +// Fast write buffer for small uns. +var writeBuffer = exports.writeBuffer = function writeBuffer (buffer, string, offset) { + for (var i = 0, il = string.length; i < il; i++) { + buffer[i + offset] = string.charCodeAt(i); + } + + return il; +}; + +var toArray = exports.toArray = function toArray (args) { + var len = args.length, + arr = new Array(len), i; + + for (i = 0; i < len; i++) { + arr[i] = args[i]; + } + + return arr; +}; + +// Queue class adapted from Tim Caswell's pattern library +// http://github.com/creationix/pattern/blob/master/lib/pattern/queue.js +var Queue = function () { + this.array = Array.prototype.slice.call(arguments); + this.offset = 0; +}; + +exports.Queue = Queue; + +Queue.prototype.shift = function () { + if (this.array.length === 0) return; + var ret = this.array[this.offset]; + this.array[this.offset++] = undefined; + if (this.offset === this.array.length) { + this.array.length = 0; + this.offset = 0; + } + return ret; +} + +Queue.prototype.push = function (item) { + return this.array.push(item); +}; + +Object.defineProperty(Queue.prototype, 'length', { + get: function () { + return this.array.length; + } +}); +; diff --git a/node_modules/stylus/LICENSE b/node_modules/stylus/LICENSE new file mode 100644 index 0000000..a206b68 --- /dev/null +++ b/node_modules/stylus/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2010 LearnBoost + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/stylus/Readme.md b/node_modules/stylus/Readme.md new file mode 100644 index 0000000..01d8d54 --- /dev/null +++ b/node_modules/stylus/Readme.md @@ -0,0 +1,163 @@ +# Stylus [![Build Status](https://travis-ci.org/LearnBoost/stylus.png?branch=master)](https://travis-ci.org/LearnBoost/stylus) + + Stylus is a revolutionary new language, providing an efficient, dynamic, and expressive way to generate CSS. Supporting both an indented syntax and regular CSS style. + +## Installation + +```bash +$ npm install stylus +``` + +### Example + +``` +border-radius() + -webkit-border-radius: arguments + -moz-border-radius: arguments + border-radius: arguments + +body a + font: 12px/1.4 "Lucida Grande", Arial, sans-serif + background: black + color: #ccc + +form input + padding: 5px + border: 1px solid + border-radius: 5px +``` + +compiles to: + +```css +body a { + font: 12px/1.4 "Lucida Grande", Arial, sans-serif; + background: #000; + color: #ccc; +} +form input { + padding: 5px; + border: 1px solid; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +``` + +the following is equivalent to the indented version of Stylus source, using the CSS syntax instead: + +``` +border-radius() { + -webkit-border-radius: arguments + -moz-border-radius: arguments + border-radius: arguments +} + +body a { + font: 12px/1.4 "Lucida Grande", Arial, sans-serif; + background: black; + color: #ccc; +} + +form input { + padding: 5px; + border: 1px solid; + border-radius: 5px; +} +``` + +### Features + + Stylus has _many_ features. Detailed documentation links follow: + + - [css syntax](docs/css-style.md) support + - [mixins](docs/mixins.md) + - [keyword arguments](docs/kwargs.md) + - [variables](docs/variables.md) + - [interpolation](docs/interpolation.md) + - arithmetic, logical, and equality [operators](docs/operators.md) + - [importing](docs/import.md) of other stylus sheets + - [introspection api](docs/introspection.md) + - type coercion + - [@extend](docs/extend.md) + - [conditionals](docs/conditionals.md) + - [iteration](docs/iteration.md) + - nested [selectors](docs/selectors.md) + - parent reference + - in-language [functions](docs/functions.md) + - [variable arguments](docs/vargs.md) + - built-in [functions](docs/bifs.md) (over 25) + - optional [image inlining](docs/functions.url.md) + - optional compression + - JavaScript [API](docs/js.md) + - extremely terse syntax + - stylus [executable](docs/executable.md) + - [error reporting](docs/error-reporting.md) + - single-line and multi-line [comments](docs/comments.md) + - css [literal](docs/literal.md) + - character [escaping](docs/escape.md) + - [@keyframes](docs/keyframes.md) support & expansion + - [@font-face](docs/font-face.md) support + - [@media](docs/media.md) support + - Connect [Middleware](docs/middleware.md) + - TextMate [bundle](docs/textmate.md) + - Coda/SubEtha Edit [Syntax mode](https://github.com/atljeremy/Stylus.mode) + - gedit [language-spec](docs/gedit.md) + - VIM [Syntax](https://github.com/wavded/vim-stylus) + - [Firebug extension](docs/firebug.md) + - heroku [web service](http://styl.heroku.com) for compiling stylus + - [style guide](https://github.com/lepture/ganam) parser and generator + - transparent vendor-specific function expansion + +### Community modules + + - https://github.com/LearnBoost/stylus/wiki + +### Framework Support + + - [Connect](docs/middleware.md) + - [Play! 2.0](https://github.com/patiencelabs/play-stylus) + - [Ruby On Rails](https://github.com/lucasmazza/ruby-stylus) + +### CMS Support + + - [DocPad](https://github.com/bevry/docpad) + - [Punch](https://github.com/laktek/punch-stylus-compiler) + +### Screencasts + + - [Stylus Intro](http://screenr.com/bNY) + - [CSS Syntax & Postfix Conditionals](http://screenr.com/A8v) + +### Authors + + - [TJ Holowaychuk (visionmedia)](http://github.com/visionmedia) + +### More Information + + - Language [comparisons](docs/compare.md) + +## License + +(The MIT License) + +Copyright (c) 2010 LearnBoost <dev@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/node_modules/stylus/bin/stylus b/node_modules/stylus/bin/stylus new file mode 100755 index 0000000..ebec6a8 --- /dev/null +++ b/node_modules/stylus/bin/stylus @@ -0,0 +1,650 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var fs = require('fs') + , stylus = require('../lib/stylus') + , basename = require('path').basename + , dirname = require('path').dirname + , resolve = require('path').resolve + , join = require('path').join + , isWindows = process.platform === 'win32'; + +/** + * Arguments. + */ + +var args = process.argv.slice(2); + +/** + * Compare flag. + */ + +var compare = false; + +/** + * Compress flag. + */ + +var compress = false; + +/** + * CSS conversion flag. + */ + +var convertCSS = false; + +/** + * Line numbers flag. + */ + +var linenos = false; + +/** + * Print to stdout flag. + */ +var print = false; + +/** + * Firebug flag + */ + +var firebug = false; + +/** + * Files to processes. + */ + +var files = []; + +/** + * Import paths. + */ + +var paths = []; + +/** + * Destination directory. + */ + +var dest; + +/** + * Watcher hash. + */ + +var watchers; + +/** + * Enable REPL. + */ + +var interactive; + +/** + * Plugins. + */ + +var plugins = []; + +/** + * Optional url() function. + */ + +var urlFunction = false; + +/** + * Include CSS on import. + */ + +var includeCSS = false; + +/** + * Set file imports. + */ + +var imports = []; + +/** + * Resolve relative urls + */ + +var resolveURL = false; + +/** + * Usage docs. + */ + +var usage = [ + '' + , ' Usage: stylus [options] [command] [< in [> out]]' + , ' [file|dir ...]' + , '' + , ' Commands:' + , '' + , ' help [:] Opens help info at MDC for in' + , ' your default browser. Optionally' + , ' searches other resources of :' + , ' safari opera w3c ms caniuse quirksmode' + , '' + , ' Options:' + , '' + , ' -i, --interactive Start interactive REPL' + , ' -u, --use Utilize the Stylus plugin at ' + , ' -U, --inline Utilize image inlining via data URI support' + , ' -w, --watch Watch file(s) for changes and re-compile' + , ' -o, --out Output to when passing files' + , ' -C, --css [dest] Convert CSS input to Stylus' + , ' -I, --include Add to lookup paths' + , ' -c, --compress Compress CSS output' + , ' -d, --compare Display input along with output' + , ' -f, --firebug Emits debug infos in the generated CSS that' + , ' can be used by the FireStylus Firebug plugin' + , ' -l, --line-numbers Emits comments in the generated CSS' + , ' indicating the corresponding Stylus line' + , ' -p, --print Print out the compiled CSS' + , ' --import Import stylus ' + , ' --include-css Include regular CSS on @import' + , ' -r, --resolve-url Resolve relative urls inside imports' + , ' -V, --version Display the version of Stylus' + , ' -h, --help Display help information' + , '' +].join('\n'); + +/** + * Handle arguments. + */ + +var arg; +while (args.length) { + arg = args.shift(); + switch (arg) { + case '-h': + case '--help': + console.error(usage); + process.exit(1); + case '-d': + case '--compare': + compare = true; + break; + case '-c': + case '--compress': + compress = true; + break; + case '-C': + case '--css': + convertCSS = true; + break; + case '-f': + case '--firebug': + firebug = true; + break; + case '-l': + case '--line-numbers': + linenos = true; + break; + case '-p': + case '--print': + print = true; + break; + case '-V': + case '--version': + console.log(stylus.version); + process.exit(0); + break; + case '-o': + case '--out': + dest = args.shift(); + if (!dest) throw new Error('--out required'); + break; + case 'help': + var name = args.shift() + , browser = name.split(':'); + if (browser.length > 1) { + name = [].slice.call(browser, 1).join(':'); + browser = browser[0]; + } else { + name = browser[0]; + browser = ''; + } + if (!name) throw new Error('help required'); + help(name); + break; + case '--include-css': + includeCSS = true; + break; + case '-i': + case '--repl': + case '--interactive': + interactive = true; + break; + case '-I': + case '--include': + var path = args.shift(); + if (!path) throw new Error('--include required'); + paths.push(path); + break; + case '-w': + case '--watch': + watchers = {}; + break; + case '-U': + case '--inline': + args.unshift('--use', 'url'); + break; + case '-u': + case '--use': + var options; + var path = args.shift(); + if (!path) throw new Error('--use required'); + + // options + if ('--with' == args[0]) { + args.shift(); + options = args.shift(); + if (!options) throw new Error('--with required'); + options = eval('(' + options + ')'); + } + + // url support + if ('url' == path) { + urlFunction = options || {}; + } else { + paths.push(dirname(path)); + plugins.push({ path: path, options: options }); + } + break; + case '--import': + var file = args.shift(); + if (!file) throw new Error('--import required'); + imports.push(file); + break; + case '-r': + case '--resolve-url': + resolveURL = true; + break; + default: + files.push(arg); + } +} + +// if --watch is used, assume we are +// not working with stdio + +if (watchers && !files.length) { + files = fs.readdirSync(process.cwd()) + .filter(function(file){ + return file.match(/\.styl$/); + }); +} + +/** + * Open the default browser to the CSS property `name`. + * + * @param {String} name + */ + +function help(name) { + var url + , exec = require('child_process').exec + , command; + + name = encodeURIComponent(name); + + switch (browser) { + case 'safari': + case 'webkit': + url = 'https://developer.apple.com/library/safari/search/?q=' + name; + break; + case 'opera': + url = 'http://dev.opera.com/search/?term=' + name; + break; + case 'w3c': + url = 'http://www.google.com/search?q=site%3Awww.w3.org%2FTR+' + name; + break; + case 'ms': + url = 'http://social.msdn.microsoft.com/search/en-US/ie?query=' + name + '&refinement=59%2c61'; + break; + case 'caniuse': + url = 'http://caniuse.com/#search=' + name; + break; + case 'quirksmode': + url = 'http://www.google.com/search?q=site%3Awww.quirksmode.org+' + name; + break; + default: + url = 'https://developer.mozilla.org/en/CSS/' + name; + } + + switch (process.platform) { + case 'linux': command = 'x-www-browser'; break; + default: command = 'open'; + } + + exec(command + ' "' + url + '"', function(){ + process.exit(0); + }); +} + +// Compilation options + +var options = { + filename: 'stdin' + , compress: compress + , firebug: firebug + , linenos: linenos + , paths: [process.cwd()].concat(paths) +}; + +// Buffer stdin + +var str = ''; + +// Convert CSS to Stylus + +if (convertCSS) { + switch (files.length) { + case 2: + compileCSSFile(files[0], files[1]); + break; + case 1: + compileCSSFile(files[0], files[0].replace('.css', '.styl')); + break; + default: + var stdin = process.openStdin(); + stdin.setEncoding('utf8'); + stdin.on('data', function(chunk){ str += chunk; }); + stdin.on('end', function(){ + var out = stylus.convertCSS(str); + console.log(out); + }); + } +} else if (interactive) { + repl(); +} else { + if (files.length) { + compileFiles(files); + } else { + compileStdio(); + } +} + +/** + * Start Stylus REPL. + */ + +function repl() { + var options = { filename: 'stdin', imports: [join(__dirname, '..', 'lib', 'functions')] } + , parser = new stylus.Parser('', options) + , evaluator = new stylus.Evaluator(parser.parse(), options) + , rl = require('readline') + , repl = rl.createInterface(process.stdin, process.stdout, autocomplete) + , global = evaluator.global.scope; + + // expose BIFs + evaluator.evaluate(); + + // readline + repl.setPrompt('> '); + repl.prompt(); + + // HACK: flat-list auto-complete + function autocomplete(line){ + var out = process.stdout + , keys = Object.keys(global.locals) + , len = keys.length + , words = line.split(/\s+/) + , word = words.pop() + , names = [] + , name + , node + , key; + + // find words that match + for (var i = 0; i < len; ++i) { + key = keys[i]; + if (0 == key.indexOf(word)) { + node = global.lookup(key); + switch (node.nodeName) { + case 'function': + names.push(node.toString()); + break; + default: + names.push(key); + } + } + } + + return [names, line]; + }; + + repl.on('line', function(line){ + if (!line.trim().length) return repl.prompt(); + parser = new stylus.Parser(line, options); + parser.state.push('expression'); + evaluator.return = true; + try { + var expr = parser.parse(); + var ret = evaluator.visit(expr); + ret = ret.nodes[ret.nodes.length - 1]; + ret = ret.toString(); + if ('(' == ret[0]) ret = ret.replace(/^\(|\)$/g, ''); + console.log('\033[90m=> \033[0m' + highlight(ret)); + repl.prompt(); + } catch (err) { + console.error('\033[31merror: %s\033[0m', err.message || err.stack); + repl.prompt(); + } + }); + + repl.on('SIGINT', function(){ + console.log(); + process.exit(0); + }); +} + +/** + * Highlight the given string of Stylus. + */ + +function highlight(str) { + return str + .replace(/(#)?(\d+(\.\d+)?)/g, function($0, $1, $2){ + return $1 ? $0 : '\033[36m' + $2 + '\033[0m'; + }) + .replace(/(#[\da-fA-F]+)/g, '\033[33m$1\033[0m') + .replace(/('.*?'|".*?")/g, '\033[32m$1\033[0m'); +} + +/** + * Convert a CSS file to a Styl file + */ + +function compileCSSFile(file, fileOut) { + fs.lstat(file, function(err, stat){ + if (err) throw err; + if (stat.isFile()) { + fs.readFile(file, 'utf8', function(err, str){ + if (err) throw err; + var styl = stylus.convertCSS(str); + fs.writeFile(fileOut, styl, function(err){ + if (err) throw err; + }); + }); + } + }); +} + +/** + * Compile with stdio. + */ + +function compileStdio() { + process.stdin.setEncoding('utf8'); + process.stdin.on('data', function(chunk){ str += chunk; }); + process.stdin.on('end', function(){ + // Compile to css + var style = stylus(str, options); + if (includeCSS) style.set('include css', true); + if (resolveURL) style.set('resolve url', true); + usePlugins(style); + importFiles(style); + style.render(function(err, css){ + if (err) throw err; + if (compare) { + console.log('\n\x1b[1mInput:\x1b[0m'); + console.log(str); + console.log('\n\x1b[1mOutput:\x1b[0m'); + } + console.log(css); + if (compare) console.log(); + }); + }).resume(); +} + +/** + * Compile the given files. + */ + +function compileFiles(files) { + files.forEach(compileFile); +} + +/** + * Compile the given file. + */ + +function compileFile(file) { + // ensure file exists + fs.lstat(file, function(err, stat){ + if (err) throw err; + // file + if (stat.isFile()) { + fs.readFile(file, 'utf8', function(err, str){ + if (err) throw err; + options.filename = file; + options._imports = []; + var style = stylus(str, options); + if (includeCSS) style.set('include css', true); + if (resolveURL) style.set('resolve url', true); + + usePlugins(style); + importFiles(style); + style.render(function(err, css){ + watchImports(file, options._imports); + if (err) { + if (watchers) { + console.error(err.stack || err.message); + } else { + throw err; + } + } else { + writeFile(file, css); + } + }); + }); + // directory + } else if (stat.isDirectory()) { + fs.readdir(file, function(err, files){ + if (err) throw err; + files.filter(function(path){ + return path.match(/\.styl$/); + }).map(function(path){ + return join(file, path); + }).forEach(compileFile); + }); + } + }); +} + +/** + * Write the given CSS output. + */ + +function writeFile(file, css) { + // --print support + if (print) return process.stdout.write(css); + // --out support + var path = dest + ? join(dest, basename(file, '.styl') + '.css') + : file.replace('.styl', '.css'); + fs.writeFile(path, css, function(err){ + if (err) throw err; + console.log(' \033[90mcompiled\033[0m %s', path); + // --watch support + watch(file, compileFile); + }); +} + +/** + * Watch the given `file` and invoke `fn` when modified. + */ + +function watch(file, fn) { + // not watching + if (!watchers) return; + + // already watched + if (watchers[file]) return; + + // watch the file itself + watchers[file] = true; + console.log(' \033[90mwatching\033[0m %s', file); + // if is windows use fs.watch api instead + // TODO: remove watchFile when fs.watch() works on osx etc + if (isWindows) { + fs.watch(file, function(event) { + if (event === 'change') fn(file); + }); + } else { + fs.watchFile(file, { interval: 300 }, function(curr, prev) { + if (curr.mtime > prev.mtime) fn(file); + }); + } +} + +/** + * Watch `imports`, re-compiling `file` when they change. + */ + +function watchImports(file, imports) { + imports.forEach(function(imported){ + if (!imported.path) return; + watch(imported.path, function(){ + compileFile(file); + }); + }); +} + +/** + * Utilize plugins. + */ + +function usePlugins(style) { + plugins.forEach(function(plugin){ + var path = plugin.path; + var options = plugin.options; + fn = require(/^\.+\//.test(path) ? resolve(path) : path); + if ('function' != typeof fn) { + throw new Error('plugin ' + path + ' does not export a function'); + } + style.use(fn(options)); + }); + + if (urlFunction) { + style.define('url', stylus.url(urlFunction)); + } else if (resolveURL) { + style.define('url', stylus.resolver()); + } +} + +/** + * Imports the indicated files. + */ + +function importFiles(style) { + imports.forEach(function(file) { + style.import(file); + }); +} diff --git a/node_modules/stylus/bm.js b/node_modules/stylus/bm.js new file mode 100644 index 0000000..d767e9e --- /dev/null +++ b/node_modules/stylus/bm.js @@ -0,0 +1,63 @@ + +/** + * Module dependencies. + */ + +var stylus = require('./') + , fs = require('fs'); + +var times = ~~process.env.TIMES || 1 + , avgs = []; + +// test cases + +var cases = fs.readdirSync('test/cases').filter(function(file){ + return ~file.indexOf('.styl'); +}).map(function(file){ + return file.replace('.styl', ''); +}); + +console.log(); +cases.forEach(function(test){ + var name = test.replace(/[-.]/g, ' '); + var path = 'test/cases/' + test + '.styl'; + var styl = fs.readFileSync(path, 'utf8').replace(/\r/g, ''); + + var style = stylus(styl) + .set('filename', path) + .include(__dirname + '/test/images') + .include(__dirname + '/test/cases/import.basic') + .define('url', stylus.url()); + + if (~test.indexOf('compress')) style.set('compress', true); + + var runs = [] + , n = times + , start; + + while (n--) { + start = new Date; + style.render(function(err){ + if (err) throw err; + }); + runs.push(new Date - start); + } + + var avg = runs.reduce(function(sum, n){ + return sum + n; + }) / times; + + avgs.push(avg); + + // im cool like that + var avgavg = avgs.reduce(function(sum, n){ + return sum + n; + }) / avgs.length; + + if (avg > avgavg) { + console.log(' \033[31m%s \033[31m%dms \033[90m+%dms\033[0m', name, avg | 0, avg - avgavg | 0); + } else { + console.log(' \033[36m%s \033[90m%dms\033[0m', name, avg | 0); + } +}); +console.log(); \ No newline at end of file diff --git a/node_modules/stylus/index.js b/node_modules/stylus/index.js new file mode 100644 index 0000000..ab58d3e --- /dev/null +++ b/node_modules/stylus/index.js @@ -0,0 +1,4 @@ + +module.exports = process.env.STYLUS_COV + ? require('./lib-cov/stylus') + : require('./lib/stylus'); \ No newline at end of file diff --git a/node_modules/stylus/lib/browserify.js b/node_modules/stylus/lib/browserify.js new file mode 100644 index 0000000..83879b2 --- /dev/null +++ b/node_modules/stylus/lib/browserify.js @@ -0,0 +1,2 @@ + +module.exports = require('./stylus'); diff --git a/node_modules/stylus/lib/colors.js b/node_modules/stylus/lib/colors.js new file mode 100644 index 0000000..9f465a2 --- /dev/null +++ b/node_modules/stylus/lib/colors.js @@ -0,0 +1,156 @@ + +/*! + * Stylus - colors + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +module.exports = { + aliceblue: [240, 248, 255] + , antiquewhite: [250, 235, 215] + , aqua: [0, 255, 255] + , aquamarine: [127, 255, 212] + , azure: [240, 255, 255] + , beige: [245, 245, 220] + , bisque: [255, 228, 196] + , black: [0, 0, 0] + , blanchedalmond: [255, 235, 205] + , blue: [0, 0, 255] + , blueviolet: [138, 43, 226] + , brown: [165, 42, 42] + , burlywood: [222, 184, 135] + , cadetblue: [95, 158, 160] + , chartreuse: [127, 255, 0] + , chocolate: [210, 105, 30] + , coral: [255, 127, 80] + , cornflowerblue: [100, 149, 237] + , cornsilk: [255, 248, 220] + , crimson: [220, 20, 60] + , cyan: [0, 255, 255] + , darkblue: [0, 0, 139] + , darkcyan: [0, 139, 139] + , darkgoldenrod: [184, 132, 11] + , darkgray: [169, 169, 169] + , darkgreen: [0, 100, 0] + , darkgrey: [169, 169, 169] + , darkkhaki: [189, 183, 107] + , darkmagenta: [139, 0, 139] + , darkolivegreen: [85, 107, 47] + , darkorange: [255, 140, 0] + , darkorchid: [153, 50, 204] + , darkred: [139, 0, 0] + , darksalmon: [233, 150, 122] + , darkseagreen: [143, 188, 143] + , darkslateblue: [72, 61, 139] + , darkslategray: [47, 79, 79] + , darkslategrey: [47, 79, 79] + , darkturquoise: [0, 206, 209] + , darkviolet: [148, 0, 211] + , deeppink: [255, 20, 147] + , deepskyblue: [0, 191, 255] + , dimgray: [105, 105, 105] + , dimgrey: [105, 105, 105] + , dodgerblue: [30, 144, 255] + , firebrick: [178, 34, 34] + , floralwhite: [255, 255, 240] + , forestgreen: [34, 139, 34] + , fuchsia: [255, 0, 255] + , gainsboro: [220, 220, 220] + , ghostwhite: [248, 248, 255] + , gold: [255, 215, 0] + , goldenrod: [218, 165, 32] + , gray: [128, 128, 128] + , green: [0, 128, 0] + , greenyellow: [173, 255, 47] + , grey: [128, 128, 128] + , honeydew: [240, 255, 240] + , hotpink: [255, 105, 180] + , indianred: [205, 92, 92] + , indigo: [75, 0, 130] + , ivory: [255, 255, 240] + , khaki: [240, 230, 140] + , lavender: [230, 230, 250] + , lavenderblush: [255, 240, 245] + , lawngreen: [124, 252, 0] + , lemonchiffon: [255, 250, 205] + , lightblue: [173, 216, 230] + , lightcoral: [240, 128, 128] + , lightcyan: [224, 255, 255] + , lightgoldenrodyellow: [250, 250, 210] + , lightgray: [211, 211, 211] + , lightgreen: [144, 238, 144] + , lightgrey: [211, 211, 211] + , lightpink: [255, 182, 193] + , lightsalmon: [255, 160, 122] + , lightseagreen: [32, 178, 170] + , lightskyblue: [135, 206, 250] + , lightslategray: [119, 136, 153] + , lightslategrey: [119, 136, 153] + , lightsteelblue: [176, 196, 222] + , lightyellow: [255, 255, 224] + , lime: [0, 255, 0] + , limegreen: [50, 205, 50] + , linen: [250, 240, 230] + , magenta: [255, 0, 255] + , maroon: [128, 0, 0] + , mediumaquamarine: [102, 205, 170] + , mediumblue: [0, 0, 205] + , mediumorchid: [186, 85, 211] + , mediumpurple: [147, 112, 219] + , mediumseagreen: [60, 179, 113] + , mediumslateblue: [123, 104, 238] + , mediumspringgreen: [0, 250, 154] + , mediumturquoise: [72, 209, 204] + , mediumvioletred: [199, 21, 133] + , midnightblue: [25, 25, 112] + , mintcream: [245, 255, 250] + , mistyrose: [255, 228, 225] + , moccasin: [255, 228, 181] + , navajowhite: [255, 222, 173] + , navy: [0, 0, 128] + , oldlace: [253, 245, 230] + , olive: [128, 128, 0] + , olivedrab: [107, 142, 35] + , orange: [255, 165, 0] + , orangered: [255, 69, 0] + , orchid: [218, 112, 214] + , palegoldenrod: [238, 232, 170] + , palegreen: [152, 251, 152] + , paleturquoise: [175, 238, 238] + , palevioletred: [219, 112, 147] + , papayawhip: [255, 239, 213] + , peachpuff: [255, 218, 185] + , peru: [205, 133, 63] + , pink: [255, 192, 203] + , plum: [221, 160, 203] + , powderblue: [176, 224, 230] + , purple: [128, 0, 128] + , red: [255, 0, 0] + , rosybrown: [188, 143, 143] + , royalblue: [65, 105, 225] + , saddlebrown: [139, 69, 19] + , salmon: [250, 128, 114] + , sandybrown: [244, 164, 96] + , seagreen: [46, 139, 87] + , seashell: [255, 245, 238] + , sienna: [160, 82, 45] + , silver: [192, 192, 192] + , skyblue: [135, 206, 235] + , slateblue: [106, 90, 205] + , slategray: [119, 128, 144] + , slategrey: [119, 128, 144] + , snow: [255, 255, 250] + , springgreen: [0, 255, 127] + , steelblue: [70, 130, 180] + , tan: [210, 180, 140] + , teal: [0, 128, 128] + , thistle: [216, 191, 216] + , tomato: [255, 99, 71] + , turquoise: [64, 224, 208] + , violet: [238, 130, 238] + , wheat: [245, 222, 179] + , white: [255, 255, 255] + , whitesmoke: [245, 245, 245] + , yellow: [255, 255, 0] + , yellowgreen: [154, 205, 5] +}; \ No newline at end of file diff --git a/node_modules/stylus/lib/convert/css.js b/node_modules/stylus/lib/convert/css.js new file mode 100644 index 0000000..82df587 --- /dev/null +++ b/node_modules/stylus/lib/convert/css.js @@ -0,0 +1,130 @@ +/*! + * Stylus - CSS to Stylus conversion + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Convert the given `css` to Stylus source. + * + * @param {String} css + * @return {String} + * @api public + */ + +module.exports = function(css){ + return new Converter(css).stylus(); +}; + +/** + * Initialize a new `Converter` with the given `css`. + * + * @param {String} css + * @api private + */ + +function Converter(css) { + var cssom = require('cssom'); + this.css = css; + this.types = cssom.CSSRule; + this.root = cssom.parse(css); + this.indents = 0; +} + +/** + * Convert to Stylus. + * + * @return {String} + * @api private + */ + +Converter.prototype.stylus = function(){ + return this.visitRules(this.root.cssRules); +}; + +/** + * Return indent string. + * + * @return {String} + * @api private + */ + +Converter.prototype.__defineGetter__('indent', function(){ + return Array(this.indents + 1).join(' '); +}); + +/** + * Visit `node`. + * + * @param {CSSRule} node + * @return {String} + * @api private + */ + +Converter.prototype.visit = function(node){ + switch (node.type) { + case this.types.STYLE_RULE: + return this.visitStyle(node); + case this.types.MEDIA_RULE: + return this.visitMedia(node); + } +}; + +/** + * Visit the rules on `node`. + * + * @param {CSSRule} node + * @return {String} + * @api private + */ + +Converter.prototype.visitRules = function(node){ + var buf = ''; + for (var i = 0, len = node.length; i < len; ++i) { + buf += this.visit(node[i]); + } + return buf; +}; + +/** + * Visit CSSMediaRule `node`. + * + * @param {CSSMediaRule} node + * @return {String} + * @api private + */ + +Converter.prototype.visitMedia = function(node){ + var buf = this.indent + '@media '; + for (var i = 0, len = node.media.length; i < len; ++i) { + buf += node.media[i]; + } + buf += '\n'; + ++this.indents; + buf += this.visitRules(node.cssRules); + --this.indents; + return buf; +}; + +/** + * Visit CSSStyleRule `node`.` + * + * @param {CSSStyleRule} node + * @return {String} + * @api private + */ + +Converter.prototype.visitStyle = function(node){ + var buf = this.indent + node.selectorText + '\n'; + ++this.indents; + for (var i = 0, len = node.style.length; i < len; ++i) { + var prop = node.style[i] + , val = node.style[prop] + , importance = node.style['_importants'][prop] ? ' !important' : ''; + if (prop) { + buf += this.indent + prop + ': ' + val + importance + '\n'; + } + } + --this.indents; + return buf + '\n'; +}; \ No newline at end of file diff --git a/node_modules/stylus/lib/errors.js b/node_modules/stylus/lib/errors.js new file mode 100644 index 0000000..d3a6842 --- /dev/null +++ b/node_modules/stylus/lib/errors.js @@ -0,0 +1,58 @@ + +/*! + * Stylus - errors + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Expose constructors. + */ + +exports.ParseError = ParseError; +exports.SyntaxError = SyntaxError; + +/** + * Inherit from `Error.prototype`. + */ + +SyntaxError.prototype.__proto__ = Error.prototype; + +/** + * Initialize a new `ParseError` with the given `msg`. + * + * @param {String} msg + * @api private + */ + +function ParseError(msg) { + this.name = 'ParseError'; + this.message = msg; + Error.captureStackTrace(this, ParseError); +} + +/** + * Inherit from `Error.prototype`. + */ + +ParseError.prototype.__proto__ = Error.prototype; + +/** + * Initialize a new `SyntaxError` with the given `msg`. + * + * @param {String} msg + * @api private + */ + +function SyntaxError(msg) { + this.name = 'SyntaxError'; + this.message = msg; + Error.captureStackTrace(this, ParseError); +} + +/** + * Inherit from `Error.prototype`. + */ + +SyntaxError.prototype.__proto__ = Error.prototype; + diff --git a/node_modules/stylus/lib/functions/image.js b/node_modules/stylus/lib/functions/image.js new file mode 100644 index 0000000..6afcdbf --- /dev/null +++ b/node_modules/stylus/lib/functions/image.js @@ -0,0 +1,162 @@ + + +/*! + * Stylus - plugin - url + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var utils = require('../utils') + , nodes = require('../nodes') + , fs = require('fs') + , path = require('path') + , sax = require('sax'); + +/** + * Initialize a new `Image` with the given `ctx` and `path. + * + * @param {Evaluator} ctx + * @param {String} path + * @api private + */ + +var Image = module.exports = function Image(ctx, path) { + this.ctx = ctx; + this.path = utils.lookup(path, ctx.paths); + if (!this.path) throw new Error('failed to locate file ' + path); +}; + +/** + * Open the image for reading. + * + * @api private + */ + +Image.prototype.open = function(){ + this.fd = fs.openSync(this.path, 'r'); + this.length = fs.fstatSync(this.fd).size; + this.extname = path.extname(this.path).slice(1); +}; + +/** + * Close the file. + * + * @api private + */ + +Image.prototype.close = function(){ + if (this.fd) fs.closeSync(this.fd); +}; + +/** + * Return the type of image, supports: + * + * - gif + * - png + * - jpeg + * - svg + * + * @return {String} + * @api private + */ + +Image.prototype.type = function(){ + var type + , buf = new Buffer(4); + + fs.readSync(this.fd, buf, 0, 4, 0); + + // GIF + if (0x47 == buf[0] && 0x49 == buf[1] && 0x46 == buf[2]) type = 'gif'; + + // PNG + else if (0x50 == buf[1] && 0x4E == buf[2] && 0x47 == buf[3]) type = 'png'; + + // JPEG + else if (0xff == buf[0] && 0xd8 == buf[1]) type = 'jpeg'; + + // SVG + else if ('svg' == this.extname) type = this.extname; + + return type; +}; + +/** + * Return image dimensions `[width, height]`. + * + * @return {Array} + * @api private + */ + +Image.prototype.size = function(){ + var type = this.type() + , width + , height + , buf + , offset + , blockSize + , parser; + + function uint16(b) { return b[1] << 8 | b[0]; } + function uint32(b) { return b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]; } + + // Determine dimensions + switch (type) { + case 'jpeg': + buf = new Buffer(this.length); + fs.readSync(this.fd, buf, 0, this.length, 0); + offset = 4; + blockSize = buf[offset] << 8 | buf[offset + 1]; + + while (offset < this.length) { + offset += blockSize; + if (offset >= this.length || 0xff != buf[offset]) break; + // SOF0 or SOF2 (progressive) + if (0xc0 == buf[offset + 1] || 0xc2 == buf[offset + 1]) { + height = buf[offset + 5] << 8 | buf[offset + 6]; + width = buf[offset + 7] << 8 | buf[offset + 8]; + } else { + offset += 2; + blockSize = buf[offset] << 8 | buf[offset + 1]; + } + } + break; + case 'png': + buf = new Buffer(8); + // IHDR chunk width / height uint32_t big-endian + fs.readSync(this.fd, buf, 0, 8, 16); + width = uint32(buf); + height = uint32(buf.slice(4, 8)); + break; + case 'gif': + buf = new Buffer(4); + // width / height uint16_t little-endian + fs.readSync(this.fd, buf, 0, 4, 6); + width = uint16(buf); + height = uint16(buf.slice(2, 4)); + break; + case 'svg': + offset = Math.min(this.length, 1024); + buf = new Buffer(offset); + fs.readSync(this.fd, buf, 0, offset, 0); + buf = buf.toString('utf8'); + parser = sax.parser(true); + parser.onopentag = function(node) { + if ('svg' == node.name && node.attributes.width && node.attributes.height) { + width = parseInt(node.attributes.width, 10); + height = parseInt(node.attributes.height, 10); + } + }; + parser.write(buf).close(); + break; + } + + if ('number' != typeof width) throw new Error('failed to find width of "' + this.path + '"'); + if ('number' != typeof height) throw new Error('failed to find height of "' + this.path + '"'); + + return [width, height]; +}; diff --git a/node_modules/stylus/lib/functions/index.js b/node_modules/stylus/lib/functions/index.js new file mode 100644 index 0000000..229cdbe --- /dev/null +++ b/node_modules/stylus/lib/functions/index.js @@ -0,0 +1,1139 @@ + +/*! + * Stylus - Evaluator - built-in functions + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Compiler = require('../visitor/compiler') + , nodes = require('../nodes') + , utils = require('../utils') + , Image = require('./image') + , units = require('../units') + , colors = require('../colors') + , path = require('path') + , fs = require('fs'); + +/** + * Color component name map. + */ + +var componentMap = { + red: 'r' + , green: 'g' + , blue: 'b' + , alpha: 'a' + , hue: 'h' + , saturation: 's' + , lightness: 'l' +}; + +/** + * Color component unit type map. + */ + +var unitMap = { + hue: 'deg' + , saturation: '%' + , lightness: '%' +}; + +/** + * Color type map. + */ + +var typeMap = { + red: 'rgba' + , blue: 'rgba' + , green: 'rgba' + , alpha: 'rgba' + , hue: 'hsla' + , saturation: 'hsla' + , lightness: 'hsla' +}; + +/** + * Convert the given `color` to an `HSLA` node, + * or h,s,l,a component values. + * + * Examples: + * + * hsla(10deg, 50%, 30%, 0.5) + * // => HSLA + * + * hsla(#ffcc00) + * // => HSLA + * + * @param {RGBA|HSLA|Unit} hue + * @param {Unit} saturation + * @param {Unit} lightness + * @param {Unit} alpha + * @return {HSLA} + * @api public + */ + +exports.hsla = function hsla(hue, saturation, lightness, alpha){ + switch (arguments.length) { + case 1: + utils.assertColor(hue); + return hue.hsla; + default: + utils.assertType(hue, 'unit', 'hue'); + utils.assertType(saturation, 'unit', 'saturation'); + utils.assertType(lightness, 'unit', 'lightness'); + utils.assertType(alpha, 'unit', 'alpha'); + if (alpha && '%' == alpha.type) alpha.val /= 100; + return new nodes.HSLA( + hue.val + , saturation.val + , lightness.val + , alpha.val); + } +}; + +/** + * Convert the given `color` to an `HSLA` node, + * or h,s,l component values. + * + * Examples: + * + * hsl(10, 50, 30) + * // => HSLA + * + * hsl(#ffcc00) + * // => HSLA + * + * @param {Unit|HSLA|RGBA} hue + * @param {Unit} saturation + * @param {Unit} lightness + * @return {HSLA} + * @api public + */ + +exports.hsl = function hsl(hue, saturation, lightness){ + if (1 == arguments.length) { + utils.assertColor(hue, 'color'); + return hue.hsla; + } else { + return exports.hsla( + hue + , saturation + , lightness + , new nodes.Unit(1)); + } +}; + +/** + * Return type of `node`. + * + * Examples: + * + * type(12) + * // => 'unit' + * + * type(#fff) + * // => 'color' + * + * type(type) + * // => 'function' + * + * type(unbound) + * typeof(unbound) + * type-of(unbound) + * // => 'ident' + * + * @param {Node} node + * @return {String} + * @api public + */ + +exports.type = +exports.typeof = +exports['type-of'] = function type(node){ + utils.assertPresent(node, 'expression'); + return node.nodeName; +}; + +/** + * Return component `name` for the given `color`. + * + * @param {RGBA|HSLA} color + * @param {String} name + * @return {Unit} + * @api public + */ + +exports.component = function component(color, name) { + utils.assertColor(color, 'color'); + utils.assertString(name, 'name'); + var name = name.string + , unit = unitMap[name] + , type = typeMap[name] + , name = componentMap[name]; + if (!name) throw new Error('invalid color component "' + name + '"'); + return new nodes.Unit(color[type][name], unit); +}; + +/** + * Return the basename of `path`. + * + * @param {String} path + * @return {String} + * @api public + */ + +exports.basename = function basename(p, ext){ + utils.assertString(p, 'path'); + return path.basename(p.val, ext && ext.val); +}; + +/** + * Return the dirname of `path`. + * + * @param {String} path + * @return {String} + * @api public + */ + +exports.dirname = function dirname(p){ + utils.assertString(p, 'path'); + return path.dirname(p.val); +}; + +/** + * Return the extname of `path`. + * + * @param {String} path + * @return {String} + * @api public + */ + +exports.extname = function extname(p){ + utils.assertString(p, 'path'); + return path.extname(p.val); +}; + +/** + * Peform a path join. + * + * @param {String} path + * @return {String} + * @api public + */ + +(exports.pathjoin = function pathjoin(){ + var paths = [].slice.call(arguments).map(function(path){ + return path.first.string; + }); + return path.join.apply(null, paths); +}).raw = true; + +/** + * Return the red component of the given `color`. + * + * Examples: + * + * red(#c00) + * // => 204 + * + * @param {RGBA|HSLA} color + * @return {Unit} + * @api public + */ + +exports.red = function red(color){ + return exports.component(color, new nodes.String('red')); +}; + +/** + * Return the green component of the given `color`. + * + * Examples: + * + * green(#0c0) + * // => 204 + * + * @param {RGBA|HSLA} color + * @return {Unit} + * @api public + */ + +exports.green = function green(color){ + return exports.component(color, new nodes.String('green')); +}; + +/** + * Return the blue component of the given `color`. + * + * Examples: + * + * blue(#00c) + * // => 204 + * + * @param {RGBA|HSLA} color + * @return {Unit} + * @api public + */ + +exports.blue = function blue(color){ + return exports.component(color, new nodes.String('blue')); +}; + +/** + * Return a `RGBA` from the r,g,b,a channels. + * + * Examples: + * + * rgba(255,0,0,0.5) + * // => rgba(255,0,0,0.5) + * + * rgba(255,0,0,1) + * // => #ff0000 + * + * rgba(#ffcc00, 50%) + * // rgba(255,204,0,0.5) + * + * @param {Unit|RGBA|HSLA} red + * @param {Unit} green + * @param {Unit} blue + * @param {Unit} alpha + * @return {RGBA} + * @api public + */ + +exports.rgba = function rgba(red, green, blue, alpha){ + switch (arguments.length) { + case 1: + utils.assertColor(red); + var color = red.rgba; + return new nodes.RGBA( + color.r + , color.g + , color.b + , color.a); + case 2: + utils.assertColor(red); + var color = red.rgba; + utils.assertType(green, 'unit', 'alpha'); + if ('%' == green.type) green.val /= 100; + return new nodes.RGBA( + color.r + , color.g + , color.b + , green.val); + default: + utils.assertType(red, 'unit', 'red'); + utils.assertType(green, 'unit', 'green'); + utils.assertType(blue, 'unit', 'blue'); + utils.assertType(alpha, 'unit', 'alpha'); + var r = '%' == red.type ? Math.round(red.val * 2.55) : red.val; + var g = '%' == green.type ? Math.round(green.val * 2.55) : green.val; + var b = '%' == blue.type ? Math.round(blue.val * 2.55) : blue.val; + if (alpha && '%' == alpha.type) alpha.val /= 100; + return new nodes.RGBA( + r + , g + , b + , alpha.val); + } +}; + +/** + * Return a `RGBA` from the r,g,b channels. + * + * Examples: + * + * rgb(255,204,0) + * // => #ffcc00 + * + * rgb(#fff) + * // => #fff + * + * @param {Unit|RGBA|HSLA} red + * @param {Unit} green + * @param {Unit} blue + * @return {RGBA} + * @api public + */ + +exports.rgb = function rgb(red, green, blue){ + switch (arguments.length) { + case 1: + utils.assertColor(red); + var color = red.rgba; + return new nodes.RGBA( + color.r + , color.g + , color.b + , 1); + default: + return exports.rgba( + red + , green + , blue + , new nodes.Unit(1)); + } +}; + +/** + * Convert a .json file into stylus variables or object. + * Nested variable object keys are joined with a dash (-) + * + * Given this sample media-queries.json file: + * { + * "small": "screen and (max-width:400px)", + * "tablet": { + * "landscape": "screen and (min-width:600px) and (orientation:landscape)", + * "portrait": "screen and (min-width:600px) and (orientation:portrait)" + * } + * } + * + * Examples: + * + * json('media-queries.json') + * + * @media small + * // => @media screen and (max-width:400px) + * + * @media tablet-landscape + * // => @media screen and (min-width:600px) and (orientation:landscape) + * + * vars = json('vars.json', { hash: true }) + * body + * width: vars.width + * + * @param {String} path + * @param {Boolean} [local] + * @param {String} [namePrefix] + * @api public +*/ + +exports.json = function(path, local, namePrefix){ + utils.assertString(path, 'path'); + + // lookup + path = path.string; + var found = utils.lookup(path, this.options.paths, this.options.filename); + if (!found) throw new Error('failed to locate .json file ' + path); + + // read + var json = JSON.parse(fs.readFileSync(found, 'utf8')); + + if (local && 'object' == local.nodeName) { + return convert(json); + } else { + exports['-old-json'].call(this, json, local, namePrefix); + } + + function convert(obj){ + var ret = new nodes.Object(); + for (var key in obj) { + var val = obj[key]; + if ('object' == typeof val) { + ret.set(key, convert(val)); + } else { + val = utils.coerce(val); + if ('string' == val.nodeName) val = parseString(val.string); + ret.set(key, val); + } + } + return ret; + } +}; + +/** + * Old `json` BIF. + * + * @api private + */ + +exports['-old-json'] = function(json, local, namePrefix){ + if (namePrefix) { + utils.assertString(namePrefix, 'namePrefix'); + namePrefix = namePrefix.val; + } else { + namePrefix = ''; + } + local = local ? local.toBoolean() : new nodes.Boolean(local); + var scope = local.isTrue ? this.currentScope : this.global.scope; + + convert(json); + return; + + function convert(obj, prefix){ + prefix = prefix ? prefix + '-' : ''; + for (var key in obj){ + var val = obj[key]; + var name = prefix + key; + if ('object' == typeof val) { + convert(val, name); + } else { + val = utils.coerce(val); + if ('string' == val.nodeName) val = parseString(val.string); + scope.add({ name: namePrefix + name, val: val }); + } + } + } +}; + +/** +* Use the given `plugin` +* +* Examples: +* +* use("plugins/add.js") +* +* width add(10, 100) +* // => width: 110 +*/ + +exports.use = function(plugin){ + utils.assertString(plugin, 'path'); + + // lookup + plugin = plugin.string; + var found = utils.lookup(plugin, this.options.paths, this.options.filename); + if (!found) throw new Error('failed to locate plugin file ' + plugin); + + // use + var fn = require(path.resolve(found)); + if ('function' != typeof fn) { + throw new Error('plugin ' + path + ' does not export a function'); + } + this.renderer.use(fn(this.options)); +} + +/** + * Unquote the given `str`. + * + * Examples: + * + * unquote("sans-serif") + * // => sans-serif + * + * unquote(sans-serif) + * // => sans-serif + * + * @param {String|Ident} string + * @return {Literal} + * @api public + */ + +exports.unquote = function unquote(string){ + utils.assertString(string, 'string'); + return new nodes.Literal(string.string); +}; + +/** + * Assign `type` to the given `unit` or return `unit`'s type. + * + * @param {Unit} unit + * @param {String|Ident} type + * @return {Unit} + * @api public + */ + +exports.unit = function unit(unit, type){ + utils.assertType(unit, 'unit', 'unit'); + + // Assign + if (type) { + utils.assertString(type, 'type'); + return new nodes.Unit(unit.val, type.string); + } else { + return unit.type || ''; + } +}; + +/** + * Lookup variable `name` or return Null. + * + * @param {String} name + * @return {Mixed} + * @api public + */ + +exports.lookup = function lookup(name){ + utils.assertType(name, 'string', 'name'); + var node = this.lookup(name.val); + if (!node) return nodes.null; + return this.visit(node); +}; + +/** + * Perform `op` on the `left` and `right` operands. + * + * @param {String} op + * @param {Node} left + * @param {Node} right + * @return {Node} + * @api public + */ + +exports.operate = function operate(op, left, right){ + utils.assertType(op, 'string', 'op'); + utils.assertPresent(left, 'left'); + utils.assertPresent(right, 'right'); + return left.operate(op.val, right); +}; + +/** + * Test if `val` matches the given `pattern`. + * + * Examples: + * + * match('^foo(bar)?', foo) + * match('^foo(bar)?', foobar) + * match('^foo(bar)?', 'foo') + * match('^foo(bar)?', 'foobar') + * // => true + * + * match('^foo(bar)?', 'bar') + * // => false + * + * @param {String} pattern + * @param {String|Ident} val + * @return {Boolean} + * @api public + */ + +exports.match = function match(pattern, val){ + utils.assertType(pattern, 'string', 'pattern'); + utils.assertString(val, 'val'); + var re = new RegExp(pattern.val); + return new nodes.Boolean(re.test(val.string)); +}; + +/** + * Returns substring of the given `val`. + * + * @param {String|Ident} val + * @param {Number} start + * @param {Number} [length] + * @return {String|Ident} + * @api public + */ + +(exports.substr = function substr(val, start, length){ + utils.assertPresent(val, 'string'); + utils.assertPresent(start, 'start'); + var valNode = utils.unwrap(val).nodes[0]; + start = utils.unwrap(start).nodes[0].val; + if (length) { + length = utils.unwrap(length).nodes[0].val; + } + var res = valNode.string.substr(start, length); + return valNode instanceof nodes.Ident + ? new nodes.Ident(res) + : new nodes.String(res); +}).raw = true; + +/** + * Returns string with all matches of `pattern` replaced by `replacement` in given `val` + * + * @param {String} pattern + * @param {String} replacement + * @param {String|Ident} val + * @return {String|Ident} + * @api public + */ + +(exports.replace = function replace(pattern, replacement, val){ + utils.assertPresent(pattern, 'pattern'); + utils.assertPresent(replacement, 'replacement'); + utils.assertPresent(val, 'val'); + pattern = new RegExp(utils.unwrap(pattern).nodes[0].string, 'g'); + replacement = utils.unwrap(replacement).nodes[0].string; + var valNode = utils.unwrap(val).nodes[0]; + var res = valNode.string.replace(pattern, replacement); + return valNode instanceof nodes.Ident + ? new nodes.Ident(res) + : new nodes.String(res); +}).raw = true; + +/** + * Splits the given `val` by `delim` + * + * @param {String} delim + * @param {String|Ident} val + * @return {Expression} + * @api public + */ +(exports.split = function split(delim, val){ + utils.assertPresent(delim, 'delimiter'); + utils.assertPresent(val, 'val'); + delim = utils.unwrap(delim).nodes[0].string; + var valNode = utils.unwrap(val).nodes[0]; + var splitted = valNode.string.split(delim); + var expr = new nodes.Expression(); + var ItemNode = valNode instanceof nodes.Ident + ? nodes.Ident + : nodes.String; + for (var i = 0, len = splitted.length; i < len; ++i) { + expr.nodes.push(new ItemNode(splitted[i])); + } + return expr; +}).raw = true; + +/** + * Return length of the given `expr`. + * + * @param {Expression} expr + * @return {Unit} + * @api public + */ + +(exports.length = function length(expr){ + if (expr) { + if (expr.nodes) { + var nodes = utils.unwrap(expr).nodes; + if (1 == nodes.length && 'object' == nodes[0].nodeName) { + return nodes[0].length; + } else { + return nodes.length; + } + } else { + return 1; + } + } + return 0; +}).raw = true; + +/** + * Inspect the given `expr`. + * + * @param {Expression} expr + * @api public + */ + +(exports.p = function p(){ + [].slice.call(arguments).forEach(function(expr){ + expr = utils.unwrap(expr); + if (!expr.nodes.length) return; + console.log('\033[90minspect:\033[0m %s', expr.toString().replace(/^\(|\)$/g, '')); + }) + return nodes.null; +}).raw = true; + +/** + * Throw an error with the given `msg`. + * + * @param {String} msg + * @api public + */ + +exports.error = function error(msg){ + utils.assertType(msg, 'string', 'msg'); + throw new Error(msg.val); +}; + +/** + * Warn with the given `msg` prefixed by "Warning: ". + * + * @param {String} msg + * @api public + */ + +exports.warn = function warn(msg){ + utils.assertType(msg, 'string', 'msg'); + console.warn('Warning: %s', msg.val); + return nodes.null; +}; + +/** + * Output stack trace. + * + * @api public + */ + +exports.trace = function trace(){ + console.log(this.stack); + return nodes.null; +}; + +/** + * Push the given args to `expr`. + * + * @param {Expression} expr + * @param {Node} ... + * @return {Unit} + * @api public + */ + +(exports.push = exports.append = function(expr){ + expr = utils.unwrap(expr); + for (var i = 1, len = arguments.length; i < len; ++i) { + expr.nodes.push(utils.unwrap(arguments[i]).clone()); + } + return expr.nodes.length; +}).raw = true; + +/** + * Pop a value from `expr`. + * + * @param {Expression} expr + * @return {Node} + * @api public + */ + +(exports.pop = function pop(expr) { + expr = utils.unwrap(expr); + return expr.nodes.pop(); +}).raw = true; + +/** + * Unshift the given args to `expr`. + * + * @param {Expression} expr + * @param {Node} ... + * @return {Unit} + * @api public + */ + +(exports.unshift = exports.prepend = function(expr){ + expr = utils.unwrap(expr); + for (var i = 1, len = arguments.length; i < len; ++i) { + expr.nodes.unshift(utils.unwrap(arguments[i])); + } + return expr.nodes.length; +}).raw = true; + +/** + * Shift an element from `expr`. + * + * @param {Expression} expr + * @return {Node} + * @api public + */ + + (exports.shift = function(expr){ + expr = utils.unwrap(expr); + return expr.nodes.shift(); + }).raw = true; + +/** + * Return a `Literal` with the given `fmt`, and + * variable number of arguments. + * + * @param {String} fmt + * @param {Node} ... + * @return {Literal} + * @api public + */ + +(exports.s = function s(fmt){ + fmt = utils.unwrap(fmt).nodes[0]; + utils.assertString(fmt); + var self = this + , str = fmt.string + , args = arguments + , i = 1; + + // format + str = str.replace(/%(s|d)/g, function(_, specifier){ + var arg = args[i++] || nodes.null; + switch (specifier) { + case 's': + return new Compiler(arg, self.options).compile(); + case 'd': + arg = utils.unwrap(arg).first; + if ('unit' != arg.nodeName) throw new Error('%d requires a unit'); + return arg.val; + } + }); + + return new nodes.Literal(str); +}).raw = true; + +/** + * Return a `Literal` `num` converted to the provided `base`, padded to `width` + * with zeroes (default width is 2) + * + * @param {Number} num + * @param {Number} base + * @param {Number} width + * @return {Literal} + * @api public + */ + +(exports['base-convert'] = function(num, base, width) { + utils.assertPresent(num, 'number'); + utils.assertPresent(base, 'base'); + num = utils.unwrap(num).nodes[0].val; + base = utils.unwrap(base).nodes[0].val; + width = (width && utils.unwrap(width).nodes[0].val) || 2; + var result = Number(num).toString(base); + while (result.length < width) { + result = "0" + result; + } + return new nodes.Literal(result); +}).raw = true; + +/** + * Return the opposites of the given `positions`. + * + * Examples: + * + * opposite-position(top left) + * // => bottom right + * + * @param {Expression} positions + * @return {Expression} + * @api public + */ + +(exports['opposite-position'] = function oppositePosition(positions){ + var expr = []; + utils.unwrap(positions).nodes.forEach(function(pos, i){ + utils.assertString(pos, 'position ' + i); + pos = (function(){ switch (pos.string) { + case 'top': return 'bottom'; + case 'bottom': return 'top'; + case 'left': return 'right'; + case 'right': return 'left'; + case 'center': return 'center'; + default: throw new Error('invalid position ' + pos); + }})(); + expr.push(new nodes.Literal(pos)); + }); + return expr; +}).raw = true; + +/** + * Return the width and height of the given `img` path. + * + * Examples: + * + * image-size('foo.png') + * // => 200px 100px + * + * image-size('foo.png')[0] + * // => 200px + * + * image-size('foo.png')[1] + * // => 100px + * + * Can be used to test if the image exists, + * using an optional argument set to `true` + * (without this argument this function throws error + * if there is no such image). + * + * Example: + * + * image-size('nosuchimage.png', true)[0] + * // => 0 + * + * @param {String} img + * @param {Boolean} ignoreErr + * @return {Expression} + * @api public + */ + +exports['image-size'] = function imageSize(img, ignoreErr) { + utils.assertType(img, 'string', 'img'); + try { + var img = new Image(this, img.string); + } catch (err) { + if (ignoreErr) { + return [new nodes.Unit(0), new nodes.Unit(0)]; + } else { + throw err; + } + } + + // Read size + img.open(); + var size = img.size(); + img.close(); + + // Return (w h) + var expr = []; + expr.push(new nodes.Unit(size[0], 'px')); + expr.push(new nodes.Unit(size[1], 'px')); + + return expr; +}; + +/** + * Apply Math `fn` to `n`. + * + * @param {Unit} n + * @param {String} fn + * @return {Unit} + * @api private + */ + +exports['-math'] = function math(n, fn){ + return new nodes.Unit(Math[fn.string](n.val), n.type); +}; + +/** + * Get Math `prop`. + * + * @param {String} prop + * @return {Unit} + * @api private + */ + +exports['-math-prop'] = function math(prop){ + return new nodes.Unit(Math[prop.string]); +}; + +/** + * Buffer the given js `str`. + * + * @param {String} str + * @return {JSLiteral} + * @api private + */ + +exports.js = function js(str){ + utils.assertString(str, 'str'); + return new nodes.JSLiteral(str.val); +}; + +/** + * Adjust HSL `color` `prop` by `amount`. + * + * @param {RGBA|HSLA} color + * @param {String} prop + * @param {Unit} amount + * @return {RGBA} + * @api private + */ + +exports['-adjust'] = function adjust(color, prop, amount){ + var hsl = color.hsla.clone(); + prop = { hue: 'h', saturation: 's', lightness: 'l' }[prop.string]; + if (!prop) throw new Error('invalid adjustment property'); + var val = amount.val; + if ('%' == amount.type){ + val = 'l' == prop && val > 0 + ? (100 - hsl[prop]) * val / 100 + : hsl[prop] * (val / 100); + } + hsl[prop] += val; + return hsl.rgba; +}; + +/** + * Return a clone of the given `expr`. + * + * @param {Expression} expr + * @return {Node} + * @api public + */ + +(exports.clone = function clone(expr){ + utils.assertPresent(expr, 'expr'); + return expr.clone(); +}).raw = true; + +/** + * Add property `name` with the given `expr` + * to the mixin-able block. + * + * @param {String|Ident|Literal} name + * @param {Expression} expr + * @return {Property} + * @api public + */ + +(exports['add-property'] = function addProperty(name, expr){ + utils.assertType(name, 'expression', 'name'); + name = utils.unwrap(name).first; + utils.assertString(name, 'name'); + utils.assertType(expr, 'expression', 'expr'); + var prop = new nodes.Property([name], expr); + var block = this.closestBlock; + + var len = block.nodes.length + , head = block.nodes.slice(0, block.index) + , tail = block.nodes.slice(block.index++, len); + head.push(prop); + block.nodes = head.concat(tail); + + return prop; +}).raw = true; + +/** + * Merge the object `dest` with the given args. + * + * @param {Object} dest + * @param {Object} ... + * @return {Object} dest + * @api public + */ + +(exports.merge = exports.extend = function merge(dest){ + utils.assertPresent(dest, 'dest'); + dest = utils.unwrap(dest).first; + utils.assertType(dest, 'object', 'dest'); + for (var i = 1, len = arguments.length; i < len; ++i) { + utils.merge(dest.vals, utils.unwrap(arguments[i]).first.vals); + } + return dest; +}).raw = true; + +/** + * Attempt to parse unit `str`. + * + * @param {String} str + * @return {Unit} + * @api private + */ + +function parseUnit(str){ + var m = str.match(/^(\d+)(.*)/); + if (!m) return; + var n = parseInt(m[1], 10); + var type = m[2]; + return new nodes.Unit(n, type); +} + +/** + * Attempt to parse color. + * + * @param {String} str + * @return {RGBA} + * @api private + */ + +function parseColor(str){ + if (str.substr(0,1) === '#') { + // Handle color shorthands (like #abc) + var shorthand = str.length === 4, + m = str.match(shorthand ? /\w/g : /\w{2}/g); + + if (!m) return; + m = m.map(function(s) { return parseInt(shorthand ? s+s : s, 16) }); + return new nodes.RGBA(m[0],m[1],m[2],1); + } + else if (str.substr(0,3) === 'rgb'){ + var m = str.match(/(\d\.*\d+)/g); + if (!m) return; + m = m.map(function(s){return parseFloat(s, 10)}); + return new nodes.RGBA(m[0], m[1], m[2], m[3] || 1); + } + else { + var rgb = colors[str]; + if (!rgb) return; + return new nodes.RGBA(rgb[0], rgb[1], rgb[2], 1); + } +} + +/** + * Attempt to parse string. + * + * @param {String} str + * @return {Unit|RGBA|Literal} + * @api private + */ + +function parseString(str){ + return parseUnit(str) || parseColor(str) || new nodes.Literal(str); +} diff --git a/node_modules/stylus/lib/functions/index.styl b/node_modules/stylus/lib/functions/index.styl new file mode 100644 index 0000000..8bc2156 --- /dev/null +++ b/node_modules/stylus/lib/functions/index.styl @@ -0,0 +1,263 @@ +vendors = moz webkit o ms official + +// stringify the given arg + +-string(arg) + type(arg) + ' ' + arg + +// require a color + +require-color(color) + unless color is a 'color' + error('RGB or HSL value expected, got a ' + -string(color)) + +// require a unit + +require-unit(n) + unless n is a 'unit' + error('unit expected, got a ' + -string(n)) + +// require a string + +require-string(str) + unless str is a 'string' or str is a 'ident' + error('string expected, got a ' + -string(str)) + +// apply js Math function + +math(n, fn) + require-unit(n) + require-string(fn) + -math(n, fn) + +// adjust the given color's property by amount + +adjust(color, prop, amount) + require-color(color) + require-string(prop) + require-unit(amount) + -adjust(color, prop, amount) + +// Math functions + +abs(n) { math(n, 'abs') } +min(a, b) { a < b ? a : b } +max(a, b) { a > b ? a : b } + +// Trigonometrics +PI = -math-prop('PI') + +radians-to-degrees(angle) + angle * (180 / PI) + +degrees-to-radians(angle) + unit(angle * (PI / 180),'') + +sin(n) + n = degrees-to-radians(n) if unit(n) == 'deg' + round(math(n, 'sin'), 9) + +cos(n) + n = degrees-to-radians(n) if unit(n) == 'deg' + round(math(n, 'cos'), 9) + +tan(n) + round(sin(n) / cos(n), 9) + +// Rounding Math functions + +ceil(n, precision = 0) + multiplier = 10 ** precision + math(n * multiplier, 'ceil') / multiplier + +floor(n, precision = 0) + multiplier = 10 ** precision + math(n * multiplier, 'floor') / multiplier + +round(n, precision = 0) + multiplier = 10 ** precision + math(n * multiplier, 'round') / multiplier + +// return the sum of the given numbers + +sum(nums) + sum = 0 + sum += n for n in nums + +// return the average of the given numbers + +avg(nums) + sum(nums) / length(nums) + +// return a unitless number, or pass through + +remove-unit(n) + if typeof(n) is "unit" + unit(n, "") + else + n + +// convert a percent to a decimal, or pass through + +percent-to-decimal(n) + if unit(n) is "%" + remove-unit(n) / 100 + else + n + +// color components + +alpha(color) { component(hsl(color), 'alpha') } +hue(color) { component(hsl(color), 'hue') } +saturation(color) { component(hsl(color), 'saturation') } +lightness(color) { component(hsl(color), 'lightness') } + +// check if n is an odd number + +odd(n) + 1 == n % 2 + +// check if n is an even number + +even(n) + 0 == n % 2 + +// check if color is light + +light(color) + lightness(color) >= 50% + +// check if color is dark + +dark(color) + lightness(color) < 50% + +// desaturate color by amount + +desaturate(color, amount) + adjust(color, 'saturation', - amount) + +// saturate color by amount + +saturate(color, amount) + adjust(color, 'saturation', amount) + +// darken by the given amount + +darken(color, amount) + adjust(color, 'lightness', - amount) + +// lighten by the given amount + +lighten(color, amount) + adjust(color, 'lightness', amount) + +// decerase opacity by amount + +fade-out(color, amount) + color - rgba(black, percent-to-decimal(amount)) + +// increase opacity by amount + +fade-in(color, amount) + color + rgba(black, percent-to-decimal(amount)) + +// spin hue by a given amount + +spin(color, amount) + color + unit(amount, deg) + +// mix two colors by a given amount + +mix(color1, color2, weight = 50%) + unless weight in 0..100 + error("Weight must be between 0% and 100%") + + if length(color1) == 2 + weight = color1[0] + color1 = color1[1] + + else if length(color2) == 2 + weight = 100 - color2[0] + color2 = color2[1] + + require-color(color1) + require-color(color2) + + p = unit(weight / 100, '') + w = p * 2 - 1 + + a = alpha(color1) - alpha(color2) + + w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2 + w2 = 1 - w1 + + channels = (red(color1) red(color2)) (green(color1) green(color2)) (blue(color1) blue(color2)) + rgb = () + + for pair in channels + push(rgb, floor(pair[0] * w1 + pair[1] * w2)) + + a1 = alpha(color1) * p + a2 = alpha(color1) * (1 - p) + alpha = a1 + a2 + + rgba(rgb[0], rgb[1], rgb[2], alpha) + +// invert colors, leave alpha intact + +invert(color) + r = 255 - red(color) + g = 255 - green(color) + b = 255 - blue(color) + rgba(r,g,b,alpha(color)) + +// return the last value in the given expr + +last(expr) + expr[length(expr) - 1] + +// return keys in the given pairs or object + +keys(pairs) + ret = () + if type(pairs) == 'object' + for key in pairs + push(ret, key) + else + for pair in pairs + push(ret, pair[0]); + ret + +// return values in the given pairs or object + +values(pairs) + ret = () + if type(pairs) == 'object' + for key, val in pairs + push(ret, val) + else + for pair in pairs + push(ret, pair[1]); + ret + +// join values with the given delimiter + +join(delim, vals...) + buf = '' + vals = vals[0] if length(vals) == 1 + for val, i in vals + buf += i ? delim + val : val + +// add a CSS rule to the containing block + +// - This definition allows add-property to be used as a mixin +// - It has the same effect as interpolation but allows users +// to opt for a functional style + +add-property-function = add-property +add-property(name, expr) + if mixin + {name} expr + else + add-property-function(name, expr) diff --git a/node_modules/stylus/lib/functions/resolver.js b/node_modules/stylus/lib/functions/resolver.js new file mode 100644 index 0000000..8e7db37 --- /dev/null +++ b/node_modules/stylus/lib/functions/resolver.js @@ -0,0 +1,77 @@ +/** + * Module dependencies. + */ + +var Compiler = require('../visitor/compiler') + , nodes = require('../nodes') + , parse = require('url').parse + , relative = require('path').relative + , dirname = require('path').dirname + , extname = require('path').extname + , sep = require('path').sep + , utils = require('../utils'); + +/** + * Return a url() function with the given `options`. + * + * Options: + * + * - `paths` resolution path(s), merged with general lookup paths + * + * Examples: + * + * stylus(str) + * .set('filename', __dirname + '/css/test.styl') + * .define('url', stylus.resolver({ paths: [__dirname + '/public'] })) + * .render(function(err, css){ ... }) + * + * @param {Object} options + * @return {Function} + * @api public + */ + +module.exports = function(options) { + options = options || {}; + + var _paths = options.paths || []; + + function url(url) { + // Compile the url + var compiler = new Compiler(url); + compiler.isURL = true; + var url = url.nodes.map(function(node){ + return compiler.visit(node); + }).join(''); + + // Parse literal + var url = parse(url) + , literal = new nodes.Literal('url("' + url.href + '")') + , paths = _paths.concat(this.paths) + , tail = '' + , res + , found; + + // Absolute + if (url.protocol) return literal; + + // Lookup + found = utils.lookup(url.pathname, paths, '', true); + + // Failed to lookup + if (!found) return literal; + + if (url.search) tail += url.search; + if (url.hash) tail += url.hash; + + if (this.includeCSS && extname(found) == '.css') { + return new nodes.Literal(found + tail); + } else { + res = relative(dirname(this.filename), found) + tail; + if ('\\' == sep) res = res.replace(/\\/g, '/'); + return new nodes.Literal('url("' + res + '")'); + } + }; + + url.raw = true; + return url; +}; diff --git a/node_modules/stylus/lib/functions/url.js b/node_modules/stylus/lib/functions/url.js new file mode 100644 index 0000000..b0e937f --- /dev/null +++ b/node_modules/stylus/lib/functions/url.js @@ -0,0 +1,113 @@ + +/*! + * Stylus - plugin - url + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Compiler = require('../visitor/compiler') + , events = require('../renderer').events + , nodes = require('../nodes') + , parse = require('url').parse + , extname = require('path').extname + , utils = require('../utils') + , fs = require('fs'); + +/** + * Mime table. + */ + +var defaultMimes = { + '.gif': 'image/gif' + , '.png': 'image/png' + , '.jpg': 'image/jpeg' + , '.jpeg': 'image/jpeg' + , '.svg': 'image/svg+xml' + , '.ttf': 'application/x-font-ttf' + , '.eot': 'application/vnd.ms-fontobject' + , '.woff': 'application/font-woff' +}; + +/** + * Return a url() function with the given `options`. + * + * Options: + * + * - `limit` bytesize limit defaulting to 30Kb + * - `paths` image resolution path(s), merged with general lookup paths + * + * Examples: + * + * stylus(str) + * .set('filename', __dirname + '/css/test.styl') + * .define('url', stylus.url({ paths: [__dirname + '/public'] })) + * .render(function(err, css){ ... }) + * + * @param {Object} options + * @return {Function} + * @api public + */ + +module.exports = function(options) { + options = options || {}; + + var _paths = options.paths || []; + var sizeLimit = null != options.limit ? options.limit : 30000; + var mimes = options.mimes || defaultMimes; + + function fn(url){ + // Compile the url + var compiler = new Compiler(url); + compiler.isURL = true; + url = url.nodes.map(function(node){ + return compiler.visit(node); + }).join(''); + + // Parse literal + url = parse(url); + var ext = extname(url.pathname) + , mime = mimes[ext] + , literal = new nodes.Literal('url("' + url.href + '")') + , paths = _paths.concat(this.paths) + , buf; + + // Not supported + if (!mime) return literal; + + // Absolute + if (url.protocol) return literal; + + // Lookup + var found = utils.lookup(url.pathname, paths); + + // Failed to lookup + if (!found) { + events.emit( + 'file not found' + , 'File ' + literal + ' could not be found, literal url retained!' + ); + + return literal; + } + + // Read data + buf = fs.readFileSync(found); + + // To large + if (false !== sizeLimit && buf.length > sizeLimit) return literal; + + // Encode + return new nodes.Literal('url("data:' + mime + ';base64,' + buf.toString('base64') + '")'); + }; + + fn.raw = true; + return fn; +}; + +// Exporting default mimes so we could easily access them +module.exports.mimes = defaultMimes; + diff --git a/node_modules/stylus/lib/lexer.js b/node_modules/stylus/lib/lexer.js new file mode 100644 index 0000000..e6b3169 --- /dev/null +++ b/node_modules/stylus/lib/lexer.js @@ -0,0 +1,845 @@ + +/*! + * Stylus - Lexer + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Token = require('./token') + , nodes = require('./nodes') + , errors = require('./errors') + , units = require('./units'); + +/** + * Expose `Lexer`. + */ + +exports = module.exports = Lexer; + +/** + * Operator aliases. + */ + +var alias = { + 'and': '&&' + , 'or': '||' + , 'is': '==' + , 'isnt': '!=' + , 'is not': '!=' + , ':=': '?=' +}; + +/** + * Units. + */ + +units = units.join('|'); + +/** + * Unit RegExp. + */ + +var unit = new RegExp('^(-)?(\\d+\\.\\d+|\\d+|\\.\\d+)(' + units + ')?[ \\t]*'); + +/** + * Initialize a new `Lexer` with the given `str` and `options`. + * + * @param {String} str + * @param {Object} options + * @api private + */ + +function Lexer(str, options) { + options = options || {}; + this.stash = []; + this.indentStack = []; + this.indentRe = null; + this.lineno = 1; + + function comment(str, val, offset, s) { + var inComment = s.lastIndexOf('/*', offset) > s.lastIndexOf('*/', offset) + || s.lastIndexOf('//', offset) > s.lastIndexOf('\n', offset); + return inComment + ? str + : val; + }; + + this.str = str + .replace(/\s+$/, '\n') + .replace(/\r\n?/g, '\n') + .replace(/\\ *\n/g, ' ') + .replace(/([,(]|:(?!\/\/[^ ])) *(?:\/\/[^\n]*)?\n\s*/g, comment) + .replace(/\s*\n *([,)])/g, comment); +}; + +/** + * Lexer prototype. + */ + +Lexer.prototype = { + + /** + * Custom inspect. + */ + + inspect: function(){ + var tok + , tmp = this.str + , buf = []; + while ('eos' != (tok = this.next()).type) { + buf.push(tok.inspect()); + } + this.str = tmp; + this.prevIndents = 0; + return buf.concat(tok.inspect()).join('\n'); + }, + + /** + * Lookahead `n` tokens. + * + * @param {Number} n + * @return {Object} + * @api private + */ + + lookahead: function(n){ + var fetch = n - this.stash.length; + while (fetch-- > 0) this.stash.push(this.advance()); + return this.stash[--n]; + }, + + /** + * Consume the given `len`. + * + * @param {Number|Array} len + * @api private + */ + + skip: function(len){ + this.str = this.str.substr(Array.isArray(len) + ? len[0].length + : len); + }, + + /** + * Fetch next token including those stashed by peek. + * + * @return {Token} + * @api private + */ + + next: function() { + var tok = this.stashed() || this.advance(); + switch (tok.type) { + case 'newline': + case 'indent': + ++this.lineno; + break; + case 'outdent': + if ('outdent' != this.prev.type) ++this.lineno; + } + this.prev = tok; + tok.lineno = this.lineno; + return tok; + }, + + /** + * Check if the current token is a part of selector. + * + * @return {Boolean} + * @api private + */ + + isPartOfSelector: function() { + switch (this.prev && this.prev.type) { + // .or + case '.': + // #for + case 'color': + // [is] + case '[': + return true; + } + return false; + }, + + /** + * Fetch next token. + * + * @return {Token} + * @api private + */ + + advance: function() { + return this.eos() + || this.null() + || this.sep() + || this.keyword() + || this.urlchars() + || this.atrule() + || this.scope() + || this.extends() + || this.media() + || this.mozdocument() + || this.comment() + || this.newline() + || this.escaped() + || this.important() + || this.literal() + || this.function() + || this.brace() + || this.paren() + || this.color() + || this.string() + || this.unit() + || this.namedop() + || this.boolean() + || this.ident() + || this.op() + || this.space() + || this.selector(); + }, + + /** + * Lookahead a single token. + * + * @return {Token} + * @api private + */ + + peek: function() { + return this.lookahead(1); + }, + + /** + * Return the next possibly stashed token. + * + * @return {Token} + * @api private + */ + + stashed: function() { + return this.stash.shift(); + }, + + /** + * EOS | trailing outdents. + */ + + eos: function() { + if (this.str.length) return; + if (this.indentStack.length) { + this.indentStack.shift(); + return new Token('outdent'); + } else { + return new Token('eos'); + } + }, + + /** + * url char + */ + + urlchars: function() { + var captures; + if (!this.isURL) return; + if (captures = /^[\/:@.;?&=*!,<>#%0-9]+/.exec(this.str)) { + this.skip(captures); + return new Token('literal', new nodes.Literal(captures[0])); + } + }, + + /** + * ';' [ \t]* + */ + + sep: function() { + var captures; + if (captures = /^;[ \t]*/.exec(this.str)) { + this.skip(captures); + return new Token(';'); + } + }, + + /** + * ' '+ + */ + + space: function() { + var captures; + if (captures = /^([ \t]+)/.exec(this.str)) { + this.skip(captures); + return new Token('space'); + } + }, + + /** + * '\\' . ' '* + */ + + escaped: function() { + var captures; + if (captures = /^\\(.)[ \t]*/.exec(this.str)) { + var c = captures[1]; + this.skip(captures); + return new Token('ident', new nodes.Literal(c)); + } + }, + + /** + * '@css' ' '* '{' .* '}' ' '* + */ + + literal: function() { + // HACK attack !!! + var captures; + if (captures = /^@css[ \t]*\{/.exec(this.str)) { + this.skip(captures); + var c + , braces = 1 + , css = ''; + while (c = this.str[0]) { + this.str = this.str.substr(1); + switch (c) { + case '{': ++braces; break; + case '}': --braces; break; + } + css += c; + if (!braces) break; + } + css = css.replace(/\s*}$/, ''); + return new Token('literal', new nodes.Literal(css)); + } + }, + + /** + * '!important' ' '* + */ + + important: function() { + var captures; + if (captures = /^!important[ \t]*/.exec(this.str)) { + this.skip(captures); + return new Token('ident', new nodes.Literal('!important')); + } + }, + + /** + * '{' | '}' + */ + + brace: function() { + var captures; + if (captures = /^([{}])/.exec(this.str)) { + this.skip(1); + var brace = captures[1]; + return new Token(brace, brace); + } + }, + + /** + * '(' | ')' ' '* + */ + + paren: function() { + var captures; + if (captures = /^([()])([ \t]*)/.exec(this.str)) { + var paren = captures[1]; + this.skip(captures); + if (')' == paren) this.isURL = false; + var tok = new Token(paren, paren); + tok.space = captures[2]; + return tok; + } + }, + + /** + * 'null' + */ + + null: function() { + var captures + , tok; + if (captures = /^(null)\b[ \t]*/.exec(this.str)) { + this.skip(captures); + if (this.isPartOfSelector()) { + tok = new Token('ident', new nodes.Ident('null')); + } else { + tok = new Token('null', nodes.null); + } + return tok; + } + }, + + /** + * 'if' + * | 'else' + * | 'unless' + * | 'return' + * | 'for' + * | 'in' + */ + + keyword: function() { + var captures + , tok; + if (captures = /^(return|if|else|unless|for|in)\b[ \t]*/.exec(this.str)) { + var keyword = captures[1]; + this.skip(captures); + if (this.isPartOfSelector()) { + tok = new Token('ident', new nodes.Ident(keyword)); + } else { + tok = new Token(keyword, keyword); + } + return tok; + } + }, + + /** + * 'not' + * | 'and' + * | 'or' + * | 'is' + * | 'is not' + * | 'isnt' + * | 'is a' + * | 'is defined' + */ + + namedop: function() { + var captures + , tok; + if (captures = /^(not|and|or|is a|is defined|isnt|is not|is)(?!-)\b([ \t]*)/.exec(this.str)) { + var op = captures[1]; + this.skip(captures); + if (this.isPartOfSelector()) { + tok = new Token('ident', new nodes.Ident(op)); + } else { + op = alias[op] || op; + tok = new Token(op, op); + } + tok.space = captures[2]; + return tok; + } + }, + + /** + * ',' + * | '+' + * | '+=' + * | '-' + * | '-=' + * | '*' + * | '*=' + * | '/' + * | '/=' + * | '%' + * | '%=' + * | '**' + * | '!' + * | '&' + * | '&&' + * | '||' + * | '>' + * | '>=' + * | '<' + * | '<=' + * | '=' + * | '==' + * | '!=' + * | '!' + * | '~' + * | '?=' + * | ':=' + * | '?' + * | ':' + * | '[' + * | ']' + * | '.' + * | '..' + * | '...' + */ + + op: function() { + var captures; + if (captures = /^([.]{1,3}|&&|\|\||[!<>=?:]=|\*\*|[-+*\/%]=?|[,=?:!~<>&\[\]])([ \t]*)/.exec(this.str)) { + var op = captures[1]; + this.skip(captures); + op = alias[op] || op; + var tok = new Token(op, op); + tok.space = captures[2]; + this.isURL = false; + return tok; + } + }, + + /** + * '@extends' ([^{\n]+) + */ + + extends: function() { + var captures; + if (captures = /^@extends?[ \t]*([^\/{\n;]+)/.exec(this.str)) { + this.skip(captures); + return new Token('extend', captures[1].trim()); + } + }, + + /** + * '@media' ([^{\n]+) + */ + + media: function() { + var captures; + if (captures = /^@media[ \t]*(.+?)(?=\/\/|[\n{])/.exec(this.str)) { + this.skip(captures); + return new Token('media', captures[1].trim()); + } + }, + + /** + * '@-moz-document' ([^{\n]+) + */ + + mozdocument: function() { + var captures; + if (captures = /^@-moz-document[ \t]*([^\/{\n]+)/.exec(this.str)) { + this.skip(captures); + return new Token('-moz-document', captures[1].trim()); + } + }, + + /** + * '@scope' ([^{\n]+) + */ + + scope: function() { + var captures; + if (captures = /^@scope[ \t]*([^\/{\n]+)/.exec(this.str)) { + this.skip(captures); + return new Token('scope', captures[1].trim()); + } + }, + + /** + * '@' ('import' | 'keyframes' | 'charset' | 'page' | 'font-face') + */ + + atrule: function() { + var captures; + if (captures = /^@(import|(?:-(\w+)-)?keyframes|charset|font-face|page)[ \t]*/.exec(this.str)) { + this.skip(captures); + var vendor = captures[2] + , type = captures[1]; + if (vendor) type = 'keyframes'; + return new Token(type, vendor); + } + }, + + /** + * '//' * + */ + + comment: function() { + // Single line + if ('/' == this.str[0] && '/' == this.str[1]) { + var end = this.str.indexOf('\n'); + if (-1 == end) end = this.str.length; + this.skip(end); + return this.advance(); + } + + // Multi-line + if ('/' == this.str[0] && '*' == this.str[1]) { + var end = this.str.indexOf('*/'); + if (-1 == end) end = this.str.length; + var str = this.str.substr(0, end + 2) + , lines = str.split('\n').length - 1 + , suppress = true; + this.lineno += lines; + this.skip(end + 2); + // output + if ('!' == str[2]) { + str = str.replace('*!', '*'); + suppress = false; + } + return new Token('comment', new nodes.Comment(str, suppress)); + } + }, + + /** + * 'true' | 'false' + */ + + boolean: function() { + var captures; + if (captures = /^(true|false)\b([ \t]*)/.exec(this.str)) { + var val = nodes.Boolean('true' == captures[1]); + this.skip(captures); + var tok = new Token('boolean', val); + tok.space = captures[2]; + return tok; + } + }, + + /** + * -*[_a-zA-Z$] [-\w\d$]* '(' + */ + + function: function() { + var captures; + if (captures = /^(-*[_a-zA-Z$][-\w\d$]*)\(([ \t]*)/.exec(this.str)) { + var name = captures[1]; + this.skip(captures); + this.isURL = 'url' == name; + var tok = new Token('function', new nodes.Ident(name)); + tok.space = captures[2]; + return tok; + } + }, + + /** + * -*[_a-zA-Z$] [-\w\d$]* + */ + + ident: function() { + var captures; + if (captures = /^(@)?(-*[_a-zA-Z$][-\w\d$]*)/.exec(this.str)) { + var at = captures[1] + , name = captures[2] + , id = new nodes.Ident(name); + this.skip(captures); + id.property = !! at; + return new Token('ident', id); + } + }, + + /** + * '\n' ' '+ + */ + + newline: function() { + var captures, re; + + // we have established the indentation regexp + if (this.indentRe){ + captures = this.indentRe.exec(this.str); + // figure out if we are using tabs or spaces + } else { + // try tabs + re = /^\n([\t]*)[ \t]*/; + captures = re.exec(this.str); + + // nope, try spaces + if (captures && !captures[1].length) { + re = /^\n([ \t]*)/; + captures = re.exec(this.str); + } + + // established + if (captures && captures[1].length) this.indentRe = re; + } + + + if (captures) { + var tok + , indents = captures[1].length; + + this.skip(captures); + if (this.str[0] === ' ' || this.str[0] === '\t') { + throw new errors.SyntaxError('Invalid indentation. You can use tabs or spaces to indent, but not both.'); + } + + // Reset state + this.isVariable = false; + + // Blank line + if ('\n' == this.str[0]) { + ++this.lineno; + return this.advance(); + } + + // Outdent + if (this.indentStack.length && indents < this.indentStack[0]) { + while (this.indentStack.length && this.indentStack[0] > indents) { + this.stash.push(new Token('outdent')); + this.indentStack.shift(); + } + tok = this.stash.pop(); + // Indent + } else if (indents && indents != this.indentStack[0]) { + this.indentStack.unshift(indents); + tok = new Token('indent'); + // Newline + } else { + tok = new Token('newline'); + } + + return tok; + } + }, + + /** + * '-'? (digit+ | digit* '.' digit+) unit + */ + + unit: function() { + var captures; + if (captures = unit.exec(this.str)) { + this.skip(captures); + var n = parseFloat(captures[2]); + if ('-' == captures[1]) n = -n; + var node = new nodes.Unit(n, captures[3]); + return new Token('unit', node); + } + }, + + /** + * '"' [^"]+ '"' | "'"" [^']+ "'" + */ + + string: function() { + var captures; + if (captures = /^("[^"]*"|'[^']*')[ \t]*/.exec(this.str)) { + var str = captures[1] + , quote = captures[0][0]; + this.skip(captures); + str = str.slice(1,-1).replace(/\\n/g, '\n'); + return new Token('string', new nodes.String(str, quote)); + } + }, + + /** + * #rrggbbaa | #rrggbb | #rgba | #rgb | #nn | #n + */ + + color: function() { + return this.rrggbbaa() + || this.rrggbb() + || this.rgba() + || this.rgb() + || this.nn() + || this.n() + }, + + /** + * #n + */ + + n: function() { + var captures; + if (captures = /^#([a-fA-F0-9]{1})[ \t]*/.exec(this.str)) { + this.skip(captures); + var n = parseInt(captures[1] + captures[1], 16) + , color = new nodes.RGBA(n, n, n, 1); + color.raw = captures[0]; + return new Token('color', color); + } + }, + + /** + * #nn + */ + + nn: function() { + var captures; + if (captures = /^#([a-fA-F0-9]{2})[ \t]*/.exec(this.str)) { + this.skip(captures); + var n = parseInt(captures[1], 16) + , color = new nodes.RGBA(n, n, n, 1); + color.raw = captures[0]; + return new Token('color', color); + } + }, + + /** + * #rgb + */ + + rgb: function() { + var captures; + if (captures = /^#([a-fA-F0-9]{3})[ \t]*/.exec(this.str)) { + this.skip(captures); + var rgb = captures[1] + , r = parseInt(rgb[0] + rgb[0], 16) + , g = parseInt(rgb[1] + rgb[1], 16) + , b = parseInt(rgb[2] + rgb[2], 16) + , color = new nodes.RGBA(r, g, b, 1); + color.raw = captures[0]; + return new Token('color', color); + } + }, + + /** + * #rgba + */ + + rgba: function() { + var captures; + if (captures = /^#([a-fA-F0-9]{4})[ \t]*/.exec(this.str)) { + this.skip(captures); + var rgb = captures[1] + , r = parseInt(rgb[0] + rgb[0], 16) + , g = parseInt(rgb[1] + rgb[1], 16) + , b = parseInt(rgb[2] + rgb[2], 16) + , a = parseInt(rgb[3] + rgb[3], 16) + , color = new nodes.RGBA(r, g, b, a/255); + color.raw = captures[0]; + return new Token('color', color); + } + }, + + /** + * #rrggbb + */ + + rrggbb: function() { + var captures; + if (captures = /^#([a-fA-F0-9]{6})[ \t]*/.exec(this.str)) { + this.skip(captures); + var rgb = captures[1] + , r = parseInt(rgb.substr(0, 2), 16) + , g = parseInt(rgb.substr(2, 2), 16) + , b = parseInt(rgb.substr(4, 2), 16) + , color = new nodes.RGBA(r, g, b, 1); + color.raw = captures[0]; + return new Token('color', color); + } + }, + + /** + * #rrggbbaa + */ + + rrggbbaa: function() { + var captures; + if (captures = /^#([a-fA-F0-9]{8})[ \t]*/.exec(this.str)) { + this.skip(captures); + var rgb = captures[1] + , r = parseInt(rgb.substr(0, 2), 16) + , g = parseInt(rgb.substr(2, 2), 16) + , b = parseInt(rgb.substr(4, 2), 16) + , a = parseInt(rgb.substr(6, 2), 16) + , color = new nodes.RGBA(r, g, b, a/255); + color.raw = captures[0]; + return new Token('color', color); + } + }, + + /** + * [^\n,;]+ + */ + + selector: function() { + var captures; + if (captures = /^.*?(?=\/\/(?![^\[]*\])|[,\n{])/.exec(this.str)) { + var selector = captures[0]; + this.skip(captures); + return new Token('selector', selector); + } + } +}; diff --git a/node_modules/stylus/lib/middleware.js b/node_modules/stylus/lib/middleware.js new file mode 100644 index 0000000..8917739 --- /dev/null +++ b/node_modules/stylus/lib/middleware.js @@ -0,0 +1,244 @@ +/*! + * Stylus - middleware + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var stylus = require('./stylus') + , fs = require('fs') + , url = require('url') + , basename = require('path').basename + , dirname = require('path').dirname + , mkdirp = require('mkdirp') + , join = require('path').join + , sep = require('path').sep + , debug = require('debug')('stylus:middleware'); + +/** + * Import map. + */ + +var imports = {}; + +/** + * Return Connect middleware with the given `options`. + * + * Options: + * + * `force` Always re-compile + * `src` Source directory used to find .styl files, + * a string or function accepting `(path)` of request. + * `dest` Destination directory used to output .css files, + * a string or function accepting `(path)` of request, + * when undefined defaults to `src`. + * `compile` Custom compile function, accepting the arguments + * `(str, path)`. + * `compress` Whether the output .css files should be compressed + * `firebug` Emits debug infos in the generated CSS that can + * be used by the FireStylus Firebug plugin + * `linenos` Emits comments in the generated CSS indicating + * the corresponding Stylus line + * + * Examples: + * + * Here we set up the custom compile function so that we may + * set the `compress` option, or define additional functions. + * + * By default the compile function simply sets the `filename` + * and renders the CSS. + * + * function compile(str, path) { + * return stylus(str) + * .set('filename', path) + * .set('compress', true); + * } + * + * Pass the middleware to Connect, grabbing .styl files from this directory + * and saving .css files to _./public_. Also supplying our custom `compile` function. + * + * Following that we have a `static()` layer setup to serve the .css + * files generated by Stylus. + * + * var app = connect(); + * + * app.middleware({ + * src: __dirname + * , dest: __dirname + '/public' + * , compile: compile + * }) + * + * app.use(connect.static(__dirname + '/public')); + * + * @param {Object} options + * @return {Function} + * @api public + */ + +module.exports = function(options){ + options = options || {}; + + // Accept src/dest dir + if ('string' == typeof options) { + options = { src: options }; + } + + // Force compilation + var force = options.force; + + // Source dir required + var src = options.src; + if (!src) throw new Error('stylus.middleware() requires "src" directory'); + + // Default dest dir to source + var dest = options.dest || src; + + // Default compile callback + options.compile = options.compile || function(str, path){ + return stylus(str) + .set('filename', path) + .set('compress', options.compress) + .set('firebug', options.firebug) + .set('linenos', options.linenos); + }; + + // Middleware + return function stylus(req, res, next){ + if ('GET' != req.method && 'HEAD' != req.method) return next(); + var path = url.parse(req.url).pathname; + if (/\.css$/.test(path)) { + + if (typeof dest == 'string' || typeof dest == 'function') { + // check for dest-path overlap + var overlap = compare((typeof dest == 'function' ? dest(path) : dest), path); + path = path.slice(overlap.length); + } + + var cssPath, stylusPath; + cssPath = (typeof dest == 'function') + ? dest(path) + : join(dest, path); + stylusPath = (typeof src == 'function') + ? src(path) + : join(src, path.replace('.css', '.styl')); + + // Ignore ENOENT to fall through as 404 + function error(err) { + next('ENOENT' == err.code + ? null + : err); + } + + // Force + if (force) return compile(); + + // Compile to cssPath + function compile() { + debug('read %s', cssPath); + fs.readFile(stylusPath, 'utf8', function(err, str){ + if (err) return error(err); + var style = options.compile(str, stylusPath); + var paths = style.options._imports = []; + delete imports[stylusPath]; + style.render(function(err, css){ + if (err) return next(err); + debug('render %s', stylusPath); + imports[stylusPath] = paths; + mkdirp(dirname(cssPath), 0700, function(err){ + if (err) return error(err); + fs.writeFile(cssPath, css, 'utf8', next); + }); + }); + }); + } + + // Re-compile on server restart, disregarding + // mtimes since we need to map imports + if (!imports[stylusPath]) return compile(); + + // Compare mtimes + fs.stat(stylusPath, function(err, stylusStats){ + if (err) return error(err); + fs.stat(cssPath, function(err, cssStats){ + // CSS has not been compiled, compile it! + if (err) { + if ('ENOENT' == err.code) { + debug('not found %s', cssPath); + compile(); + } else { + next(err); + } + } else { + // Source has changed, compile it + if (stylusStats.mtime > cssStats.mtime) { + debug('modified %s', cssPath); + compile(); + // Already compiled, check imports + } else { + checkImports(stylusPath, function(changed){ + if (debug && changed.length) { + changed.forEach(function(path) { + debug('modified import %s', path); + }); + } + changed.length ? compile() : next(); + }); + } + } + }); + }); + } else { + next(); + } + } +}; + +/** + * Check `path`'s imports to see if they have been altered. + * + * @param {String} path + * @param {Function} fn + * @api private + */ + +function checkImports(path, fn) { + var nodes = imports[path]; + if (!nodes) return fn(); + if (!nodes.length) return fn(); + + var pending = nodes.length + , changed = []; + + nodes.forEach(function(imported){ + fs.stat(imported.path, function(err, stat){ + // error or newer mtime + if (err || !imported.mtime || stat.mtime > imported.mtime) { + changed.push(imported.path); + } + --pending || fn(changed); + }); + }); +} + +/** + * get the overlaping path from the end of path A, and the begining of path B. + * + * @param {String} pathA + * @param {String} pathB + * @return {String} + * @api private + */ + +function compare(pathA, pathB) { + pathA = pathA.split(sep); + pathB = pathB.split(sep); + var overlap = []; + while (pathA[pathA.length - 1] == pathB[0]) { + overlap.push(pathA.pop()); + pathB.shift(); + } + return overlap.join(sep); +} diff --git a/node_modules/stylus/lib/nodes/arguments.js b/node_modules/stylus/lib/nodes/arguments.js new file mode 100644 index 0000000..d0a00c0 --- /dev/null +++ b/node_modules/stylus/lib/nodes/arguments.js @@ -0,0 +1,65 @@ + +/*! + * Stylus - Arguments + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('../nodes') + , utils = require('../utils'); + +/** + * Initialize a new `Arguments`. + * + * @api public + */ + +var Arguments = module.exports = function Arguments(){ + nodes.Expression.call(this); + this.map = {}; +}; + +/** + * Inherit from `nodes.Expression.prototype`. + */ + +Arguments.prototype.__proto__ = nodes.Expression.prototype; + +/** + * Initialize an `Arguments` object with the nodes + * from the given `expr`. + * + * @param {Expression} expr + * @return {Arguments} + * @api public + */ + +Arguments.fromExpression = function(expr){ + var args = new Arguments + , len = expr.nodes.length; + args.lineno = expr.lineno; + args.isList = expr.isList; + for (var i = 0; i < len; ++i) { + args.push(expr.nodes[i]); + } + return args; +}; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Arguments.prototype.clone = function(){ + var clone = nodes.Expression.prototype.clone.call(this); + clone.map = this.map; + return clone; +}; + diff --git a/node_modules/stylus/lib/nodes/binop.js b/node_modules/stylus/lib/nodes/binop.js new file mode 100644 index 0000000..b4d8d09 --- /dev/null +++ b/node_modules/stylus/lib/nodes/binop.js @@ -0,0 +1,64 @@ + +/*! + * Stylus - BinOp + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `BinOp` with `op`, `left` and `right`. + * + * @param {String} op + * @param {Node} left + * @param {Node} right + * @api public + */ + +var BinOp = module.exports = function BinOp(op, left, right){ + Node.call(this); + this.op = op; + this.left = left; + this.right = right; +}; + +/** + * Inherit from `Node.prototype`. + */ + +BinOp.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +BinOp.prototype.clone = function(){ + var clone = new BinOp( + this.op + , this.left.clone() + , this.right ? + this.right.clone() + : null); + clone.lineno = this.lineno; + clone.filename = this.filename; + if (this.val) clone.val = this.val.clone(); + return clone; +}; + +/** + * Return + * + * @return {String} + * @api public + */ +BinOp.prototype.toString = function() { + return this.left.toString() + ' ' + this.op + ' ' + this.right.toString(); +}; diff --git a/node_modules/stylus/lib/nodes/block.js b/node_modules/stylus/lib/nodes/block.js new file mode 100644 index 0000000..71e7542 --- /dev/null +++ b/node_modules/stylus/lib/nodes/block.js @@ -0,0 +1,99 @@ + +/*! + * Stylus - Block + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Block` node with `parent` Block. + * + * @param {Block} parent + * @api public + */ + +var Block = module.exports = function Block(parent, node){ + Node.call(this); + this.nodes = []; + this.parent = parent; + this.node = node; + this.scope = true; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Block.prototype.__proto__ = Node.prototype; + +/** + * Check if this block has properties.. + * + * @return {Boolean} + * @api public + */ + +Block.prototype.__defineGetter__('hasProperties', function(){ + for (var i = 0, len = this.nodes.length; i < len; ++i) { + if ('property' == this.nodes[i].nodeName) { + return true; + } + } +}); + +/** + * Check if this block is empty. + * + * @return {Boolean} + * @api public + */ + +Block.prototype.__defineGetter__('isEmpty', function(){ + return !this.nodes.length; +}); + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Block.prototype.clone = function(){ + var clone = new Block(this.parent, this.node); + clone.lineno = this.lineno; + clone.filename = this.filename; + clone.scope = this.scope; + this.nodes.forEach(function(node){ + node = node.clone(); + switch (node.nodeName) { + case 'each': + case 'group': + node.block.parent = clone; + break; + case 'ident': + if ('function' == node.val.nodeName) { + node.val.block.parent = clone; + } + } + clone.push(node); + }); + return clone; +}; + +/** + * Push a `node` to this block. + * + * @param {Node} node + * @api public + */ + +Block.prototype.push = function(node){ + this.nodes.push(node); +}; diff --git a/node_modules/stylus/lib/nodes/boolean.js b/node_modules/stylus/lib/nodes/boolean.js new file mode 100644 index 0000000..d07b5ab --- /dev/null +++ b/node_modules/stylus/lib/nodes/boolean.js @@ -0,0 +1,103 @@ + +/*! + * Stylus - Boolean + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Boolean` node with the given `val`. + * + * @param {Boolean} val + * @api public + */ + +var Boolean = module.exports = function Boolean(val){ + Node.call(this); + if (this.nodeName) { + this.val = !!val; + } else { + return new Boolean(val); + } +}; + +/** + * Inherit from `Node.prototype`. + */ + +Boolean.prototype.__proto__ = Node.prototype; + +/** + * Return `this` node. + * + * @return {Boolean} + * @api public + */ + +Boolean.prototype.toBoolean = function(){ + return this; +}; + +/** + * Return `true` if this node represents `true`. + * + * @return {Boolean} + * @api public + */ + +Boolean.prototype.__defineGetter__('isTrue', function(){ + return this.val; +}); + +/** + * Return `true` if this node represents `false`. + * + * @return {Boolean} + * @api public + */ + +Boolean.prototype.__defineGetter__('isFalse', function(){ + return ! this.val; +}); + +/** + * Negate the value. + * + * @return {Boolean} + * @api public + */ + +Boolean.prototype.negate = function(){ + return new Boolean(!this.val); +}; + +/** + * Return 'Boolean'. + * + * @return {String} + * @api public + */ + +Boolean.prototype.inspect = function(){ + return '[Boolean ' + this.val + ']'; +}; + +/** + * Return 'true' or 'false'. + * + * @return {String} + * @api public + */ + +Boolean.prototype.toString = function(){ + return this.val + ? 'true' + : 'false'; +}; \ No newline at end of file diff --git a/node_modules/stylus/lib/nodes/call.js b/node_modules/stylus/lib/nodes/call.js new file mode 100644 index 0000000..0cf8cab --- /dev/null +++ b/node_modules/stylus/lib/nodes/call.js @@ -0,0 +1,62 @@ + +/*! + * Stylus - Call + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Call` with `name` and `args`. + * + * @param {String} name + * @param {Expression} args + * @api public + */ + +var Call = module.exports = function Call(name, args){ + Node.call(this); + this.name = name; + this.args = args; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Call.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Call.prototype.clone = function(){ + var clone = new Call(this.name, this.args.clone()); + clone.lineno = this.lineno; + clone.filename = this.filename; + return clone; +}; + +/** + * Return (param1, param2, ...). + * + * @return {String} + * @api public + */ + +Call.prototype.toString = function(){ + var args = this.args.nodes.map(function(node) { + var str = node.toString(); + return str.slice(1, str.length - 1); + }).join(', '); + + return this.name + '(' + args + ')'; +}; diff --git a/node_modules/stylus/lib/nodes/charset.js b/node_modules/stylus/lib/nodes/charset.js new file mode 100644 index 0000000..2e95c34 --- /dev/null +++ b/node_modules/stylus/lib/nodes/charset.js @@ -0,0 +1,42 @@ + +/*! + * Stylus - Charset + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Charset` with the given `val` + * + * @param {String} val + * @api public + */ + +var Charset = module.exports = function Charset(val){ + Node.call(this); + this.val = val; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Charset.prototype.__proto__ = Node.prototype; + +/** + * Return @charset "val". + * + * @return {String} + * @api public + */ + +Charset.prototype.toString = function(){ + return '@charset ' + this.val; +}; diff --git a/node_modules/stylus/lib/nodes/comment.js b/node_modules/stylus/lib/nodes/comment.js new file mode 100644 index 0000000..d36b0eb --- /dev/null +++ b/node_modules/stylus/lib/nodes/comment.js @@ -0,0 +1,32 @@ + +/*! + * Stylus - Comment + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Comment` with the given `str`. + * + * @param {String} str + * @param {Boolean} suppress + * @api public + */ + +var Comment = module.exports = function Comment(str, suppress){ + Node.call(this); + this.str = str; + this.suppress = suppress; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Comment.prototype.__proto__ = Node.prototype; diff --git a/node_modules/stylus/lib/nodes/each.js b/node_modules/stylus/lib/nodes/each.js new file mode 100644 index 0000000..b06777f --- /dev/null +++ b/node_modules/stylus/lib/nodes/each.js @@ -0,0 +1,56 @@ + +/*! + * Stylus - Each + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Each` node with the given `val` name, + * `key` name, `expr`, and `block`. + * + * @param {String} val + * @param {String} key + * @param {Expression} expr + * @param {Block} block + * @api public + */ + +var Each = module.exports = function Each(val, key, expr, block){ + Node.call(this); + this.val = val; + this.key = key; + this.expr = expr; + this.block = block; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Each.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Each.prototype.clone = function(){ + var clone = new Each( + this.val + , this.key + , this.expr.clone() + , this.block.clone()); + clone.lineno = this.lineno; + clone.filename = this.filename; + return clone; +}; \ No newline at end of file diff --git a/node_modules/stylus/lib/nodes/expression.js b/node_modules/stylus/lib/nodes/expression.js new file mode 100644 index 0000000..d4fc047 --- /dev/null +++ b/node_modules/stylus/lib/nodes/expression.js @@ -0,0 +1,200 @@ + +/*! + * Stylus - Expression + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('../nodes') + , utils = require('../utils'); + +/** + * Initialize a new `Expression`. + * + * @param {Boolean} isList + * @api public + */ + +var Expression = module.exports = function Expression(isList){ + Node.call(this); + this.nodes = []; + this.isList = isList; +}; + +/** + * Check if the variable has a value. + * + * @return {Boolean} + * @api public + */ + +Expression.prototype.__defineGetter__('isEmpty', function(){ + return !this.nodes.length; +}); + +/** + * Return the first node in this expression. + * + * @return {Node} + * @api public + */ + +Expression.prototype.__defineGetter__('first', function(){ + return this.nodes[0] + ? this.nodes[0].first + : nodes.null; +}); + +/** + * Hash all the nodes in order. + * + * @return {String} + * @api public + */ + +Expression.prototype.__defineGetter__('hash', function(){ + return this.nodes.map(function(node){ + return node.hash; + }).join('::'); +}); + +/** + * Inherit from `Node.prototype`. + */ + +Expression.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Expression.prototype.clone = function(){ + var clone = new this.constructor(this.isList); + clone.preserve = this.preserve; + clone.lineno = this.lineno; + clone.filename = this.filename; + for (var i = 0; i < this.nodes.length; ++i) { + clone.push(this.nodes[i].clone()); + } + return clone; +}; + +/** + * Push the given `node`. + * + * @param {Node} node + * @api public + */ + +Expression.prototype.push = function(node){ + this.nodes.push(node); +}; + +/** + * Operate on `right` with the given `op`. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +Expression.prototype.operate = function(op, right, val){ + switch (op) { + case '[]=': + var self = this + , range = utils.unwrap(right).nodes + , val = utils.unwrap(val) + , len + , node; + range.forEach(function(unit){ + len = self.nodes.length; + if ('unit' == unit.nodeName) { + var i = unit.val; + while (i-- > len) self.nodes[i] = nodes.null; + self.nodes[unit.val] = val; + } else if ('string' == unit.nodeName) { + node = self.nodes[0]; + if (node && 'object' == node.nodeName) node.set(unit.val, val.clone()); + } + }); + return val; + case '[]': + var expr = new nodes.Expression + , vals = utils.unwrap(this).nodes + , range = utils.unwrap(right).nodes + , node; + range.forEach(function(unit){ + if ('unit' == unit.nodeName) { + node = vals[unit.val]; + } else if ('string' == unit.nodeName && 'object' == vals[0].nodeName) { + node = vals[0].get(unit.val); + } + if (node) expr.push(node); + }); + return expr.isEmpty + ? nodes.null + : utils.unwrap(expr); + case '||': + return this.toBoolean().isTrue + ? this + : right; + case 'in': + return Node.prototype.operate.call(this, op, right); + case '!=': + return this.operate('==', right, val).negate(); + case '==': + var len = this.nodes.length + , right = right.toExpression() + , a + , b; + if (len != right.nodes.length) return nodes.false; + for (var i = 0; i < len; ++i) { + a = this.nodes[i]; + b = right.nodes[i]; + if (a.operate(op, b).isTrue) continue; + return nodes.false; + } + return nodes.true; + break; + default: + return this.first.operate(op, right, val); + } +}; + +/** + * Expressions with length > 1 are truthy, + * otherwise the first value's toBoolean() + * method is invoked. + * + * @return {Boolean} + * @api public + */ + +Expression.prototype.toBoolean = function(){ + if (this.nodes.length > 1) return nodes.true; + return this.first.toBoolean(); +}; + +/** + * Return " " or ", , " if + * the expression represents a list. + * + * @return {String} + * @api public + */ + +Expression.prototype.toString = function(){ + return '(' + this.nodes.map(function(node){ + return node.toString(); + }).join(this.isList ? ', ' : ' ') + ')'; +}; + diff --git a/node_modules/stylus/lib/nodes/extend.js b/node_modules/stylus/lib/nodes/extend.js new file mode 100644 index 0000000..5c22a73 --- /dev/null +++ b/node_modules/stylus/lib/nodes/extend.js @@ -0,0 +1,52 @@ + +/*! + * Stylus - Extend + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Extend` with the given `selector`. + * + * @param {Selector} selector + * @api public + */ + +var Extend = module.exports = function Extend(selector){ + Node.call(this); + this.selector = selector; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Extend.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Extend.prototype.clone = function(){ + return new Extend(this.selector); +}; + +/** + * Return `@extend selector`. + * + * @return {String} + * @api public + */ + +Extend.prototype.toString = function(){ + return '@extend ' + this.selector; +}; diff --git a/node_modules/stylus/lib/nodes/fontface.js b/node_modules/stylus/lib/nodes/fontface.js new file mode 100644 index 0000000..8a8bfaf --- /dev/null +++ b/node_modules/stylus/lib/nodes/fontface.js @@ -0,0 +1,55 @@ + +/*! + * Stylus - FontFace + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `FontFace` with the given `block`. + * + * @param {Block} block + * @api public + */ + +var FontFace = module.exports = function FontFace(block){ + Node.call(this); + this.block = block; +}; + +/** + * Inherit from `Node.prototype`. + */ + +FontFace.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +FontFace.prototype.clone = function(){ + var clone = new FontFace(this.block.clone()); + clone.lineno = this.lineno; + clone.filename = this.filename; + return clone; +}; + +/** + * Return `@oage name`. + * + * @return {String} + * @api public + */ + +FontFace.prototype.toString = function(){ + return '@font-face'; +}; diff --git a/node_modules/stylus/lib/nodes/function.js b/node_modules/stylus/lib/nodes/function.js new file mode 100644 index 0000000..83fcea7 --- /dev/null +++ b/node_modules/stylus/lib/nodes/function.js @@ -0,0 +1,104 @@ + +/*! + * Stylus - Function + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Function` with `name`, `params`, and `body`. + * + * @param {String} name + * @param {Params|Function} params + * @param {Block} body + * @api public + */ + +var Function = module.exports = function Function(name, params, body){ + Node.call(this); + this.name = name; + this.params = params; + this.block = body; + if ('function' == typeof params) this.fn = params; +}; + +/** + * Check function arity. + * + * @return {Boolean} + * @api public + */ + +Function.prototype.__defineGetter__('arity', function(){ + return this.params.length; +}); + +/** + * Inherit from `Node.prototype`. + */ + +Function.prototype.__proto__ = Node.prototype; + +/** + * Return hash. + * + * @return {String} + * @api public + */ + +Function.prototype.__defineGetter__('hash', function(){ + return 'function ' + this.name; +}); + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Function.prototype.clone = function(){ + if (this.fn) { + var clone = new Function( + this.name + , this.fn); + } else { + var clone = new Function( + this.name + , this.params.clone() + , this.block.clone()); + } + clone.lineno = this.lineno; + clone.filename = this.filename; + return clone; +}; + +/** + * Return (param1, param2, ...). + * + * @return {String} + * @api public + */ + +Function.prototype.toString = function(){ + if (this.fn) { + return this.name + + '(' + + this.fn.toString() + .match(/^function *\w*\((.*?)\)/) + .slice(1) + .join(', ') + + ')'; + } else { + return this.name + + '(' + + this.params.nodes.join(', ') + + ')'; + } +}; diff --git a/node_modules/stylus/lib/nodes/group.js b/node_modules/stylus/lib/nodes/group.js new file mode 100644 index 0000000..a1bb57a --- /dev/null +++ b/node_modules/stylus/lib/nodes/group.js @@ -0,0 +1,80 @@ + +/*! + * Stylus - Group + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Group`. + * + * @api public + */ + +var Group = module.exports = function Group(){ + Node.call(this); + this.nodes = []; + this.extends = []; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Group.prototype.__proto__ = Node.prototype; + +/** + * Push the given `selector` node. + * + * @param {Selector} selector + * @api public + */ + +Group.prototype.push = function(selector){ + this.nodes.push(selector); +}; + +/** + * Return this set's `Block`. + */ + +Group.prototype.__defineGetter__('block', function(){ + return this.nodes[0].block; +}); + +/** + * Assign `block` to each selector in this set. + * + * @param {Block} block + * @api public + */ + +Group.prototype.__defineSetter__('block', function(block){ + for (var i = 0, len = this.nodes.length; i < len; ++i) { + this.nodes[i].block = block; + } +}); + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Group.prototype.clone = function(){ + var clone = new Group; + clone.lineno = this.lineno; + this.nodes.forEach(function(node){ + clone.push(node.clone()); + }); + clone.filename = this.filename; + clone.block = this.block.clone(); + return clone; +}; diff --git a/node_modules/stylus/lib/nodes/hsla.js b/node_modules/stylus/lib/nodes/hsla.js new file mode 100644 index 0000000..2ee2ebf --- /dev/null +++ b/node_modules/stylus/lib/nodes/hsla.js @@ -0,0 +1,256 @@ + +/*! + * Stylus - HSLA + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `HSLA` with the given h,s,l,a component values. + * + * @param {Number} h + * @param {Number} s + * @param {Number} l + * @param {Number} a + * @api public + */ + +var HSLA = exports = module.exports = function HSLA(h,s,l,a){ + Node.call(this); + this.h = clampDegrees(h); + this.s = clampPercentage(s); + this.l = clampPercentage(l); + this.a = clampAlpha(a); + this.hsla = this; +}; + +/** + * Inherit from `Node.prototype`. + */ + +HSLA.prototype.__proto__ = Node.prototype; + +/** + * Return hsla(n,n,n,n). + * + * @return {String} + * @api public + */ + +HSLA.prototype.toString = function(){ + return 'hsla(' + + this.h + ',' + + this.s.toFixed(0) + ',' + + this.l.toFixed(0) + ',' + + this.a + ')'; +}; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +HSLA.prototype.clone = function(){ + var clone = new HSLA( + this.h + , this.s + , this.l + , this.a); + clone.lineno = this.lineno; + clone.filename = this.filename; + return clone; +}; + +/** + * Return rgba `RGBA` representation. + * + * @return {RGBA} + * @api public + */ + +HSLA.prototype.__defineGetter__('rgba', function(){ + return nodes.RGBA.fromHSLA(this); +}); + +/** + * Return hash. + * + * @return {String} + * @api public + */ + +HSLA.prototype.__defineGetter__('hash', function(){ + return this.rgba.toString(); +}); + +/** + * Add h,s,l to the current component values. + * + * @param {Number} h + * @param {Number} s + * @param {Number} l + * @return {HSLA} new node + * @api public + */ + +HSLA.prototype.add = function(h,s,l){ + return new HSLA( + this.h + h + , this.s + s + , this.l + l + , this.a); +}; + +/** + * Subtract h,s,l from the current component values. + * + * @param {Number} h + * @param {Number} s + * @param {Number} l + * @return {HSLA} new node + * @api public + */ + +HSLA.prototype.sub = function(h,s,l){ + return this.add(-h, -s, -l); +}; + +/** + * Operate on `right` with the given `op`. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +HSLA.prototype.operate = function(op, right){ + switch (op) { + case '==': + case '!=': + case '<=': + case '>=': + case '<': + case '>': + case 'is a': + case '||': + case '&&': + return this.rgba.operate(op, right); + default: + return this.rgba.operate(op, right).hsla; + } +}; + +/** + * Return `HSLA` representation of the given `color`. + * + * @param {RGBA} color + * @return {HSLA} + * @api public + */ + +exports.fromRGBA = function(rgba){ + var r = rgba.r / 255 + , g = rgba.g / 255 + , b = rgba.b / 255 + , a = rgba.a; + + var min = Math.min(r,g,b) + , max = Math.max(r,g,b) + , l = (max + min) / 2 + , d = max - min + , h, s; + + switch (max) { + case min: h = 0; break; + case r: h = 60 * (g-b) / d; break; + case g: h = 60 * (b-r) / d + 120; break; + case b: h = 60 * (r-g) / d + 240; break; + } + + if (max == min) { + s = 0; + } else if (l < .5) { + s = d / (2 * l); + } else { + s = d / (2 - 2 * l); + } + + h %= 360; + s *= 100; + l *= 100; + + return new HSLA(h,s,l,a); +}; + +/** + * Adjust lightness by `percent`. + * + * @param {Number} percent + * @return {HSLA} for chaining + * @api public + */ + +HSLA.prototype.adjustLightness = function(percent){ + this.l = clampPercentage(this.l + this.l * (percent / 100)); + return this; +}; + +/** + * Adjust hue by `deg`. + * + * @param {Number} deg + * @return {HSLA} for chaining + * @api public + */ + +HSLA.prototype.adjustHue = function(deg){ + this.h = clampDegrees(this.h + deg); + return this; +}; + +/** + * Clamp degree `n` >= 0 and <= 360. + * + * @param {Number} n + * @return {Number} + * @api private + */ + +function clampDegrees(n) { + n = n % 360; + return n >= 0 ? n : 360 + n; +} + +/** + * Clamp percentage `n` >= 0 and <= 100. + * + * @param {Number} n + * @return {Number} + * @api private + */ + +function clampPercentage(n) { + return Math.max(0, Math.min(n, 100)); +} + +/** + * Clamp alpha `n` >= 0 and <= 1. + * + * @param {Number} n + * @return {Number} + * @api private + */ + +function clampAlpha(n) { + return Math.max(0, Math.min(n, 1)); +} diff --git a/node_modules/stylus/lib/nodes/ident.js b/node_modules/stylus/lib/nodes/ident.js new file mode 100644 index 0000000..0943811 --- /dev/null +++ b/node_modules/stylus/lib/nodes/ident.js @@ -0,0 +1,128 @@ + +/*! + * Stylus - Ident + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Ident` by `name` with the given `val` node. + * + * @param {String} name + * @param {Node} val + * @api public + */ + +var Ident = module.exports = function Ident(name, val){ + Node.call(this); + this.name = name; + this.string = name; + this.val = val || nodes.null; +}; + +/** + * Check if the variable has a value. + * + * @return {Boolean} + * @api public + */ + +Ident.prototype.__defineGetter__('isEmpty', function(){ + return undefined == this.val; +}); + +/** + * Return hash. + * + * @return {String} + * @api public + */ + +Ident.prototype.__defineGetter__('hash', function(){ + return this.name; +}); + +/** + * Inherit from `Node.prototype`. + */ + +Ident.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Ident.prototype.clone = function(){ + var clone = new Ident(this.name, this.val.clone()); + clone.lineno = this.lineno; + clone.filename = this.filename; + clone.property = this.property; + return clone; +}; + +/** + * Return . + * + * @return {String} + * @api public + */ + +Ident.prototype.toString = function(){ + return this.name; +}; + +/** + * Coerce `other` to an ident. + * + * @param {Node} other + * @return {String} + * @api public + */ + +Ident.prototype.coerce = function(other){ + switch (other.nodeName) { + case 'ident': + case 'string': + case 'literal': + return new Ident(other.string); + default: + return Node.prototype.coerce.call(this, other); + } +}; + +/** + * Operate on `right` with the given `op`. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +Ident.prototype.operate = function(op, right){ + var val = right.first; + switch (op) { + case '-': + if ('unit' == val.nodeName) { + var expr = new nodes.Expression; + val = val.clone(); + val.val = -val.val; + expr.push(this); + expr.push(val); + return expr; + } + case '+': + return new nodes.Ident(this.string + this.coerce(val).string); + } + return Node.prototype.operate.call(this, op, right); +}; diff --git a/node_modules/stylus/lib/nodes/if.js b/node_modules/stylus/lib/nodes/if.js new file mode 100644 index 0000000..9f4db8c --- /dev/null +++ b/node_modules/stylus/lib/nodes/if.js @@ -0,0 +1,56 @@ + +/*! + * Stylus - If + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `If` with the given `cond`. + * + * @param {Expression} cond + * @param {Boolean|Block} negate, block + * @api public + */ + +var If = module.exports = function If(cond, negate){ + Node.call(this); + this.cond = cond; + this.elses = []; + if (negate && negate.nodeName) { + this.block = negate; + } else { + this.negate = negate; + } +}; + +/** + * Inherit from `Node.prototype`. + */ + +If.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +If.prototype.clone = function(){ + var cond = this.cond.clone() + , block = this.block.clone(); + var clone = new If(cond, block); + clone.elses = this.elses.map(function(node){ return node.clone(); }); + clone.negate = this.negate; + clone.postfix = this.postfix; + clone.lineno = this.lineno; + clone.filename = this.filename; + return clone; +}; diff --git a/node_modules/stylus/lib/nodes/import.js b/node_modules/stylus/lib/nodes/import.js new file mode 100644 index 0000000..9356c30 --- /dev/null +++ b/node_modules/stylus/lib/nodes/import.js @@ -0,0 +1,30 @@ + +/*! + * Stylus - Import + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Import` with the given `expr`. + * + * @param {Expression} expr + * @api public + */ + +var Import = module.exports = function Import(expr){ + Node.call(this); + this.path = expr; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Import.prototype.__proto__ = Node.prototype; diff --git a/node_modules/stylus/lib/nodes/index.js b/node_modules/stylus/lib/nodes/index.js new file mode 100644 index 0000000..dfd692c --- /dev/null +++ b/node_modules/stylus/lib/nodes/index.js @@ -0,0 +1,56 @@ + +/*! + * Stylus - nodes + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Constructors + */ + +exports.Node = require('./node'); +exports.Root = require('./root'); +exports.Null = require('./null'); +exports.Each = require('./each'); +exports.If = require('./if'); +exports.Call = require('./call'); +exports.Page = require('./page'); +exports.FontFace = require('./fontface'); +exports.UnaryOp = require('./unaryop'); +exports.BinOp = require('./binop'); +exports.Ternary = require('./ternary'); +exports.Block = require('./block'); +exports.Unit = require('./unit'); +exports.String = require('./string'); +exports.HSLA = require('./hsla'); +exports.RGBA = require('./rgba'); +exports.Ident = require('./ident'); +exports.Group = require('./group'); +exports.Literal = require('./literal'); +exports.JSLiteral = require('./jsliteral'); +exports.Boolean = require('./boolean'); +exports.Return = require('./return'); +exports.Media = require('./media'); +exports.Params = require('./params'); +exports.Comment = require('./comment'); +exports.Keyframes = require('./keyframes'); +exports.Member = require('./member'); +exports.Charset = require('./charset'); +exports.Import = require('./import'); +exports.Extend = require('./extend'); +exports.Object = require('./object'); +exports.Function = require('./function'); +exports.Property = require('./property'); +exports.Selector = require('./selector'); +exports.Expression = require('./expression'); +exports.Arguments = require('./arguments'); +exports.MozDocument = require('./mozdocument'); + +/** + * Singletons. + */ + +exports.true = new exports.Boolean(true); +exports.false = new exports.Boolean(false); +exports.null = new exports.Null; diff --git a/node_modules/stylus/lib/nodes/jsliteral.js b/node_modules/stylus/lib/nodes/jsliteral.js new file mode 100644 index 0000000..08cdcb2 --- /dev/null +++ b/node_modules/stylus/lib/nodes/jsliteral.js @@ -0,0 +1,32 @@ + +/*! + * Stylus - JSLiteral + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `JSLiteral` with the given `str`. + * + * @param {String} str + * @api public + */ + +var JSLiteral = module.exports = function JSLiteral(str){ + Node.call(this); + this.val = str; + this.string = str; +}; + +/** + * Inherit from `Node.prototype`. + */ + +JSLiteral.prototype.__proto__ = Node.prototype; diff --git a/node_modules/stylus/lib/nodes/keyframes.js b/node_modules/stylus/lib/nodes/keyframes.js new file mode 100644 index 0000000..8b8a169 --- /dev/null +++ b/node_modules/stylus/lib/nodes/keyframes.js @@ -0,0 +1,78 @@ + +/*! + * Stylus - Keyframes + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Keyframes` with the given `name`, + * and optional vendor `prefix`. + * + * @param {String} name + * @param {String} prefix + * @api public + */ + +var Keyframes = module.exports = function Keyframes(name, prefix){ + Node.call(this); + this.name = name; + this.frames = []; + this.prefix = prefix || 'official'; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Keyframes.prototype.__proto__ = Node.prototype; + +/** + * Push the given `block` at `pos`. + * + * @param {Array} pos + * @param {Block} block + * @api public + */ + +Keyframes.prototype.push = function(pos, block){ + this.frames.push({ + pos: pos + , block: block + }); +}; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Keyframes.prototype.clone = function(){ + var clone = new Keyframes(this.name); + clone.lineno = this.lineno; + clone.prefix = this.prefix; + clone.frames = this.frames.map(function(node){ + node.block = node.block.clone(); + return node; + }); + return clone; +}; + +/** + * Return `@keyframes name`. + * + * @return {String} + * @api public + */ + +Keyframes.prototype.toString = function(){ + return '@keyframes ' + this.name; +}; diff --git a/node_modules/stylus/lib/nodes/literal.js b/node_modules/stylus/lib/nodes/literal.js new file mode 100644 index 0000000..314329c --- /dev/null +++ b/node_modules/stylus/lib/nodes/literal.js @@ -0,0 +1,92 @@ + +/*! + * Stylus - Literal + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Literal` with the given `str`. + * + * @param {String} str + * @api public + */ + +var Literal = module.exports = function Literal(str){ + Node.call(this); + this.val = str; + this.string = str; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Literal.prototype.__proto__ = Node.prototype; + +/** + * Return hash. + * + * @return {String} + * @api public + */ + +Literal.prototype.__defineGetter__('hash', function(){ + return this.val; +}); + +/** + * Return literal value. + * + * @return {String} + * @api public + */ + +Literal.prototype.toString = function(){ + return this.val; +}; + +/** + * Coerce `other` to a literal. + * + * @param {Node} other + * @return {String} + * @api public + */ + +Literal.prototype.coerce = function(other){ + switch (other.nodeName) { + case 'ident': + case 'string': + case 'literal': + return new Literal(other.string); + default: + return Node.prototype.coerce.call(this, other); + } +}; + +/** + * Operate on `right` with the given `op`. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +Literal.prototype.operate = function(op, right){ + var val = right.first; + switch (op) { + case '+': + return new nodes.Literal(this.string + this.coerce(val).string); + default: + return Node.prototype.operate.call(this, op, right); + } +}; diff --git a/node_modules/stylus/lib/nodes/media.js b/node_modules/stylus/lib/nodes/media.js new file mode 100644 index 0000000..79382e4 --- /dev/null +++ b/node_modules/stylus/lib/nodes/media.js @@ -0,0 +1,55 @@ + +/*! + * Stylus - Media + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Media` with the given `val` + * + * @param {String} val + * @api public + */ + +var Media = module.exports = function Media(val){ + Node.call(this); + this.val = val; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Media.prototype.__proto__ = Node.prototype; + +/** + * Clone this node. + * + * @return {Media} + * @api public + */ + +Media.prototype.clone = function(){ + var clone = new Media(this.val); + clone.block = this.block.clone(); + return clone; +}; + +/** + * Return @media "val". + * + * @return {String} + * @api public + */ + +Media.prototype.toString = function(){ + return '@media ' + this.val; +}; diff --git a/node_modules/stylus/lib/nodes/member.js b/node_modules/stylus/lib/nodes/member.js new file mode 100644 index 0000000..2150f6d --- /dev/null +++ b/node_modules/stylus/lib/nodes/member.js @@ -0,0 +1,55 @@ + +/*! + * Stylus - Member + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var BinOp = require('./binop'); + +/** + * Initialize a new `Member` with `left` and `right`. + * + * @param {Node} left + * @param {Node} right + * @api public + */ + +var Member = module.exports = function Member(left, right){ + BinOp.call(this, '.', left, right); +}; + +/** + * Inherit from `BinOp.prototype`. + */ + +Member.prototype.__proto__ = BinOp.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Member.prototype.clone = function(){ + var clone = BinOp.prototype.clone.call(this); + clone.constructor = Member; + return clone; +}; + +/** + * Return a string representation of this node. + * + * @return {String} + * @api public + */ + +Member.prototype.toString = function(){ + return this.left.toString() + + '.' + this.right.toString(); +}; diff --git a/node_modules/stylus/lib/nodes/mozdocument.js b/node_modules/stylus/lib/nodes/mozdocument.js new file mode 100644 index 0000000..dc6b98e --- /dev/null +++ b/node_modules/stylus/lib/nodes/mozdocument.js @@ -0,0 +1,19 @@ +var Node = require('./node') + , nodes = require('./'); + +var MozDocument = module.exports = function MozDocument(val){ + Node.call(this); + this.val = val; +}; + +MozDocument.prototype.__proto__ = Node.prototype; + +MozDocument.prototype.clone = function(){ + var clone = new MozDocument(this.val); + clone.block = this.block.clone(); + return clone; +}; + +MozDocument.prototype.toString = function(){ + return '@-moz-document ' + this.val; +} diff --git a/node_modules/stylus/lib/nodes/node.js b/node_modules/stylus/lib/nodes/node.js new file mode 100644 index 0000000..583cd10 --- /dev/null +++ b/node_modules/stylus/lib/nodes/node.js @@ -0,0 +1,230 @@ + +/*! + * Stylus - Node + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Evaluator = require('../visitor/evaluator') + , utils = require('../utils') + , nodes = require('./'); + +/** + * Node constructor. + * + * @api public + */ + +var Node = module.exports = function Node(){ + this.lineno = nodes.lineno; + Object.defineProperty(this, 'filename', { writable: true, value: nodes.filename }); +}; + +/** + * Return this node. + * + * @return {Node} + * @api public + */ + +Node.prototype.__defineGetter__('first', function(){ + return this; +}); + +/** + * Return hash. + * + * @return {String} + * @api public + */ + +Node.prototype.__defineGetter__('hash', function(){ + return this.val; +}); + +/** + * Return node name. + * + * @return {String} + * @api public + */ + +Node.prototype.__defineGetter__('nodeName', function(){ + return this.constructor.name.toLowerCase(); +}); + +/** + * Return this node. + * + * @return {Node} + * @api public + */ + +Node.prototype.clone = function(){ + return this; +}; + +/** + * Nodes by default evaluate to themselves. + * + * @return {Node} + * @api public + */ + +Node.prototype.eval = function(){ + return new Evaluator(this).evaluate(); +}; + +/** + * Return true. + * + * @return {Boolean} + * @api public + */ + +Node.prototype.toBoolean = function(){ + return nodes.true; +}; + +/** + * Return the expression, or wrap this node in an expression. + * + * @return {Expression} + * @api public + */ + +Node.prototype.toExpression = function(){ + if ('expression' == this.nodeName) return this; + var expr = new nodes.Expression; + expr.push(this); + return expr; +}; + +/** + * Return false if `op` is generally not coerced. + * + * @param {String} op + * @return {Boolean} + * @api private + */ + +Node.prototype.shouldCoerce = function(op){ + switch (op) { + case 'is a': + case 'in': + case '||': + case '&&': + return false; + default: + return true; + } +}; + +/** + * Operate on `right` with the given `op`. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +Node.prototype.operate = function(op, right){ + switch (op) { + case 'is a': + if ('string' == right.nodeName) { + return nodes.Boolean(this.nodeName == right.val); + } else { + throw new Error('"is a" expects a string, got ' + right.toString()); + } + case '==': + return nodes.Boolean(this.hash == right.hash); + case '!=': + return nodes.Boolean(this.hash != right.hash); + case '>=': + return nodes.Boolean(this.hash >= right.hash); + case '<=': + return nodes.Boolean(this.hash <= right.hash); + case '>': + return nodes.Boolean(this.hash > right.hash); + case '<': + return nodes.Boolean(this.hash < right.hash); + case '||': + return this.toBoolean().isTrue + ? this + : right; + case 'in': + var vals = utils.unwrap(right).nodes + , len = vals.length + , hash = this.hash; + if (!vals) throw new Error('"in" given invalid right-hand operand, expecting an expression'); + + // 'prop' in obj + if (1 == len && 'object' == vals[0].nodeName) { + return nodes.Boolean(vals[0].has(this.hash)); + } + + for (var i = 0; i < len; ++i) { + if (hash == vals[i].hash) { + return nodes.true; + } + } + return nodes.false; + case '&&': + var a = this.toBoolean() + , b = right.toBoolean(); + return a.isTrue && b.isTrue + ? right + : a.isFalse + ? this + : right; + default: + if ('[]' == op) { + var msg = 'cannot perform ' + + this + + '[' + right + ']'; + } else { + var msg = 'cannot perform' + + ' ' + this + + ' ' + op + + ' ' + right; + } + throw new Error(msg); + } +}; + +/** + * Initialize a new `CoercionError` with the given `msg`. + * + * @param {String} msg + * @api private + */ + +function CoercionError(msg) { + this.name = 'CoercionError' + this.message = msg + Error.captureStackTrace(this, CoercionError); +} + +/** + * Inherit from `Error.prototype`. + */ + +CoercionError.prototype.__proto__ = Error.prototype; + +/** + * Default coercion throws. + * + * @param {Node} other + * @return {Node} + * @api public + */ + +Node.prototype.coerce = function(other){ + if (other.nodeName == this.nodeName) return other; + throw new CoercionError('cannot coerce ' + other + ' to ' + this.nodeName); +}; diff --git a/node_modules/stylus/lib/nodes/null.js b/node_modules/stylus/lib/nodes/null.js new file mode 100644 index 0000000..dea78bc --- /dev/null +++ b/node_modules/stylus/lib/nodes/null.js @@ -0,0 +1,72 @@ + +/*! + * Stylus - Null + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Null` node. + * + * @api public + */ + +var Null = module.exports = function Null(){}; + +/** + * Inherit from `Node.prototype`. + */ + +Null.prototype.__proto__ = Node.prototype; + +/** + * Return 'Null'. + * + * @return {String} + * @api public + */ + +Null.prototype.inspect = +Null.prototype.toString = function(){ + return 'null'; +}; + +/** + * Return false. + * + * @return {Boolean} + * @api public + */ + +Null.prototype.toBoolean = function(){ + return nodes.false; +}; + +/** + * Check if the node is a null node. + * + * @return {Boolean} + * @api public + */ + +Null.prototype.__defineGetter__('isNull', function(){ + return true; +}); + +/** + * Return hash. + * + * @return {String} + * @api public + */ + +Null.prototype.__defineGetter__('hash', function(){ + return null; +}); \ No newline at end of file diff --git a/node_modules/stylus/lib/nodes/object.js b/node_modules/stylus/lib/nodes/object.js new file mode 100644 index 0000000..3bc3efc --- /dev/null +++ b/node_modules/stylus/lib/nodes/object.js @@ -0,0 +1,142 @@ + +/*! + * Stylus - Object + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./') + , nativeObj = {}.constructor; + +/** + * Initialize a new `Object`. + * + * @api public + */ + +var Object = module.exports = function Object(){ + Node.call(this); + this.vals = {}; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Object.prototype.__proto__ = Node.prototype; + +/** + * Set `key` to `val`. + * + * @param {String} key + * @param {Node} val + * @return {Object} for chaining + * @api public + */ + +Object.prototype.set = function(key, val){ + this.vals[key] = val; + return this; +}; + +/** + * Return length. + * + * @return {Number} + * @api public + */ + +Object.prototype.__defineGetter__('length', function() { + return nativeObj.keys(this.vals).length; +}); + +/** + * Get `key`. + * + * @param {String} key + * @return {Node} + * @api public + */ + +Object.prototype.get = function(key){ + return this.vals[key] || nodes.null; +}; + +/** + * Has `key`? + * + * @param {String} key + * @return {Boolean} + * @api public + */ + +Object.prototype.has = function(key){ + return key in this.vals; +}; + +/** + * Operate on `right` with the given `op`. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +Object.prototype.operate = function(op, right){ + switch (op) { + case '.': + case '[]': + return this.get(right.hash); + default: + return Node.prototype.operate.call(this, op, right); + } +}; + +/** + * Return Boolean based on the length of this object. + * + * @return {Boolean} + * @api public + */ + +Object.prototype.toBoolean = function(){ + return nodes.Boolean(this.length); +}; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Object.prototype.clone = function(){ + var clone = new Object; + clone.lineno = this.lineno; + clone.filename = this.filename; + for (var key in this.vals) { + clone.vals[key] = this.vals[key].clone(); + } + return clone; +}; + +/** + * Return "{ : }" + * + * @return {String} + * @api public + */ + +Object.prototype.toString = function(){ + var obj = {}; + for (var prop in this.vals) { + obj[prop] = this.vals[prop].toString(); + } + return JSON.stringify(obj); +}; diff --git a/node_modules/stylus/lib/nodes/page.js b/node_modules/stylus/lib/nodes/page.js new file mode 100644 index 0000000..2a14595 --- /dev/null +++ b/node_modules/stylus/lib/nodes/page.js @@ -0,0 +1,43 @@ + +/*! + * Stylus - Page + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Page` with the given `selector` and `block`. + * + * @param {Selector} selector + * @param {Block} block + * @api public + */ + +var Page = module.exports = function Page(selector, block){ + Node.call(this); + this.selector = selector; + this.block = block; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Page.prototype.__proto__ = Node.prototype; + +/** + * Return `@page name`. + * + * @return {String} + * @api public + */ + +Page.prototype.toString = function(){ + return '@page ' + this.selector; +}; diff --git a/node_modules/stylus/lib/nodes/params.js b/node_modules/stylus/lib/nodes/params.js new file mode 100644 index 0000000..be67e65 --- /dev/null +++ b/node_modules/stylus/lib/nodes/params.js @@ -0,0 +1,72 @@ + +/*! + * Stylus - Params + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Params` with `name`, `params`, and `body`. + * + * @param {String} name + * @param {Params} params + * @param {Expression} body + * @api public + */ + +var Params = module.exports = function Params(){ + Node.call(this); + this.nodes = []; +}; + +/** + * Check function arity. + * + * @return {Boolean} + * @api public + */ + +Params.prototype.__defineGetter__('length', function(){ + return this.nodes.length; +}); + +/** + * Inherit from `Node.prototype`. + */ + +Params.prototype.__proto__ = Node.prototype; + +/** + * Push the given `node`. + * + * @param {Node} node + * @api public + */ + +Params.prototype.push = function(node){ + this.nodes.push(node); +}; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Params.prototype.clone = function(){ + var clone = new Params; + clone.lineno = this.lineno; + clone.filename = this.filename; + this.nodes.forEach(function(node){ + clone.push(node.clone()); + }); + return clone; +}; + diff --git a/node_modules/stylus/lib/nodes/property.js b/node_modules/stylus/lib/nodes/property.js new file mode 100644 index 0000000..363a347 --- /dev/null +++ b/node_modules/stylus/lib/nodes/property.js @@ -0,0 +1,73 @@ + +/*! + * Stylus - Property + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Property` with the given `segs` and optional `expr`. + * + * @param {Array} segs + * @param {Expression} expr + * @api public + */ + +var Property = module.exports = function Property(segs, expr){ + Node.call(this); + this.segments = segs; + this.expr = expr; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Property.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Property.prototype.clone = function(){ + var clone = new Property(this.segments); + clone.name = this.name; + clone.lineno = this.lineno; + clone.filename = this.filename; + clone.segments = this.segments.map(function(node){ return node.clone(); }); + if (this.expr) clone.expr = this.expr.clone(); + return clone; +}; + +/** + * Return string representation of this node. + * + * @return {String} + * @api public + */ + +Property.prototype.toString = function(){ + return 'property(' + this.segments.join('') + ', ' + this.expr + ')'; +}; + +/** + * Operate on the property expression. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +Property.prototype.operate = function(op, right, val){ + return this.expr.operate(op, right, val); +}; diff --git a/node_modules/stylus/lib/nodes/return.js b/node_modules/stylus/lib/nodes/return.js new file mode 100644 index 0000000..73680ae --- /dev/null +++ b/node_modules/stylus/lib/nodes/return.js @@ -0,0 +1,44 @@ + +/*! + * Stylus - Return + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Return` node with the given `expr`. + * + * @param {Expression} expr + * @api public + */ + +var Return = module.exports = function Return(expr){ + this.expr = expr || nodes.null; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Return.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Return.prototype.clone = function(){ + var clone = new Return(this.expr.clone()); + clone.lineno = this.lineno; + clone.filename = this.filename; + return clone; +}; \ No newline at end of file diff --git a/node_modules/stylus/lib/nodes/rgba.js b/node_modules/stylus/lib/nodes/rgba.js new file mode 100644 index 0000000..2d1022a --- /dev/null +++ b/node_modules/stylus/lib/nodes/rgba.js @@ -0,0 +1,337 @@ + +/*! + * Stylus - RGBA + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , HSLA = require('./hsla') + , functions = require('../functions') + , adjust = functions['-adjust'] + , nodes = require('./'); + +/** + * Initialize a new `RGBA` with the given r,g,b,a component values. + * + * @param {Number} r + * @param {Number} g + * @param {Number} b + * @param {Number} a + * @api public + */ + +var RGBA = exports = module.exports = function RGBA(r,g,b,a){ + Node.call(this); + this.r = clamp(r); + this.g = clamp(g); + this.b = clamp(b); + this.a = clampAlpha(a); + this.rgba = this; +}; + +/** + * Inherit from `Node.prototype`. + */ + +RGBA.prototype.__proto__ = Node.prototype; + +/** + * Return an `RGBA` without clamping values. + * + * @param {Number} r + * @param {Number} g + * @param {Number} b + * @param {Number} a + * @return {RGBA} + * @api public + */ + +RGBA.withoutClamping = function(r,g,b,a){ + var rgba = new RGBA(0,0,0,0); + rgba.r = r; + rgba.g = g; + rgba.b = b; + rgba.a = a; + return rgba; +}; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +RGBA.prototype.clone = function(){ + var clone = new RGBA( + this.r + , this.g + , this.b + , this.a); + clone.lineno = this.lineno; + clone.filename = this.filename; + return clone; +}; + +/** + * Return true. + * + * @return {Boolean} + * @api public + */ + +RGBA.prototype.toBoolean = function(){ + return nodes.true; +}; + +/** + * Return `HSLA` representation. + * + * @return {HSLA} + * @api public + */ + +RGBA.prototype.__defineGetter__('hsla', function(){ + return HSLA.fromRGBA(this); +}); + +/** + * Return hash. + * + * @return {String} + * @api public + */ + +RGBA.prototype.__defineGetter__('hash', function(){ + return this.toString(); +}); + +/** + * Add r,g,b,a to the current component values. + * + * @param {Number} r + * @param {Number} g + * @param {Number} b + * @param {Number} a + * @return {RGBA} new node + * @api public + */ + +RGBA.prototype.add = function(r,g,b,a){ + return new RGBA( + this.r + r + , this.g + g + , this.b + b + , this.a + a); +}; + +/** + * Subtract r,g,b,a from the current component values. + * + * @param {Number} r + * @param {Number} g + * @param {Number} b + * @param {Number} a + * @return {RGBA} new node + * @api public + */ + +RGBA.prototype.sub = function(r,g,b,a){ + return new RGBA( + this.r - r + , this.g - g + , this.b - b + , a == 1 ? this.a : this.a - a); +}; + +/** + * Multiply rgb components by `n`. + * + * @param {String} n + * @return {RGBA} new node + * @api public + */ + +RGBA.prototype.multiply = function(n){ + return new RGBA( + this.r * n + , this.g * n + , this.b * n + , this.a); +}; + +/** + * Divide rgb components by `n`. + * + * @param {String} n + * @return {RGBA} new node + * @api public + */ + +RGBA.prototype.divide = function(n){ + return new RGBA( + this.r / n + , this.g / n + , this.b / n + , this.a); +}; + +/** + * Operate on `right` with the given `op`. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +RGBA.prototype.operate = function(op, right){ + right = right.first; + + switch (op) { + case 'is a': + if ('string' == right.nodeName && 'color' == right.string) { + return nodes.true; + } + break; + case '+': + switch (right.nodeName) { + case 'unit': + var n = right.val; + switch (right.type) { + case '%': return adjust(this, new nodes.String('lightness'), right); + case 'deg': return this.hsla.adjustHue(n).rgba; + default: return this.add(n,n,n,0); + } + case 'rgba': + return this.add(right.r, right.g, right.b, right.a); + case 'hsla': + return this.hsla.add(right.h, right.s, right.l); + } + break; + case '-': + switch (right.nodeName) { + case 'unit': + var n = right.val; + switch (right.type) { + case '%': return adjust(this, new nodes.String('lightness'), new nodes.Unit(-n, '%')); + case 'deg': return this.hsla.adjustHue(-n).rgba; + default: return this.sub(n,n,n,0); + } + case 'rgba': + return this.sub(right.r, right.g, right.b, right.a); + case 'hsla': + return this.hsla.sub(right.h, right.s, right.l); + } + break; + case '*': + switch (right.nodeName) { + case 'unit': + return this.multiply(right.val); + } + break; + case '/': + switch (right.nodeName) { + case 'unit': + return this.divide(right.val); + } + break; + } + return Node.prototype.operate.call(this, op, right); +}; + +/** + * Return #nnnnnn, #nnn, or rgba(n,n,n,n) string representation of the color. + * + * @return {String} + * @api public + */ + +RGBA.prototype.toString = function(){ + function pad(n) { + return n < 16 + ? '0' + n.toString(16) + : n.toString(16); + } + + if (1 == this.a) { + var r = pad(this.r) + , g = pad(this.g) + , b = pad(this.b); + + // Compress + if (r[0] == r[1] && g[0] == g[1] && b[0] == b[1]) { + return '#' + r[0] + g[0] + b[0]; + } else { + return '#' + r + g + b; + } + } else { + return 'rgba(' + + this.r + ',' + + this.g + ',' + + this.b + ',' + + (+this.a.toFixed(3)) + ')'; + } +}; + +/** + * Return a `RGBA` from the given `hsla`. + * + * @param {HSLA} hsla + * @return {RGBA} + * @api public + */ + +exports.fromHSLA = function(hsla){ + var h = hsla.h / 360 + , s = hsla.s / 100 + , l = hsla.l / 100 + , a = hsla.a; + + var m2 = l <= .5 ? l * (s + 1) : l + s - l * s + , m1 = l * 2 - m2; + + var r = hue(h + 1/3) * 0xff + , g = hue(h) * 0xff + , b = hue(h - 1/3) * 0xff; + + function hue(h) { + if (h < 0) ++h; + if (h > 1) --h; + if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; + if (h * 2 < 1) return m2; + if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6; + return m1; + } + + return new RGBA(r,g,b,a); +}; + +/** + * Clamp `n` >= 0 and <= 255. + * + * @param {Number} n + * @return {Number} + * @api private + */ + +function clamp(n) { + return Math.max(0, Math.min(n.toFixed(0), 255)); +} + +/** + * Clamp alpha `n` >= 0 and <= 1. + * + * @param {Number} n + * @return {Number} + * @api private + */ + +function clampAlpha(n) { + return Math.max(0, Math.min(n, 1)); +} diff --git a/node_modules/stylus/lib/nodes/root.js b/node_modules/stylus/lib/nodes/root.js new file mode 100644 index 0000000..b606ec1 --- /dev/null +++ b/node_modules/stylus/lib/nodes/root.js @@ -0,0 +1,61 @@ + +/*! + * Stylus - Root + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Root` node. + * + * @api public + */ + +var Root = module.exports = function Root(){ + this.nodes = []; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Root.prototype.__proto__ = Node.prototype; + +/** + * Push a `node` to this block. + * + * @param {Node} node + * @api public + */ + +Root.prototype.push = function(node){ + this.nodes.push(node); +}; + +/** + * Unshift a `node` to this block. + * + * @param {Node} node + * @api public + */ + +Root.prototype.unshift = function(node){ + this.nodes.unshift(node); +}; + +/** + * Return "root". + * + * @return {String} + * @api public + */ + +Root.prototype.toString = function(){ + return '[Root]'; +}; diff --git a/node_modules/stylus/lib/nodes/selector.js b/node_modules/stylus/lib/nodes/selector.js new file mode 100644 index 0000000..5789796 --- /dev/null +++ b/node_modules/stylus/lib/nodes/selector.js @@ -0,0 +1,58 @@ + +/*! + * Stylus - Selector + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Block = require('./block') + , Node = require('./node'); + +/** + * Initialize a new `Selector` with the given `segs`. + * + * @param {Array} segs + * @api public + */ + +var Selector = module.exports = function Selector(segs){ + Node.call(this); + this.inherits = true; + this.segments = segs; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Selector.prototype.__proto__ = Node.prototype; + +/** + * Return the selector string. + * + * @return {String} + * @api public + */ + +Selector.prototype.toString = function(){ + return this.segments.join(''); +}; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Selector.prototype.clone = function(){ + var clone = new Selector; + clone.lineno = this.lineno; + clone.filename = this.filename; + clone.segments = this.segments.map(function(node){ return node.clone(); }); + return clone; +}; diff --git a/node_modules/stylus/lib/nodes/string.js b/node_modules/stylus/lib/nodes/string.js new file mode 100644 index 0000000..6a4f508 --- /dev/null +++ b/node_modules/stylus/lib/nodes/string.js @@ -0,0 +1,125 @@ +/*! + * Stylus - String + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , sprintf = require('../functions').s + , utils = require('../utils') + , nodes = require('./'); + +/** + * Initialize a new `String` with the given `val`. + * + * @param {String} val + * @param {String} quote + * @api public + */ + +var String = module.exports = function String(val, quote){ + Node.call(this); + this.val = val; + this.string = val; + if (typeof quote !== 'string') { + this.quote = "'"; + } else { + this.quote = quote; + } +}; + +/** + * Inherit from `Node.prototype`. + */ + +String.prototype.__proto__ = Node.prototype; + +/** + * Return quoted string. + * + * @return {String} + * @api public + */ + +String.prototype.toString = function(){ + return this.quote + this.val + this.quote; +}; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +String.prototype.clone = function(){ + var clone = new String(this.val, this.quote); + clone.lineno = this.lineno; + clone.filename = this.filename; + return clone; +}; + +/** + * Return Boolean based on the length of this string. + * + * @return {Boolean} + * @api public + */ + +String.prototype.toBoolean = function(){ + return nodes.Boolean(this.val.length); +}; + +/** + * Coerce `other` to a string. + * + * @param {Node} other + * @return {String} + * @api public + */ + +String.prototype.coerce = function(other){ + switch (other.nodeName) { + case 'string': + return other; + case 'expression': + return new String(other.nodes.map(function(node){ + return this.coerce(node).val; + }, this).join(' ')); + default: + return new String(other.toString()); + } +}; + +/** + * Operate on `right` with the given `op`. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +String.prototype.operate = function(op, right){ + switch (op) { + case '%': + var expr = new nodes.Expression; + expr.push(this); + + // constructargs + var args = 'expression' == right.nodeName + ? utils.unwrap(right).nodes + : [right]; + + // apply + return sprintf.apply(null, [expr].concat(args)); + case '+': + return new String(this.val + this.coerce(right).val); + default: + return Node.prototype.operate.call(this, op, right); + } +}; diff --git a/node_modules/stylus/lib/nodes/ternary.js b/node_modules/stylus/lib/nodes/ternary.js new file mode 100644 index 0000000..118fe19 --- /dev/null +++ b/node_modules/stylus/lib/nodes/ternary.js @@ -0,0 +1,51 @@ + +/*! + * Stylus - Ternary + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `Ternary` with `cond`, `trueExpr` and `falseExpr`. + * + * @param {Expression} cond + * @param {Expression} trueExpr + * @param {Expression} falseExpr + * @api public + */ + +var Ternary = module.exports = function Ternary(cond, trueExpr, falseExpr){ + Node.call(this); + this.cond = cond; + this.trueExpr = trueExpr; + this.falseExpr = falseExpr; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Ternary.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Ternary.prototype.clone = function(){ + var clone = new Ternary( + this.cond.clone() + , this.trueExpr.clone() + , this.falseExpr.clone()); + clone.lineno = this.lineno; + clone.filename = this.filename; + return clone; +}; \ No newline at end of file diff --git a/node_modules/stylus/lib/nodes/unaryop.js b/node_modules/stylus/lib/nodes/unaryop.js new file mode 100644 index 0000000..6d10bd6 --- /dev/null +++ b/node_modules/stylus/lib/nodes/unaryop.js @@ -0,0 +1,46 @@ + +/*! + * Stylus - UnaryOp + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node'); + +/** + * Initialize a new `UnaryOp` with `op`, and `expr`. + * + * @param {String} op + * @param {Node} expr + * @api public + */ + +var UnaryOp = module.exports = function UnaryOp(op, expr){ + Node.call(this); + this.op = op; + this.expr = expr; +}; + +/** + * Inherit from `Node.prototype`. + */ + +UnaryOp.prototype.__proto__ = Node.prototype; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +UnaryOp.prototype.clone = function(){ + var clone = new UnaryOp(this.op, this.expr.clone()); + clone.lineno = this.lineno; + clone.filename = this.filename; + return clone; +}; \ No newline at end of file diff --git a/node_modules/stylus/lib/nodes/unit.js b/node_modules/stylus/lib/nodes/unit.js new file mode 100644 index 0000000..d168010 --- /dev/null +++ b/node_modules/stylus/lib/nodes/unit.js @@ -0,0 +1,191 @@ + +/*! + * Stylus - Unit + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Node = require('./node') + , nodes = require('./'); + +/** + * Initialize a new `Unit` with the given `val` and unit `type` + * such as "px", "pt", "in", etc. + * + * @param {String} val + * @param {String} type + * @api public + */ + +var Unit = module.exports = function Unit(val, type){ + Node.call(this); + this.val = val; + this.type = type; +}; + +/** + * Inherit from `Node.prototype`. + */ + +Unit.prototype.__proto__ = Node.prototype; + +/** + * Return Boolean based on the unit value. + * + * @return {Boolean} + * @api public + */ + +Unit.prototype.toBoolean = function(){ + return nodes.Boolean(this.type + ? true + : this.val); +}; + +/** + * Return unit string. + * + * @return {String} + * @api public + */ + +Unit.prototype.toString = function(){ + var n = this.val; + if ('px' == this.type) n = n.toFixed(0); + return n + (this.type || ''); +}; + +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Unit.prototype.clone = function(){ + var clone = new Unit(this.val, this.type); + clone.lineno = this.lineno; + clone.filename = this.filename; + return clone; +}; + +/** + * Operate on `right` with the given `op`. + * + * @param {String} op + * @param {Node} right + * @return {Node} + * @api public + */ + +Unit.prototype.operate = function(op, right){ + var type = this.type || right.first.type; + + // swap color + if ('rgba' == right.nodeName || 'hsla' == right.nodeName) { + return right.operate(op, this); + } + + // operate + if (this.shouldCoerce(op)) { + right = right.first; + // percentages + if (('-' == op || '+' == op) && '%' == right.type) { + right = new Unit(this.val * (right.val / 100), '%'); + } else { + right = this.coerce(right); + } + + switch (op) { + case '-': + return new Unit(this.val - right.val, type); + case '+': + return new Unit(this.val + right.val, type); + case '/': + return new Unit(this.val / right.val, type); + case '*': + return new Unit(this.val * right.val, type); + case '%': + return new Unit(this.val % right.val, type); + case '**': + return new Unit(Math.pow(this.val, right.val), type); + case '..': + case '...': + var start = this.val + , end = right.val + , expr = new nodes.Expression + , inclusive = '..' == op; + do { + expr.push(new nodes.Unit(start)); + } while (inclusive ? ++start <= end : ++start < end); + return expr; + } + } + + return Node.prototype.operate.call(this, op, right); +}; + +/** + * Coerce `other` unit to the same type as `this` unit. + * + * Supports: + * + * mm -> cm | in + * cm -> mm | in + * in -> mm | cm + * + * ms -> s + * s -> ms + * + * Hz -> kHz + * kHz -> Hz + * + * @param {Unit} other + * @return {Unit} + * @api public + */ + +Unit.prototype.coerce = function(other){ + if ('unit' == other.nodeName) { + var a = this + , b = other + , factorA = factor(a) + , factorB = factor(b); + + if (factorA && factorB && (factorA.label == factorB.label)) { + var bVal = b.val * (factorB.val / factorA.val); + return new nodes.Unit(bVal, a.type); + } else { + return new nodes.Unit(b.val, a.type); + } + } else if ('string' == other.nodeName) { + var val = parseInt(other.val, 10); + if (isNaN(val)) Node.prototype.coerce.call(this, other); + return new nodes.Unit(val); + } else { + return Node.prototype.coerce.call(this, other); + } +}; + + +/** + * Convert a unit to base unit + */ +function factor(unit) { + var factorTable = { + 'mm': {val: 1, label: 'mm'}, + 'cm': {val: 10, label: 'mm'}, + 'in': {val: 25.4, label: 'mm'}, + 'ms': {val: 1, label: 'ms'}, + 's': {val: 1000, label: 'ms'}, + 'Hz': {val: 1, label: 'Hz'}, + 'kHz': {val: 1000, label: 'Hz'} + }; + + return factorTable[unit.type]; +}; + diff --git a/node_modules/stylus/lib/parser.js b/node_modules/stylus/lib/parser.js new file mode 100644 index 0000000..910ab4a --- /dev/null +++ b/node_modules/stylus/lib/parser.js @@ -0,0 +1,1717 @@ + +/*! + * Stylus - Parser + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Lexer = require('./lexer') + , nodes = require('./nodes') + , Token = require('./token') + , inspect = require('util').inspect + , errors = require('./errors'); + +// debuggers + +var debug = { + lexer: require('debug')('stylus:lexer') + , selector: require('debug')('stylus:parser:selector') +}; + +/** + * Selector composite tokens. + */ + +var selectorTokens = [ + 'ident' + , 'string' + , 'selector' + , 'function' + , 'comment' + , 'boolean' + , 'space' + , 'color' + , 'unit' + , 'for' + , 'in' + , '[' + , ']' + , '(' + , ')' + , '+' + , '-' + , '*' + , '*=' + , '<' + , '>' + , '=' + , ':' + , '&' + , '~' + , '{' + , '}' + , '.' +]; + +/** + * CSS3 pseudo-selectors. + */ + +var pseudoSelectors = [ + 'root' + , 'nth-child' + , 'nth-last-child' + , 'nth-of-type' + , 'nth-last-of-type' + , 'first-child' + , 'last-child' + , 'first-of-type' + , 'last-of-type' + , 'only-child' + , 'only-of-type' + , 'empty' + , 'link' + , 'visited' + , 'active' + , 'hover' + , 'focus' + , 'target' + , 'lang' + , 'enabled' + , 'disabled' + , 'checked' + , 'not' +]; + +/** + * Initialize a new `Parser` with the given `str` and `options`. + * + * @param {String} str + * @param {Object} options + * @api private + */ + +var Parser = module.exports = function Parser(str, options) { + var self = this; + options = options || {}; + this.lexer = new Lexer(str, options); + this.root = options.root || new nodes.Root; + this.state = ['root']; + this.stash = []; + this.parens = 0; + this.css = 0; + this.state.pop = function(){ + self.prevState = [].pop.call(this); + }; +}; + +/** + * Parser prototype. + */ + +Parser.prototype = { + + /** + * Constructor. + */ + + constructor: Parser, + + /** + * Return current state. + * + * @return {String} + * @api private + */ + + currentState: function() { + return this.state[this.state.length - 1]; + }, + + /** + * Return previous state. + * + * @return {String} + * @api private + */ + + previousState: function() { + return this.state[this.state.length - 2]; + }, + + /** + * Parse the input, then return the root node. + * + * @return {Node} + * @api private + */ + + parse: function(){ + var block = this.parent = this.root; + while ('eos' != this.peek().type) { + if (this.accept('newline')) continue; + var stmt = this.statement(); + this.accept(';'); + if (!stmt) this.error('unexpected token {peek}, not allowed at the root level'); + block.push(stmt); + } + return block; + }, + + /** + * Throw an `Error` with the given `msg`. + * + * @param {String} msg + * @api private + */ + + error: function(msg){ + var type = this.peek().type + , val = undefined == this.peek().val + ? '' + : ' ' + this.peek().toString(); + if (val.trim() == type.trim()) val = ''; + throw new errors.ParseError(msg.replace('{peek}', '"' + type + val + '"')); + }, + + /** + * Accept the given token `type`, and return it, + * otherwise return `undefined`. + * + * @param {String} type + * @return {Token} + * @api private + */ + + accept: function(type){ + if (type == this.peek().type) { + return this.next(); + } + }, + + /** + * Expect token `type` and return it, throw otherwise. + * + * @param {String} type + * @return {Token} + * @api private + */ + + expect: function(type){ + if (type != this.peek().type) { + this.error('expected "' + type + '", got {peek}'); + } + return this.next(); + }, + + /** + * Get the next token. + * + * @return {Token} + * @api private + */ + + next: function() { + var tok = this.stash.length + ? this.stash.pop() + : this.lexer.next(); + nodes.lineno = tok.lineno; + debug.lexer('%s %s', tok.type, tok.val || ''); + return tok; + }, + + /** + * Peek with lookahead(1). + * + * @return {Token} + * @api private + */ + + peek: function() { + return this.lexer.peek(); + }, + + /** + * Lookahead `n` tokens. + * + * @param {Number} n + * @return {Token} + * @api private + */ + + lookahead: function(n){ + return this.lexer.lookahead(n); + }, + + /** + * Check if the token at `n` is a valid selector token. + * + * @param {Number} n + * @return {Boolean} + * @api private + */ + + isSelectorToken: function(n) { + var la = this.lookahead(n).type; + switch (la) { + case 'for': + return this.bracketed; + case '[': + this.bracketed = true; + return true; + case ']': + this.bracketed = false; + return true; + default: + return ~selectorTokens.indexOf(la); + } + }, + + /** + * Check if the token at `n` is a pseudo selector. + * + * @param {Number} n + * @return {Boolean} + * @api private + */ + + isPseudoSelector: function(n){ + return ~pseudoSelectors.indexOf(this.lookahead(n).val.name); + }, + + /** + * Check if the current line contains `type`. + * + * @param {String} type + * @return {Boolean} + * @api private + */ + + lineContains: function(type){ + var i = 1 + , la; + + while (la = this.lookahead(i++)) { + if (~['indent', 'outdent', 'newline', 'eos'].indexOf(la.type)) return; + if (type == la.type) return true; + } + }, + + /** + * Valid selector tokens. + */ + + selectorToken: function() { + if (this.isSelectorToken(1)) { + if ('{' == this.peek().type) { + // unclosed, must be a block + if (!this.lineContains('}')) return; + // check if ':' is within the braces. + // though not required by Stylus, chances + // are if someone is using {} they will + // use CSS-style props, helping us with + // the ambiguity in this case + var i = 0 + , la; + while (la = this.lookahead(++i)) { + if ('}' == la.type) { + // Check empty block. + if (i == 2 || (i == 3 && this.lookahead(i - 1).type == 'space')) + return; + break; + } + if (':' == la.type) return; + } + } + return this.next(); + } + }, + + /** + * Consume whitespace. + */ + + skipWhitespace: function() { + while (~['space', 'indent', 'outdent', 'newline'].indexOf(this.peek().type)) + this.next(); + }, + + /** + * Consume newlines. + */ + + skipNewlines: function() { + while ('newline' == this.peek().type) + this.next(); + }, + + /** + * Consume spaces. + */ + + skipSpaces: function() { + while ('space' == this.peek().type) + this.next(); + }, + + /** + * Check if the following sequence of tokens + * forms a function definition, ie trailing + * `{` or indentation. + */ + + looksLikeFunctionDefinition: function(i) { + return 'indent' == this.lookahead(i).type + || '{' == this.lookahead(i).type; + }, + + /** + * Check if the following sequence of tokens + * forms a selector. + */ + + looksLikeSelector: function() { + var i = 1 + , brace; + + // Assume selector when an ident is + // followed by a selector + while ('ident' == this.lookahead(i).type + && 'newline' == this.lookahead(i + 1).type) i += 2; + + while (this.isSelectorToken(i) + || ',' == this.lookahead(i).type) { + + if ('selector' == this.lookahead(i).type) + return true; + + if ('ident' == this.lookahead(i).type && '.' == this.lookahead(i + 1).type) + return true; + + if (('=' == this.lookahead(i).type || 'function' == this.lookahead(i).type) + && '{' == this.lookahead(i + 1).type) + return false; + + if (':' == this.lookahead(i).type && !this.isPseudoSelector(i + 1) && this.lineContains('.')) + return false; + + // the ':' token within braces signifies + // a selector. ex: "foo{bar:'baz'}" + if ('{' == this.lookahead(i).type) brace = true; + else if ('}' == this.lookahead(i).type) brace = false; + if (brace && ':' == this.lookahead(i).type) return true; + + // '}' preceded by a space is considered a selector. + // for example "foo{bar}{baz}" may be a property, + // however "foo{bar} {baz}" is a selector + if ('space' == this.lookahead(i).type + && '{' == this.lookahead(i + 1).type) + return true; + + // Assume pseudo selectors are NOT properties + // as 'td:th-child(1)' may look like a property + // and function call to the parser otherwise + if (':' == this.lookahead(i++).type + && !this.lookahead(i-1).space + && this.isPseudoSelector(i)) + return true; + + if (',' == this.lookahead(i).type + && 'newline' == this.lookahead(i + 1).type) + return true; + } + + // Trailing comma + if (',' == this.lookahead(i).type + && 'newline' == this.lookahead(i + 1).type) + return true; + + // Trailing brace + if ('{' == this.lookahead(i).type + && 'newline' == this.lookahead(i + 1).type) + return true; + + // css-style mode, false on ; } + if (this.css) { + if (';' == this.lookahead(i) || + '}' == this.lookahead(i)) + return false; + } + + // Trailing separators + while (!~[ + 'indent' + , 'outdent' + , 'newline' + , 'for' + , 'if' + , ';' + , '}' + , 'eos'].indexOf(this.lookahead(i).type)) + ++i; + + if ('indent' == this.lookahead(i).type) + return true; + }, + + /** + * Check if the current state allows object literal. + */ + + stateAllowsObject: function() { + switch (this.previousState()) { + case 'conditional': + case 'for': + return false; + // if a == 1 { + // if a = 1 { + case 'expression': + case 'assignment': + return !this.cond; + } + return true; + }, + + /** + * Check if the current state supports selectors. + */ + + stateAllowsSelector: function() { + switch (this.currentState()) { + case 'root': + case 'selector': + case 'conditional': + case 'keyframe': + case 'function': + case 'font-face': + case 'media': + case '-moz-document': + case 'for': + return true; + } + }, + + /** + * statement + * | statement 'if' expression + * | statement 'unless' expression + */ + + statement: function() { + var stmt = this.stmt() + , state = this.prevState + , block + , op; + + // special-case statements since it + // is not an expression. We could + // implement postfix conditionals at + // the expression level, however they + // would then fail to enclose properties + if (this.allowPostfix) { + delete this.allowPostfix; + state = 'expression'; + } + + switch (state) { + case 'assignment': + case 'expression': + case 'function arguments': + while (op = + this.accept('if') + || this.accept('unless') + || this.accept('for')) { + switch (op.type) { + case 'if': + case 'unless': + stmt = new nodes.If(this.expression(), stmt); + stmt.postfix = true; + stmt.negate = 'unless' == op.type; + this.accept(';'); + break; + case 'for': + var key + , val = this.id().name; + if (this.accept(',')) key = this.id().name; + this.expect('in'); + var each = new nodes.Each(val, key, this.expression()); + block = new nodes.Block; + block.push(stmt); + each.block = block; + stmt = each; + } + } + } + + return stmt; + }, + + /** + * ident + * | selector + * | literal + * | charset + * | import + * | media + * | scope + * | keyframes + * | page + * | for + * | if + * | unless + * | comment + * | expression + * | 'return' expression + */ + + stmt: function() { + var type = this.peek().type; + switch (type) { + case '-webkit-keyframes': + case 'keyframes': + return this.keyframes(); + case 'font-face': + return this.fontface(); + case '-moz-document': + return this.mozdocument(); + case 'comment': + case 'selector': + case 'literal': + case 'charset': + case 'import': + case 'extend': + case 'media': + case 'page': + case 'ident': + case 'scope': + case 'unless': + case 'function': + case 'for': + case 'if': + return this[type](); + case 'return': + return this.return(); + case '{': + return this.property(); + default: + // Contextual selectors + if (this.stateAllowsSelector()) { + switch (type) { + case 'color': + case '~': + case '+': + case '>': + case '<': + case ':': + case '&': + case '[': + case '.': + return this.selector(); + case '*': + return this.property(); + case '-': + if ('{' == this.lookahead(2).type) + return this.property(); + } + } + + // Expression fallback + var expr = this.expression(); + if (expr.isEmpty) this.error('unexpected {peek}'); + return expr; + } + }, + + /** + * indent (!outdent)+ outdent + */ + + block: function(node, scope) { + var delim + , stmt + , block = this.parent = new nodes.Block(this.parent, node); + + if (false === scope) block.scope = false; + + // css-style + if (this.accept('{')) { + this.css++; + delim = '}'; + this.skipWhitespace(); + } else { + delim = 'outdent'; + this.expect('indent'); + } + + while (delim != this.peek().type) { + // css-style + if (this.css) { + if (this.accept('newline')) continue; + stmt = this.statement(); + this.accept(';'); + this.skipWhitespace(); + } else { + if (this.accept('newline')) continue; + stmt = this.statement(); + this.accept(';'); + } + if (!stmt) this.error('unexpected token {peek} in block'); + block.push(stmt); + } + + // css-style + if (this.css) { + this.skipWhitespace(); + this.expect('}'); + this.skipSpaces(); + this.css--; + } else { + this.expect('outdent'); + } + + this.parent = block.parent; + return block; + }, + + /** + * comment space* + */ + + comment: function(){ + var node = this.next().val; + this.skipSpaces(); + return node; + }, + + /** + * for val (',' key) in expr + */ + + for: function() { + this.expect('for'); + var key + , val = this.id().name; + if (this.accept(',')) key = this.id().name; + this.expect('in'); + this.state.push('for'); + var each = new nodes.Each(val, key, this.expression()); + each.block = this.block(each, false); + this.state.pop(); + return each; + }, + + /** + * return expression + */ + + return: function() { + this.expect('return'); + var expr = this.expression(); + return expr.isEmpty + ? new nodes.Return + : new nodes.Return(expr); + }, + + /** + * unless expression block + */ + + unless: function() { + this.expect('unless'); + this.state.push('conditional'); + this.cond = true; + var node = new nodes.If(this.expression(), true); + this.cond = false; + node.block = this.block(node, false); + this.state.pop(); + return node; + }, + + /** + * if expression block (else block)? + */ + + if: function() { + this.expect('if'); + this.state.push('conditional'); + this.cond = true; + var node = new nodes.If(this.expression()) + , cond + , block; + this.cond = false; + node.block = this.block(node, false); + while (this.accept('else')) { + if (this.accept('if')) { + this.cond = true; + cond = this.expression(); + this.cond = false; + block = this.block(node, false); + node.elses.push(new nodes.If(cond, block)); + } else { + node.elses.push(this.block(node, false)); + break; + } + } + this.state.pop(); + return node; + }, + + /** + * scope + */ + + scope: function(){ + var val = this.expect('scope').val; + this.selectorScope = val; + return nodes.null; + }, + + /** + * extend + */ + + extend: function(){ + var val = this.expect('extend').val + , arr = this.selectorParts(); + + arr.unshift(new nodes.Literal(val)); + + return new nodes.Extend(new nodes.Selector(arr)); + }, + + /** + * media + */ + + media: function() { + var val = this.expect('media').val + , media = new nodes.Media(val); + this.state.push('media'); + media.block = this.block(media); + this.state.pop(); + return media; + }, + + /** + * @-moz-document block + */ + + mozdocument: function(){ + var val = this.expect('-moz-document').val + , mozdocument = new nodes.MozDocument(val); + this.state.push('-moz-document'); + mozdocument.block = this.block(mozdocument, false); + this.state.pop(); + return mozdocument; + }, + + /** + * fontface + */ + + fontface: function() { + this.expect('font-face'); + var node = new nodes.FontFace; + this.state.push('font-face'); + node.block = this.block(node); + this.state.pop(); + return node; + }, + + /** + * import expression + */ + + import: function() { + this.expect('import'); + this.allowPostfix = true; + return new nodes.Import(this.expression()); + }, + + /** + * charset string + */ + + charset: function() { + this.expect('charset'); + var str = this.expect('string').val; + this.allowPostfix = true; + return new nodes.Charset(str); + }, + + /** + * page selector? block + */ + + page: function() { + var selector; + this.expect('page'); + if (this.accept(':')) { + var str = this.expect('ident').val.name; + selector = new nodes.Literal(':' + str); + } + var page = new nodes.Page(selector); + this.skipSpaces(); + this.state.push('page'); + page.block = this.block(page); + this.state.pop(); + return page; + }, + + /** + * keyframes name ( + * (unit | from | to) + * (',' (unit | from | to)*) + * block)+ + */ + + keyframes: function() { + var pos + , tok = this.expect('keyframes') + , keyframes = new nodes.Keyframes(this.id(), tok.val) + , vals = []; + + // css-style + if (this.accept('{')) { + this.css++; + this.skipWhitespace(); + } else { + this.expect('indent'); + } + + this.skipNewlines(); + + while (pos = this.accept('unit') || this.accept('ident')) { + // from | to + if ('ident' == pos.type) { + this.accept('space'); + switch (pos.val.name) { + case 'from': + pos = new nodes.Unit(0, '%'); + break; + case 'to': + pos = new nodes.Unit(100, '%'); + break; + default: + this.error('"' + pos.val.name + '" is invalid, use "from" or "to"'); + } + } else { + pos = pos.val; + } + + vals.push(pos); + + // ',' + if (this.accept(',') || this.accept('newline')) continue; + + // block + this.state.push('keyframe'); + var block = this.block(keyframes); + keyframes.push(vals, block); + vals = []; + this.state.pop(); + if (this.css) this.skipWhitespace(); + this.skipNewlines(); + } + + // css-style + if (this.css) { + this.skipWhitespace(); + this.expect('}'); + this.css--; + } else { + this.expect('outdent'); + } + + return keyframes; + }, + + /** + * literal + */ + + literal: function() { + return this.expect('literal').val; + }, + + /** + * ident space? + */ + + id: function() { + var tok = this.expect('ident'); + this.accept('space'); + return tok.val; + }, + + /** + * ident + * | assignment + * | property + * | selector + */ + + ident: function() { + var i = 2 + , la = this.lookahead(i).type + , isSelector; + + while ('space' == la) la = this.lookahead(++i).type; + + switch (la) { + // Assignment + case '=': + case '?=': + case '-=': + case '+=': + case '*=': + case '/=': + case '%=': + return this.assignment(); + // Assignment []= + case '[': + if (this._ident == this.peek()) return this.id(); + while (']' != this.lookahead(i++).type + && 'selector' != this.lookahead(i).type + && 'eos' != this.lookahead(i).type) ; + isSelector = this.looksLikeSelector() && this.stateAllowsSelector(); + if ('=' == this.lookahead(i).type || ('[' == this.lookahead(i).type && !isSelector)) { + this._ident = this.peek(); + return this.expression(); + } else if (isSelector) { + return this.selector(); + } + // Operation + case '-': + case '+': + case '/': + case '*': + case '%': + case '**': + case 'and': + case 'or': + case '&&': + case '||': + case '>': + case '<': + case '>=': + case '<=': + case '!=': + case '==': + case '?': + case 'in': + case 'is a': + case 'is defined': + // Prevent cyclic .ident, return literal + if (this._ident == this.peek()) { + return this.id(); + } else { + this._ident = this.peek(); + switch (this.currentState()) { + // unary op or selector in property / for + case 'for': + case 'selector': + return this.property(); + // Part of a selector + case 'root': + case 'media': + case '-moz-document': + case 'font-face': + return this.selector(); + case 'function': + return this.looksLikeSelector() + ? this.selector() + : this.expression(); + // Do not disrupt the ident when an operand + default: + return this.operand + ? this.id() + : this.expression(); + } + } + // Selector or property + default: + switch (this.currentState()) { + case 'root': + return this.selector(); + case 'for': + case 'page': + case 'media': + case '-moz-document': + case 'font-face': + case 'selector': + case 'function': + case 'keyframe': + case 'conditional': + return this.property(); + default: + return this.id(); + } + } + }, + + /** + * '*'? (ident | '{' expression '}')+ + */ + + interpolate: function() { + var node + , segs = [] + , star; + + star = this.accept('*'); + if (star) segs.push(new nodes.Literal('*')); + + while (true) { + if (this.accept('{')) { + this.state.push('interpolation'); + segs.push(this.expression()); + this.expect('}'); + this.state.pop(); + } else if (node = this.accept('-')){ + segs.push(new nodes.Literal('-')); + } else if (node = this.accept('ident')){ + segs.push(node.val); + } else { + break; + } + } + if (!segs.length) this.expect('ident'); + return segs; + }, + + /** + * property ':'? expression + * | ident + */ + + property: function() { + if (this.looksLikeSelector()) return this.selector(); + + // property + var ident = this.interpolate() + , prop = new nodes.Property(ident) + , ret = prop; + + // optional ':' + this.accept('space'); + if (this.accept(':')) this.accept('space'); + + this.state.push('property'); + this.inProperty = true; + prop.expr = this.list(); + if (prop.expr.isEmpty) ret = ident[0]; + this.inProperty = false; + this.allowPostfix = true; + this.state.pop(); + + // optional ';' + this.accept(';'); + + return ret; + }, + + /** + * selector ',' selector + * | selector newline selector + * | selector block + */ + + selector: function() { + var arr + , group = new nodes.Group + , scope = this.selectorScope + , isRoot = 'root' == this.currentState(); + + do { + // Clobber newline after , + this.accept('newline'); + + arr = this.selectorParts(); + + // Push the selector + if (isRoot && scope) arr.unshift(new nodes.Literal(scope + ' ')); + if (arr.length) group.push(new nodes.Selector(arr)); + } while (this.accept(',') || this.accept('newline')); + + this.state.push('selector'); + group.block = this.block(group); + this.state.pop(); + + return group; + }, + + selectorParts: function(){ + var tok + , arr = []; + + // Selector candidates, + // stitched together to + // form a selector. + while (tok = this.selectorToken()) { + debug.selector('%s', tok); + // Selector component + switch (tok.type) { + case '{': + this.skipSpaces(); + var expr = this.expression(); + this.skipSpaces(); + this.expect('}'); + arr.push(expr); + break; + case 'comment': + arr.push(new nodes.Literal(tok.val.str)); + break; + case 'color': + arr.push(new nodes.Literal(tok.val.raw)); + break; + case 'space': + arr.push(new nodes.Literal(' ')); + break; + case 'function': + arr.push(new nodes.Literal(tok.val.name + '(')); + break; + case 'ident': + arr.push(new nodes.Literal(tok.val.name)); + break; + default: + arr.push(new nodes.Literal(tok.val)); + if (tok.space) arr.push(new nodes.Literal(' ')); + } + } + + return arr; + }, + + /** + * ident ('=' | '?=') expression + */ + + assignment: function() { + var op + , node + , name = this.id().name; + + if (op = + this.accept('=') + || this.accept('?=') + || this.accept('+=') + || this.accept('-=') + || this.accept('*=') + || this.accept('/=') + || this.accept('%=')) { + this.state.push('assignment'); + var expr = this.list(); + if (expr.isEmpty) this.error('invalid right-hand side operand in assignment, got {peek}') + node = new nodes.Ident(name, expr); + this.state.pop(); + + switch (op.type) { + case '?=': + var defined = new nodes.BinOp('is defined', node) + , lookup = new nodes.Ident(name); + node = new nodes.Ternary(defined, lookup, node); + break; + case '+=': + case '-=': + case '*=': + case '/=': + case '%=': + node.val = new nodes.BinOp(op.type[0], new nodes.Ident(name), expr); + break; + } + } + + return node; + }, + + /** + * definition + * | call + */ + + function: function() { + var parens = 1 + , i = 2 + , tok; + + // Lookahead and determine if we are dealing + // with a function call or definition. Here + // we pair parens to prevent false negatives + out: + while (tok = this.lookahead(i++)) { + switch (tok.type) { + case 'function': + case '(': + ++parens; + break; + case ')': + if (!--parens) break out; + break; + case 'eos': + this.error('failed to find closing paren ")"'); + } + } + + // Definition or call + switch (this.currentState()) { + case 'expression': + return this.functionCall(); + default: + return this.looksLikeFunctionDefinition(i) + ? this.functionDefinition() + : this.expression(); + } + }, + + /** + * url '(' (expression | urlchars)+ ')' + */ + + url: function() { + this.expect('function'); + this.state.push('function arguments'); + var args = this.args(); + this.expect(')'); + this.state.pop(); + return new nodes.Call('url', args); + }, + + /** + * ident '(' expression ')' + */ + + functionCall: function() { + if ('url' == this.peek().val.name) return this.url(); + var name = this.expect('function').val.name; + this.state.push('function arguments'); + this.parens++; + var args = this.args(); + this.expect(')'); + this.parens--; + this.state.pop(); + return new nodes.Call(name, args); + }, + + /** + * ident '(' params ')' block + */ + + functionDefinition: function() { + var name = this.expect('function').val.name; + + // params + this.state.push('function params'); + this.skipWhitespace(); + var params = this.params(); + this.skipWhitespace(); + this.expect(')'); + this.state.pop(); + + // Body + this.state.push('function'); + var fn = new nodes.Function(name, params); + fn.block = this.block(fn); + this.state.pop(); + return new nodes.Ident(name, fn); + }, + + /** + * ident + * | ident '...' + * | ident '=' expression + * | ident ',' ident + */ + + params: function() { + var tok + , node + , params = new nodes.Params; + while (tok = this.accept('ident')) { + this.accept('space'); + params.push(node = tok.val); + if (this.accept('...')) { + node.rest = true; + } else if (this.accept('=')) { + node.val = this.expression(); + } + this.skipWhitespace(); + this.accept(','); + this.skipWhitespace(); + } + return params; + }, + + /** + * (ident ':')? expression (',' (ident ':')? expression)* + */ + + args: function() { + var args = new nodes.Arguments + , keyword; + + do { + // keyword + if ('ident' == this.peek().type && ':' == this.lookahead(2).type) { + keyword = this.next().val.string; + this.expect(':'); + args.map[keyword] = this.expression(); + // arg + } else { + args.push(this.expression()); + } + } while (this.accept(',')); + + return args; + }, + + /** + * expression (',' expression)* + */ + + list: function() { + var node = this.expression(); + while (this.accept(',')) { + if (node.isList) { + list.push(this.expression()); + } else { + var list = new nodes.Expression(true); + list.push(node); + list.push(this.expression()); + node = list; + } + } + return node; + }, + + /** + * negation+ + */ + + expression: function() { + var node + , expr = new nodes.Expression; + this.state.push('expression'); + while (node = this.negation()) { + if (!node) this.error('unexpected token {peek} in expression'); + expr.push(node); + } + this.state.pop(); + return expr; + }, + + /** + * 'not' ternary + * | ternary + */ + + negation: function() { + if (this.accept('not')) { + return new nodes.UnaryOp('!', this.negation()); + } + return this.ternary(); + }, + + /** + * logical ('?' expression ':' expression)? + */ + + ternary: function() { + var node = this.logical(); + if (this.accept('?')) { + var trueExpr = this.expression(); + this.expect(':'); + var falseExpr = this.expression(); + node = new nodes.Ternary(node, trueExpr, falseExpr); + } + return node; + }, + + /** + * typecheck (('&&' | '||') typecheck)* + */ + + logical: function() { + var op + , node = this.typecheck(); + while (op = this.accept('&&') || this.accept('||')) { + node = new nodes.BinOp(op.type, node, this.typecheck()); + } + return node; + }, + + /** + * equality ('is a' equality)* + */ + + typecheck: function() { + var op + , node = this.equality(); + while (op = this.accept('is a')) { + this.operand = true; + if (!node) this.error('illegal unary "' + op + '", missing left-hand operand'); + node = new nodes.BinOp(op.type, node, this.equality()); + this.operand = false; + } + return node; + }, + + /** + * in (('==' | '!=') in)* + */ + + equality: function() { + var op + , node = this.in(); + while (op = this.accept('==') || this.accept('!=')) { + this.operand = true; + if (!node) this.error('illegal unary "' + op + '", missing left-hand operand'); + node = new nodes.BinOp(op.type, node, this.in()); + this.operand = false; + } + return node; + }, + + /** + * relational ('in' relational)* + */ + + in: function() { + var node = this.relational(); + while (this.accept('in')) { + this.operand = true; + if (!node) this.error('illegal unary "in", missing left-hand operand'); + node = new nodes.BinOp('in', node, this.relational()); + this.operand = false; + } + return node; + }, + + /** + * range (('>=' | '<=' | '>' | '<') range)* + */ + + relational: function() { + var op + , node = this.range(); + while (op = + this.accept('>=') + || this.accept('<=') + || this.accept('<') + || this.accept('>') + ) { + this.operand = true; + if (!node) this.error('illegal unary "' + op + '", missing left-hand operand'); + node = new nodes.BinOp(op.type, node, this.range()); + this.operand = false; + } + return node; + }, + + /** + * additive (('..' | '...') additive)* + */ + + range: function() { + var op + , node = this.additive(); + if (op = this.accept('...') || this.accept('..')) { + this.operand = true; + if (!node) this.error('illegal unary "' + op + '", missing left-hand operand'); + node = new nodes.BinOp(op.val, node, this.additive()); + this.operand = false; + } + return node; + }, + + /** + * multiplicative (('+' | '-') multiplicative)* + */ + + additive: function() { + var op + , node = this.multiplicative(); + while (op = this.accept('+') || this.accept('-')) { + this.operand = true; + node = new nodes.BinOp(op.type, node, this.multiplicative()); + this.operand = false; + } + return node; + }, + + /** + * defined (('**' | '*' | '/' | '%') defined)* + */ + + multiplicative: function() { + var op + , node = this.defined(); + while (op = + this.accept('**') + || this.accept('*') + || this.accept('/') + || this.accept('%')) { + this.operand = true; + if ('/' == op && this.inProperty && !this.parens) { + this.stash.push(new Token('literal', new nodes.Literal('/'))); + this.operand = false; + return node; + } else { + if (!node) this.error('illegal unary "' + op + '", missing left-hand operand'); + node = new nodes.BinOp(op.type, node, this.defined()); + this.operand = false; + } + } + return node; + }, + + /** + * unary 'is defined' + * | unary + */ + + defined: function() { + var node = this.unary(); + if (this.accept('is defined')) { + if (!node) this.error('illegal unary "is defined", missing left-hand operand'); + node = new nodes.BinOp('is defined', node); + } + return node; + }, + + /** + * ('!' | '~' | '+' | '-') unary + * | subscript + */ + + unary: function() { + var op + , node; + if (op = + this.accept('!') + || this.accept('~') + || this.accept('+') + || this.accept('-')) { + this.operand = true; + node = new nodes.UnaryOp(op.type, this.unary()); + this.operand = false; + return node; + } + return this.subscript(); + }, + + /** + * member ('[' expression ']' ('.' id)? '='?)+ + * | member + */ + + subscript: function() { + var node = this.member() + , id; + while (this.accept('[')) { + node = new nodes.BinOp('[]', node, this.expression()); + this.expect(']'); + if (this.accept('.')) { + id = new nodes.Ident(this.expect('ident').val.string); + node = new nodes.Member(node, id); + } + // TODO: TernaryOp :) + if (this.accept('=')) { + node.op += '='; + node.val = this.expression(); + } + } + return node; + }, + + /** + * primary ('.' id)+ + * | primary + */ + + member: function() { + var node = this.primary(); + if (node) { + while (this.accept('.')) { + var id = new nodes.Ident(this.expect('ident').val.string); + node = new nodes.Member(node, id); + } + this.skipSpaces(); + } + return node; + }, + + /** + * '{' '}' + * | '{' pair (ws pair)* '}' + */ + + object: function(){ + var id, val; + var obj = new nodes.Object; + this.expect('{'); + this.skipWhitespace(); + + while (!this.accept('}')) { + id = this.accept('ident') || this.accept('string'); + if (!id) this.error('expected "ident" or "string", got {peek}'); + id = id.val.hash; + this.expect(':'); + val = this.expression(); + obj.set(id, val); + this.accept(','); + this.skipWhitespace(); + } + + return obj; + }, + + /** + * unit + * | null + * | color + * | string + * | ident + * | boolean + * | literal + * | object + * | '(' expression ')' '%'? + */ + + primary: function() { + var op + , node; + + // Parenthesis + if (this.accept('(')) { + ++this.parens; + var expr = this.expression(); + this.expect(')'); + --this.parens; + if (this.accept('%')) expr.push(new nodes.Ident('%')); + return expr; + } + + // Primitive + switch (this.peek().type) { + case 'null': + case 'unit': + case 'color': + case 'string': + case 'literal': + case 'boolean': + return this.next().val; + case '{': + if (this.stateAllowsObject()) return this.object(); + return; + case 'ident': + return this.ident(); + case 'function': + return this.functionCall(); + } + } +}; diff --git a/node_modules/stylus/lib/renderer.js b/node_modules/stylus/lib/renderer.js new file mode 100644 index 0000000..aa53f5b --- /dev/null +++ b/node_modules/stylus/lib/renderer.js @@ -0,0 +1,200 @@ + +/*! + * Stylus - Renderer + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Parser = require('./parser') + , EventEmitter = require('events').EventEmitter + , Compiler = require('./visitor/compiler') + , Evaluator = require('./visitor/evaluator') + , Normalizer = require('./visitor/normalizer') + , events = new EventEmitter + , utils = require('./utils') + , nodes = require('./nodes') + , path = require('path') + , join = path.join; + +/** + * Expose `Renderer`. + */ + +module.exports = Renderer; + +/** + * Initialize a new `Renderer` with the given `str` and `options`. + * + * @param {String} str + * @param {Object} options + * @api public + */ + +function Renderer(str, options) { + options = options || {}; + options.globals = {}; + options.functions = {}; + options.imports = [join(__dirname, 'functions')]; + options.paths = options.paths || []; + options.filename = options.filename || 'stylus'; + options.Evaluator = options.Evaluator || Evaluator; + this.options = options; + this.str = str; + this.events = events; +}; + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Renderer.prototype.__proto__ = EventEmitter.prototype; + +/** + * Expose events explicitly. + */ + +module.exports.events = events; + +/** + * Parse and evaluate AST, then callback `fn(err, css, js)`. + * + * @param {Function} fn + * @api public + */ + +Renderer.prototype.render = function(fn){ + var parser = this.parser = new Parser(this.str, this.options); + try { + nodes.filename = this.options.filename; + // parse + var ast = parser.parse(); + + // evaluate + this.evaluator = new this.options.Evaluator(ast, this.options); + this.nodes = nodes; + this.evaluator.renderer = this; + ast = this.evaluator.evaluate(); + + // normalize + var normalizer = new Normalizer(ast, this.options); + ast = normalizer.normalize(); + + // compile + var compiler = new Compiler(ast, this.options) + , css = compiler.compile(); + + var listeners = this.listeners('end'); + if (fn) listeners.push(fn); + for (var i = 0, len = listeners.length; i < len; i++) { + var ret = listeners[i](null, css); + if (ret) css = ret; + } + if (!fn) return css; + } catch (err) { + var options = {}; + options.input = err.input || this.str; + options.filename = err.filename || this.options.filename; + options.lineno = err.lineno || parser.lexer.lineno; + if (!fn) throw utils.formatException(err, options); + fn(utils.formatException(err, options)); + } +}; + +/** + * Set option `key` to `val`. + * + * @param {String} key + * @param {Mixed} val + * @return {Renderer} for chaining + * @api public + */ + +Renderer.prototype.set = function(key, val){ + this.options[key] = val; + return this; +}; + +/** + * Get option `key`. + * + * @param {String} key + * @return {Mixed} val + * @api public + */ + +Renderer.prototype.get = function(key){ + return this.options[key]; +}; + +/** + * Include the given `path` to the lookup paths array. + * + * @param {String} path + * @return {Renderer} for chaining + * @api public + */ + +Renderer.prototype.include = function(path){ + this.options.paths.push(path); + return this; +}; + +/** + * Use the given `fn`. + * + * This allows for plugins to alter the renderer in + * any way they wish, exposing paths etc. + * + * @param {Function} + * @return {Renderer} for chaining + * @api public + */ + +Renderer.prototype.use = function(fn){ + fn.call(this, this); + return this; +}; + +/** + * Define function or global var with the given `name`. Optionally + * the function may accept full expressions, by setting `raw` + * to `true`. + * + * @param {String} name + * @param {Function|Node} fn + * @return {Renderer} for chaining + * @api public + */ + +Renderer.prototype.define = function(name, fn, raw){ + fn = utils.coerce(fn); + + if (fn.nodeName) { + this.options.globals[name] = fn; + return this; + } + + // function + this.options.functions[name] = fn; + if (undefined != raw) fn.raw = raw; + return this; +}; + +/** + * Import the given `file`. + * + * @param {String} file + * @return {Renderer} for chaining + * @api public + */ + +Renderer.prototype.import = function(file){ + this.options.imports.push(file); + return this; +}; + + diff --git a/node_modules/stylus/lib/stack/frame.js b/node_modules/stylus/lib/stack/frame.js new file mode 100644 index 0000000..580f9cb --- /dev/null +++ b/node_modules/stylus/lib/stack/frame.js @@ -0,0 +1,66 @@ + +/*! + * Stylus - stack - Frame + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Scope = require('./scope') + , blocks = require('../nodes'); + +/** + * Initialize a new `Frame` with the given `block`. + * + * @param {Block} block + * @api private + */ + +var Frame = module.exports = function Frame(block) { + this._scope = false === block.scope + ? null + : new Scope; + this.block = block; +}; + +/** + * Return this frame's scope or the parent scope + * for scope-less blocks. + * + * @return {Scope} + * @api public + */ + +Frame.prototype.__defineGetter__('scope', function(){ + return this._scope || this.parent.scope; +}); + +/** + * Lookup the given local variable `name`. + * + * @param {String} name + * @return {Node} + * @api private + */ + +Frame.prototype.lookup = function(name){ + return this.scope.lookup(name) +}; + +/** + * Custom inspect. + * + * @return {String} + * @api public + */ + +Frame.prototype.inspect = function(){ + return '[Frame ' + + (false === this.block.scope + ? 'scope-less' + : this.scope.inspect()) + + ']'; +}; diff --git a/node_modules/stylus/lib/stack/index.js b/node_modules/stylus/lib/stack/index.js new file mode 100644 index 0000000..5c59458 --- /dev/null +++ b/node_modules/stylus/lib/stack/index.js @@ -0,0 +1,146 @@ + +/*! + * Stylus - Stack + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Frame = require('./frame'); + +/** + * Initialize a new `Stack`. + * + * @api private + */ + +var Stack = module.exports = function Stack() { + Array.apply(this, arguments); +}; + +/** + * Inherit from `Array.prototype`. + */ + +Stack.prototype.__proto__ = Array.prototype; + +/** + * Push the given `frame`. + * + * @param {Frame} frame + * @api public + */ + +Stack.prototype.push = function(frame){ + frame.stack = this; + frame.parent = this.currentFrame; + return [].push.apply(this, arguments); +}; + +/** + * Return the current stack `Frame`. + * + * @return {Frame} + * @api private + */ + +Stack.prototype.__defineGetter__('currentFrame', function(){ + return this[this.length - 1]; +}); + +/** + * Lookup stack frame for the given `block`. + * + * @param {Block} block + * @return {Frame} + * @api private + */ + +Stack.prototype.getBlockFrame = function(block){ + for (var i = 0; i < this.length; ++i) { + if (block == this[i].block) { + return this[i]; + } + } +}; + +/** + * Lookup the given local variable `name`, relative + * to the lexical scope of the current frame's `Block`. + * + * When the result of a lookup is an identifier + * a recursive lookup is performed, defaulting to + * returning the identifier itself. + * + * @param {String} name + * @return {Node} + * @api private + */ + +Stack.prototype.lookup = function(name){ + var block = this.currentFrame.block + , val + , ret; + + do { + var frame = this.getBlockFrame(block); + if (frame && (val = frame.lookup(name))) { + switch (val.first.nodeName) { + case 'ident': + return this.lookup(val.first.name) || val; + default: + return val; + } + } + } while (block = block.parent); +}; + +/** + * Custom inspect. + * + * @return {String} + * @api private + */ + +Stack.prototype.inspect = function(){ + return this.reverse().map(function(frame){ + return frame.inspect(); + }).join('\n'); +}; + +/** + * Return stack string formatted as: + * + * at (:) + * + * @return {String} + * @api private + */ + +Stack.prototype.toString = function(){ + var block + , node + , buf = [] + , location + , len = this.length; + + while (len--) { + block = this[len].block; + if (node = block.node) { + location = '(' + node.filename + ':' + (node.lineno + 1) + ')'; + switch (node.nodeName) { + case 'function': + buf.push(' at ' + node.name + '() ' + location); + break; + case 'group': + buf.push(' at "' + node.nodes[0].val + '" ' + location); + break; + } + } + } + + return buf.join('\n'); +}; \ No newline at end of file diff --git a/node_modules/stylus/lib/stack/scope.js b/node_modules/stylus/lib/stack/scope.js new file mode 100644 index 0000000..e2dc4da --- /dev/null +++ b/node_modules/stylus/lib/stack/scope.js @@ -0,0 +1,53 @@ + +/*! + * Stylus - stack - Scope + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Initialize a new `Scope`. + * + * @api private + */ + +var Scope = module.exports = function Scope() { + this.locals = {}; +}; + +/** + * Add `ident` node to the current scope. + * + * @param {Ident} ident + * @api private + */ + +Scope.prototype.add = function(ident){ + this.locals[ident.name] = ident.val; +}; + +/** + * Lookup the given local variable `name`. + * + * @param {String} name + * @return {Node} + * @api private + */ + +Scope.prototype.lookup = function(name){ + return this.locals[name]; +}; + +/** + * Custom inspect. + * + * @return {String} + * @api public + */ + +Scope.prototype.inspect = function(){ + var keys = Object.keys(this.locals).map(function(key){ return '@' + key; }); + return '[Scope' + + (keys.length ? ' ' + keys.join(', ') : '') + + ']'; +}; diff --git a/node_modules/stylus/lib/stylus.js b/node_modules/stylus/lib/stylus.js new file mode 100644 index 0000000..b448fb8 --- /dev/null +++ b/node_modules/stylus/lib/stylus.js @@ -0,0 +1,103 @@ +/*! + * Stylus + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Renderer = require('./renderer') + , Parser = require('./parser') + , nodes = require('./nodes') + , utils = require('./utils'); + +/** + * Export render as the module. + */ + +exports = module.exports = render; + +/** + * Library version. + */ + +exports.version = require('../package').version; + +/** + * Expose nodes. + */ + +exports.nodes = nodes; + +/** + * Expose BIFs. + */ + +exports.functions = require('./functions'); + +/** + * Expose utils. + */ + +exports.utils = require('./utils'); + +/** + * Expose middleware. + */ + +exports.middleware = require('./middleware'); + +/** + * Expose constructors. + */ + +exports.Visitor = require('./visitor'); +exports.Parser = require('./parser'); +exports.Evaluator = require('./visitor/evaluator'); +exports.Compiler = require('./visitor/compiler'); + +/** + * Convert the given `css` to `stylus` source. + * + * @param {String} css + * @return {String} + * @api public + */ + +exports.convertCSS = require('./convert/css'); + +/** + * Render the given `str` with `options` and callback `fn(err, css)`. + * + * @param {String} str + * @param {Object|Function} options + * @param {Function} fn + * @api public + */ + +exports.render = function(str, options, fn){ + if ('function' == typeof options) fn = options, options = {}; + return new Renderer(str, options).render(fn); +}; + +/** + * Return a new `Renderer` for the given `str` and `options`. + * + * @param {String} str + * @param {Object} options + * @return {Renderer} + * @api public + */ + +function render(str, options) { + return new Renderer(str, options); +} + +/** + * Expose optional functions. + */ + +exports.url = require('./functions/url'); +exports.resolver = require('./functions/resolver'); diff --git a/node_modules/stylus/lib/token.js b/node_modules/stylus/lib/token.js new file mode 100644 index 0000000..8e95e60 --- /dev/null +++ b/node_modules/stylus/lib/token.js @@ -0,0 +1,53 @@ + +/*! + * Stylus - Token + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var inspect = require('util').inspect; + +/** + * Initialize a new `Token` with the given `type` and `val`. + * + * @param {String} type + * @param {Mixed} val + * @api private + */ + +var Token = exports = module.exports = function Token(type, val) { + this.type = type; + this.val = val; +}; + +/** + * Custom inspect. + * + * @return {String} + * @api public + */ + +Token.prototype.inspect = function(){ + var val = ' ' + inspect(this.val); + return '[Token:' + this.lineno + ' ' + + '\x1b[32m' + this.type + '\x1b[0m' + + '\x1b[33m' + (this.val ? val : '') + '\x1b[0m' + + ']'; +}; + +/** + * Return type or val. + * + * @return {String} + * @api public + */ + +Token.prototype.toString = function(){ + return (undefined === this.val + ? this.type + : this.val).toString(); +}; diff --git a/node_modules/stylus/lib/units.js b/node_modules/stylus/lib/units.js new file mode 100644 index 0000000..8470104 --- /dev/null +++ b/node_modules/stylus/lib/units.js @@ -0,0 +1,20 @@ + +/*! + * Stylus - units + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +// units found in http://www.w3.org/TR/css3-values + +module.exports = [ + 'em', 'ex', 'ch', 'rem' // relative lengths + , 'vw', 'vh', 'vmin' // relative viewport-percentage lengths + , 'cm', 'mm', 'in', 'pt', 'pc', 'px' // absolute lengths + , 'deg', 'grad', 'rad', 'turn' // angles + , 's', 'ms' // times + , 'Hz', 'kHz' // frequencies + , 'dpi', 'dpcm', 'dppx', 'x' // resolutions + , '%' // percentage type + , 'fr' // grid-layout (http://www.w3.org/TR/css3-grid-layout/) +]; diff --git a/node_modules/stylus/lib/utils.js b/node_modules/stylus/lib/utils.js new file mode 100644 index 0000000..ce8946c --- /dev/null +++ b/node_modules/stylus/lib/utils.js @@ -0,0 +1,307 @@ + +/*! + * Stylus - utils + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var nodes = require('./nodes') + , join = require('path').join + , resolve = require('path').resolve + , fs = require('fs'); + +/** + * Check if `path` looks absolute. + * + * @param {String} path + * @return {Boolean} + * @api private + */ + +exports.absolute = function(path){ + // On Windows the path could start with a drive letter, i.e. a:\\ or two leading backslashes + return path.substr(0, 2) == '\\\\' || path[0] == '/' || /^[a-z]:\\/i.test(path); +}; + +/** + * Attempt to lookup `path` within `paths` from tail to head. + * Optionally a path to `ignore` may be passed. + * + * @param {String} path + * @param {String} paths + * @param {String} ignore + * @param {Boolean} resolveURL + * @return {String} + * @api private + */ + +exports.lookup = function(path, paths, ignore, resolveURL){ + var lookup + , method = resolveURL ? resolve : join + , i = paths.length; + + // Absolute + if (exports.absolute(path)) { + try { + fs.statSync(path); + return path; + } catch (err) { + // Ignore, continue on + // to trying relative lookup. + // Needed for url(/images/foo.png) + // for example + } + } + + // Relative + while (i--) { + try { + lookup = method(paths[i], path); + if (ignore == lookup) continue; + fs.statSync(lookup); + return lookup; + } catch (err) { + // Ignore + } + } +}; + +/** + * Format the given `err` with the given `options`. + * + * Options: + * + * - `filename` context filename + * - `context` context line count [8] + * - `lineno` context line number + * - `input` input string + * + * @param {Error} err + * @param {Object} options + * @return {Error} + * @api private + */ + +exports.formatException = function(err, options){ + var lineno = options.lineno + , filename = options.filename + , str = options.input + , context = options.context || 8 + , context = context / 2 + , lines = ('\n' + str).split('\n') + , start = Math.max(lineno - context, 1) + , end = Math.min(lines.length, lineno + context) + , pad = end.toString().length; + + var context = lines.slice(start, end).map(function(line, i){ + var curr = i + start; + return (curr == lineno ? ' > ' : ' ') + + Array(pad - curr.toString().length + 1).join(' ') + + curr + + '| ' + + line; + }).join('\n'); + + err.message = filename + + ':' + lineno + + '\n' + context + + '\n\n' + err.message + '\n' + + (err.stylusStack ? err.stylusStack + '\n' : ''); + + return err; +}; + +/** + * Assert that `node` is of the given `type`, or throw. + * + * @param {Node} node + * @param {Function} type + * @param {String} param + * @api public + */ + +exports.assertType = function(node, type, param){ + exports.assertPresent(node, param); + if (node.nodeName == type) return; + var actual = node.nodeName + , msg = 'expected "' + + param + '" to be a ' + + type + ', but got ' + + actual + ':' + node; + throw new Error('TypeError: ' + msg); +}; + +/** + * Assert that `node` is a `String` or `Ident`. + * + * @param {Node} node + * @param {String} param + * @api public + */ + +exports.assertString = function(node, param){ + exports.assertPresent(node, param); + switch (node.nodeName) { + case 'string': + case 'ident': + case 'literal': + return; + default: + var actual = node.nodeName + , msg = 'expected string, ident or literal, but got ' + actual + ':' + node; + throw new Error('TypeError: ' + msg); + } +}; + +/** + * Assert that `node` is a `RGBA` or `HSLA`. + * + * @param {Node} node + * @param {String} param + * @api public + */ + +exports.assertColor = function(node, param){ + exports.assertPresent(node, param); + switch (node.nodeName) { + case 'rgba': + case 'hsla': + return; + default: + var actual = node.nodeName + , msg = 'expected rgba or hsla, but got ' + actual + ':' + node; + throw new Error('TypeError: ' + msg); + } +}; + +/** + * Assert that param `name` is given, aka the `node` is passed. + * + * @param {Node} node + * @param {String} name + * @api public + */ + +exports.assertPresent = function(node, name){ + if (node) return; + if (name) throw new Error('"' + name + '" argument required'); + throw new Error('argument missing'); +}; + +/** + * Unwrap `expr`. + * + * Takes an expressions with length of 1 + * such as `((1 2 3))` and unwraps it to `(1 2 3)`. + * + * @param {Expression} expr + * @return {Node} + * @api public + */ + +exports.unwrap = function(expr){ + // explicitly preserve the expression + if (expr.preserve) return expr; + if ('arguments' != expr.nodeName && 'expression' != expr.nodeName) return expr; + if (1 != expr.nodes.length) return expr; + if ('arguments' != expr.nodes[0].nodeName && 'expression' != expr.nodes[0].nodeName) return expr; + return exports.unwrap(expr.nodes[0]); +}; + +/** + * Coerce JavaScript values to their Stylus equivalents. + * + * @param {Mixed} val + * @return {Node} + * @api public + */ + +exports.coerce = function(val){ + switch (typeof val) { + case 'function': + return val; + case 'string': + return new nodes.String(val); + case 'boolean': + return new nodes.Boolean(val); + case 'number': + return new nodes.Unit(val); + default: + if (null == val) return nodes.null; + if (Array.isArray(val)) return exports.coerceArray(val); + if (val.nodeName) return val; + return exports.coerceObject(val); + } +}; + +/** + * Coerce a javascript `Array` to a Stylus `Expression`. + * + * @param {Array} val + * @return {Expression} + * @api private + */ + +exports.coerceArray = function(val){ + var expr = new nodes.Expression; + val.forEach(function(val){ + expr.push(exports.coerce(val)); + }); + return expr; +}; + +/** + * Coerce a javascript object to a Stylus `Expression`. + * + * For example `{ foo: 'bar', bar: 'baz' }` would become + * the expression `(foo 'bar') (bar 'baz')`. + * + * @param {Object} obj + * @return {Expression} + * @api public + */ + +exports.coerceObject = function(obj){ + var expr = new nodes.Expression + , val; + + for (var key in obj) { + val = exports.coerce(obj[key]); + key = new nodes.Ident(key); + expr.push(exports.coerceArray([key, val])); + } + + return expr; +}; + +/** + * Return param names for `fn`. + * + * @param {Function} fn + * @return {Array} + * @api private + */ + +exports.params = function(fn){ + return fn + .toString() + .match(/\(([^)]*)\)/)[1].split(/ *, */); +}; + +/** + * Merge object `b` with `a`. + * + * @param {Object} a + * @param {Object} b + * @return {Object} a + * @api private + */ + +exports.merge = function(a, b){ + for (var k in b) a[k] = b[k]; + return a; +} diff --git a/node_modules/stylus/lib/visitor/compiler.js b/node_modules/stylus/lib/visitor/compiler.js new file mode 100644 index 0000000..0532feb --- /dev/null +++ b/node_modules/stylus/lib/visitor/compiler.js @@ -0,0 +1,528 @@ +/*! + * Stylus - Compiler + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Visitor = require('./') + , nodes = require('../nodes') + , utils = require('../utils') + , fs = require('fs'); + +/** + * Initialize a new `Compiler` with the given `root` Node + * and the following `options`. + * + * Options: + * + * - `compress` Compress the CSS output (default: false) + * + * @param {Node} root + * @api public + */ + +var Compiler = module.exports = function Compiler(root, options) { + options = options || {}; + this.compress = options.compress; + this.firebug = options.firebug; + this.linenos = options.linenos; + this.spaces = options['indent spaces'] || 2; + this.includeCSS = options['include css']; + this.indents = 1; + Visitor.call(this, root); + this.stack = []; + this.js = ''; +}; + +/** + * Inherit from `Visitor.prototype`. + */ + +Compiler.prototype.__proto__ = Visitor.prototype; + +/** + * Compile to css, and return a string of CSS. + * + * @return {String} + * @api private + */ + +Compiler.prototype.compile = function(){ + return this.visit(this.root); +}; + +/** + * Return indentation string. + * + * @return {String} + * @api private + */ + +Compiler.prototype.__defineGetter__('indent', function(){ + if (this.compress) return ''; + return new Array(this.indents).join(Array(this.spaces + 1).join(' ')); +}); + +/** + * Visit Root. + */ + +Compiler.prototype.visitRoot = function(block){ + this.buf = ''; + for (var i = 0, len = block.nodes.length; i < len; ++i) { + var node = block.nodes[i]; + if (this.linenos || this.firebug) this.debugInfo(node); + var ret = this.visit(node); + if (ret) this.buf += ret + '\n'; + } + return this.buf; +}; + +/** + * Visit Block. + */ + +Compiler.prototype.visitBlock = function(block){ + var node; + + if (block.hasProperties && !block.lacksRenderedSelectors) { + var arr = [this.compress ? '{' : ' {']; + ++this.indents; + for (var i = 0, len = block.nodes.length; i < len; ++i) { + this.last = len - 1 == i; + node = block.nodes[i]; + switch (node.nodeName) { + case 'null': + case 'expression': + case 'function': + case 'jsliteral': + case 'group': + case 'unit': + continue; + case 'media': + // Prevent double-writing the @media declaration when + // nested inside of a function/mixin + if (node.block.parent.scope) { + continue; + } + default: + arr.push(this.visit(node)); + } + } + --this.indents; + arr.push(this.indent + '}'); + this.buf += arr.join(this.compress ? '' : '\n'); + this.buf += '\n'; + } + + // Nesting + for (var i = 0, len = block.nodes.length; i < len; ++i) { + node = block.nodes[i]; + switch (node.nodeName) { + case 'group': + case 'print': + case 'page': + case 'block': + case 'keyframes': + if (this.linenos || this.firebug) this.debugInfo(node); + this.visit(node); + break; + case 'media': + case 'mozdocument': + case 'import': + case 'fontface': + this.visit(node); + break; + case 'comment': + // only show comments inside when outside of scope and unsuppressed + if (!block.scope && !node.suppress) { + this.buf += this.visit(node) + '\n'; + } + break; + case 'literal': + this.buf += this.visit(node) + '\n'; + break; + } + } +}; + +/** + * Visit Keyframes. + */ + +Compiler.prototype.visitKeyframes = function(node){ + var comma = this.compress ? ',' : ', '; + + var prefix = 'official' == node.prefix + ? '' + : '-' + node.prefix + '-'; + + this.buf += '@' + prefix + 'keyframes ' + + this.visit(node.name) + + (this.compress ? '{' : ' {'); + + ++this.indents; + node.frames.forEach(function(frame){ + if (!this.compress) this.buf += '\n '; + this.buf += this.visit(frame.pos.join(comma)); + this.visit(frame.block); + }, this); + --this.indents; + + this.buf += '}' + (this.compress ? '' : '\n'); +}; + +/** + * Visit Media. + */ + +Compiler.prototype.visitMedia = function(media){ + this.buf += '@media ' + media.val; + this.buf += this.compress ? '{' : ' {\n'; + ++this.indents; + this.visit(media.block); + --this.indents; + this.buf += '}' + (this.compress ? '' : '\n'); +}; + +/** + * Visit MozDocument. + */ + +Compiler.prototype.visitMozDocument = function(mozdocument){ + this.buf += '@-moz-document ' + mozdocument.val; + this.buf += this.compress ? '{' : ' {\n'; + ++this.indents; + this.visit(mozdocument.block); + --this.indents; + this.buf += '}' + (this.compress ? '' : '\n'); +}; + +/** + * Visit Page. + */ + +Compiler.prototype.visitPage = function(page){ + this.buf += this.indent + '@page'; + this.buf += page.selector ? ' ' + page.selector : ''; + this.visit(page.block); +}; + +/** + * Visit Import. + */ + +Compiler.prototype.visitImport = function(imported){ + this.buf += '@import ' + this.visit(imported.path) + ';\n'; +}; + +/** + * Visit FontFace. + */ + +Compiler.prototype.visitFontFace = function(face){ + this.buf += this.indent + '@font-face'; + this.visit(face.block); +}; + +/** + * Visit JSLiteral. + */ + +Compiler.prototype.visitJSLiteral = function(js){ + this.js += '\n' + js.val.replace(/@selector/g, '"' + this.selector + '"'); + return ''; +}; + +/** + * Visit Comment. + */ + +Compiler.prototype.visitComment = function(comment){ + return this.compress + ? comment.suppress + ? '' + : comment.str + : comment.str; +}; + +/** + * Visit Function. + */ + +Compiler.prototype.visitFunction = function(fn){ + return fn.name; +}; + +/** + * Visit Variable. + */ + +Compiler.prototype.visitVariable = function(variable){ + return ''; +}; + +/** + * Visit Charset. + */ + +Compiler.prototype.visitCharset = function(charset){ + return '@charset ' + this.visit(charset.val) + ';'; +}; + +/** + * Visit Literal. + */ + +Compiler.prototype.visitLiteral = function(lit){ + var val = lit.val.trim(); + if (!this.includeCSS) val = val.replace(/^ /gm, ''); + return val; +}; + +/** + * Visit Boolean. + */ + +Compiler.prototype.visitBoolean = function(bool){ + return bool.toString(); +}; + +/** + * Visit RGBA. + */ + +Compiler.prototype.visitRGBA = function(rgba){ + return rgba.toString(); +}; + +/** + * Visit HSLA. + */ + +Compiler.prototype.visitHSLA = function(hsla){ + return hsla.rgba.toString(); +}; + +/** + * Visit Unit. + */ + +Compiler.prototype.visitUnit = function(unit){ + var type = unit.type || '' + , n = unit.val + , float = n != (n | 0); + + // Compress + if (this.compress) { + // Zero is always '0', unless when + // a percentage, this is required by keyframes + if ('%' != type && 0 == n) return '0'; + // Omit leading '0' on floats + if (float && n < 1 && n > -1) { + return n.toString().replace('0.', '.') + type; + } + } + + return n.toString() + type; +}; + +/** + * Visit Group. + */ + +Compiler.prototype.visitGroup = function(group){ + var stack = this.stack; + + stack.push(group.nodes); + + // selectors + if (group.block.hasProperties) { + var selectors = this.compileSelectors(stack); + if(selectors.length) + this.buf += (this.selector = selectors.join(this.compress ? ',' : ',\n')); + else + group.block.lacksRenderedSelectors = true; + } + + // output block + this.visit(group.block); + stack.pop(); +}; + +/** + * Visit Ident. + */ + +Compiler.prototype.visitIdent = function(ident){ + return ident.name; +}; + +/** + * Visit String. + */ + +Compiler.prototype.visitString = function(string){ + return this.isURL + ? string.val + : string.toString(); +}; + +/** + * Visit Null. + */ + +Compiler.prototype.visitNull = function(node){ + return ''; +}; + +/** + * Visit Call. + */ + +Compiler.prototype.visitCall = function(call){ + this.isURL = 'url' == call.name; + var args = call.args.nodes.map(function(arg){ + return this.visit(arg); + }, this).join(this.compress ? ',' : ', '); + if (this.isURL) args = '"' + args + '"'; + this.isURL = false; + return call.name + '(' + args + ')'; +}; + +/** + * Visit Expression. + */ + +Compiler.prototype.visitExpression = function(expr){ + var buf = [] + , self = this + , len = expr.nodes.length + , nodes = expr.nodes.map(function(node){ return self.visit(node); }); + + nodes.forEach(function(node, i){ + var last = i == len - 1; + buf.push(node); + if ('/' == nodes[i + 1] || '/' == node) return; + if (last) return; + buf.push(expr.isList + ? (self.compress ? ',' : ', ') + : (self.isURL ? '' : ' ')); + }); + + return buf.join(''); +}; + +/** + * Visit Arguments. + */ + +Compiler.prototype.visitArguments = Compiler.prototype.visitExpression; + +/** + * Visit Property. + */ + +Compiler.prototype.visitProperty = function(prop){ + var self = this + , val = this.visit(prop.expr).trim(); + return this.indent + (prop.name || prop.segments.join('')) + + (this.compress ? ':' + val : ': ' + val) + + (this.compress + ? (this.last ? '' : ';') + : ';'); +}; + +/** + * Compile selector strings in `arr` from the bottom-up + * to produce the selector combinations. For example + * the following Stylus: + * + * ul + * li + * p + * a + * color: red + * + * Would return: + * + * [ 'ul li a', 'ul p a' ] + * + * @param {Array} arr + * @return {Array} + * @api private + */ + +Compiler.prototype.compileSelectors = function(arr){ + var stack = this.stack + , self = this + , selectors = [] + , buf = [] + , hiddenSelectorRegexp = /^\s*\$/; + + function interpolateParent(selector, buf) { + var str = selector.val.trim(); + if (buf.length) { + for (var i = 0, len = buf.length; i < len; ++i) { + if (~buf[i].indexOf('&')) { + str = buf[i].replace(/&/g, str).trim(); + } else { + str += ' ' + buf[i].trim(); + } + } + } + return str; + } + + function compile(arr, i) { + if (i) { + arr[i].forEach(function(selector){ + if(selector.val.match(hiddenSelectorRegexp)) return; + if (selector.inherits) { + buf.unshift(selector.val); + compile(arr, i - 1); + buf.shift(); + } else { + selectors.push(interpolateParent(selector, buf)); + } + }); + } else { + arr[0].forEach(function(selector){ + if(selector.val.match(hiddenSelectorRegexp)) return; + var str = interpolateParent(selector, buf); + selectors.push(self.indent + str.trimRight()); + }); + } + } + + compile(arr, arr.length - 1); + + return selectors; +}; + +/** + * Debug info. + */ + +Compiler.prototype.debugInfo = function(node){ + + var path = node.filename == 'stdin' ? 'stdin' : fs.realpathSync(node.filename) + , line = node.nodes ? node.nodes[0].lineno : node.lineno; + + if (this.linenos){ + this.buf += '\n/* ' + 'line ' + line + ' : ' + path + ' */\n'; + } + + if (this.firebug){ + // debug info for firebug, the crazy formatting is needed + path = 'file\\\:\\\/\\\/' + path.replace(/(\/|\.)/g, '\\$1'); + line = '\\00003' + line; + this.buf += '\n@media -stylus-debug-info' + + '{filename{font-family:' + path + + '}line{font-family:' + line + '}}\n'; + } +} diff --git a/node_modules/stylus/lib/visitor/evaluator.js b/node_modules/stylus/lib/visitor/evaluator.js new file mode 100644 index 0000000..723b037 --- /dev/null +++ b/node_modules/stylus/lib/visitor/evaluator.js @@ -0,0 +1,1321 @@ + +/*! + * Stylus - Evaluator + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Visitor = require('./') + , units = require('../units') + , nodes = require('../nodes') + , Stack = require('../stack') + , Frame = require('../stack/frame') + , Scope = require('../stack/scope') + , utils = require('../utils') + , bifs = require('../functions') + , dirname = require('path').dirname + , join = require('path').join + , colors = require('../colors') + , debug = require('debug')('stylus:evaluator') + , fs = require('fs'); + +/** + * Clone the block node within the each loop so we don't keep + * extending the same block in multiple contexts + * + * @param {Node} + * @return {Node} + */ +function cloneNode (node) { + if (node.block && node.block.node) { + node.block.node = node.block.node.clone(); + } + if (node.nodes && node.nodes.length) { + node.nodes.map(cloneNode); + } + return node; +} + +/** + * Initialize a new `Evaluator` with the given `root` Node + * and the following `options`. + * + * Options: + * + * - `compress` Compress the css output, defaults to false + * - `warn` Warn the user of duplicate function definitions etc + * + * @param {Node} root + * @api private + */ + +var Evaluator = module.exports = function Evaluator(root, options) { + options = options || {}; + Visitor.call(this, root); + this.stack = new Stack; + this.imports = options.imports || []; + this.functions = options.functions || {}; + this.globals = options.globals || {}; + this.paths = options.paths || []; + this.filename = options.filename; + this.includeCSS = options['include css']; + this.resolveURL = options['resolve url']; + this.paths.push(dirname(options.filename || '.')); + this.stack.push(this.global = new Frame(root)); + this.warnings = options.warn; + this.options = options; + this.calling = []; // TODO: remove, use stack + this.importStack = []; + this.return = 0; +}; + +/** + * Inherit from `Visitor.prototype`. + */ + +Evaluator.prototype.__proto__ = Visitor.prototype; + +/** + * Proxy visit to expose node line numbers. + * + * @param {Node} node + * @return {Node} + * @api private + */ + +var visit = Visitor.prototype.visit; +Evaluator.prototype.visit = function(node){ + try { + return visit.call(this, node); + } catch (err) { + if (err.filename) throw err; + err.lineno = node.lineno; + err.filename = node.filename; + err.stylusStack = this.stack.toString(); + try { + err.input = fs.readFileSync(err.filename, 'utf8'); + } catch (err) { + // ignore + } + throw err; + } +}; + +/** + * Perform evaluation setup: + * + * - populate global scope + * - iterate imports + * + * @api private + */ + +Evaluator.prototype.setup = function(){ + var root = this.root; + var imports = []; + + this.populateGlobalScope(); + this.imports.forEach(function(file){ + var expr = new nodes.Expression; + expr.push(new nodes.String(file)); + imports.push(new nodes.Import(expr)); + }, this); + + root.nodes = imports.concat(root.nodes); +}; + +/** + * Populate the global scope with: + * + * - css colors + * - user-defined globals + * + * @api private + */ + +Evaluator.prototype.populateGlobalScope = function(){ + var scope = this.global.scope; + + // colors + Object.keys(colors).forEach(function(name){ + var rgb = colors[name] + , rgba = new nodes.RGBA(rgb[0], rgb[1], rgb[2], 1) + , node = new nodes.Ident(name, rgba); + scope.add(node); + }); + + // user-defined globals + var globals = this.globals; + Object.keys(globals).forEach(function(name){ + scope.add(new nodes.Ident(name, globals[name])); + }); +}; + +/** + * Evaluate the tree. + * + * @return {Node} + * @api private + */ + +Evaluator.prototype.evaluate = function(){ + debug('eval %s', this.filename); + this.setup(); + return this.visit(this.root); +}; + +/** + * Visit Group. + */ + +Evaluator.prototype.visitGroup = function(group){ + group.nodes = group.nodes.map(function(selector){ + selector.val = this.interpolate(selector); + debug('ruleset %s', selector.val); + return selector; + }, this); + + group.block = this.visit(group.block); + return group; +}; + +/** + * Visit Charset. + */ + +Evaluator.prototype.visitCharset = function(charset){ + return charset; +}; + +/** + * Visit Return. + */ + +Evaluator.prototype.visitReturn = function(ret){ + ret.expr = this.visit(ret.expr); + throw ret; +}; + +/** + * Visit Media. + */ + +Evaluator.prototype.visitMedia = function(media){ + media.block = this.visit(media.block); + var query = this.lookup(media.val); + if (query) media.val = new nodes.Literal(query.first.string); + return media; +}; + +/** + * Visit MozDocument. + */ + +Evaluator.prototype.visitMozDocument = function(mozdocument){ + mozdocument.block = this.visit(mozdocument.block); + return mozdocument; +}; + +/** + * Visit FontFace. + */ + +Evaluator.prototype.visitFontFace = function(face){ + face.block = this.visit(face.block); + return face; +}; + +/** + * Visit FontFace. + */ + +Evaluator.prototype.visitPage = function(page){ + page.block = this.visit(page.block); + return page; +}; + +/** + * Visit Object. + */ + +Evaluator.prototype.visitObject = function(obj){ + for (var key in obj.vals) { + obj.vals[key] = this.visit(obj.vals[key]); + } + return obj; +}; + +/** + * Visit Member. + */ + +Evaluator.prototype.visitMember = function(node){ + var left = node.left + , right = node.right + , obj = this.visit(left).first; + + if ('object' != obj.nodeName) { + throw new Error(left.toString() + ' has no property .' + right); + } + return obj.get(right.name); +}; + +/** + * Visit Keyframes. + */ + +Evaluator.prototype.visitKeyframes = function(keyframes){ + if (keyframes.fabricated) return keyframes; + keyframes.name = this.visit(keyframes.name).first.name; + + keyframes.frames = keyframes.frames.map(function(frame){ + frame.block = this.visit(frame.block); + return frame; + }, this); + + if ('official' != keyframes.prefix) return keyframes; + + this.vendors.forEach(function(prefix){ + var node = keyframes.clone(); + node.prefix = prefix; + node.fabricated = true; + this.currentBlock.push(node); + }, this); + + return nodes.null; +}; + +/** + * Visit Function. + */ + +Evaluator.prototype.visitFunction = function(fn){ + // check local + var local = this.stack.currentFrame.scope.lookup(fn.name); + if (local) this.warn('local ' + local.nodeName + ' "' + fn.name + '" previously defined in this scope'); + + // user-defined + var user = this.functions[fn.name]; + if (user) this.warn('user-defined function "' + fn.name + '" is already defined'); + + // BIF + var bif = bifs[fn.name]; + if (bif) this.warn('built-in function "' + fn.name + '" is already defined'); + + return fn; +}; + +/** + * Visit Each. + */ + +Evaluator.prototype.visitEach = function(each){ + this.return++; + var expr = utils.unwrap(this.visit(utils.unwrap(each.expr))) + , len = expr.nodes.length + , val = new nodes.Ident(each.val) + , key = new nodes.Ident(each.key || '__index__') + , scope = this.currentScope + , block = this.currentBlock + , vals = [] + , self = this + , body + , obj; + this.return--; + + each.block.scope = false; + + function visitBody(body) { + body = each.block.clone(); + body.nodes.map(cloneNode); + body = self.visit(body); + vals = vals.concat(body.nodes); + } + + // for prop in obj + if (1 == len && 'object' == expr.nodes[0].nodeName) { + obj = expr.nodes[0]; + for (var prop in obj.vals) { + val.val = new nodes.String(prop); + key.val = obj.get(prop); + scope.add(val); + scope.add(key); + visitBody(body); + } + } else { + for (var i = 0; i < len; ++i) { + val.val = expr.nodes[i]; + key.val = new nodes.Unit(i); + scope.add(val); + scope.add(key); + visitBody(body); + } + } + + this.mixin(vals, block); + return vals[vals.length - 1] || nodes.null; +}; + +/** + * Visit Call. + */ + +Evaluator.prototype.visitCall = function(call){ + debug('call %s', call); + var fn = this.lookup(call.name) + , literal + , ret; + + // url() + this.ignoreColors = 'url' == call.name; + + // Variable function + if (fn && 'expression' == fn.nodeName) { + fn = fn.nodes[0]; + } + + // Not a function? try user-defined or built-ins + if (fn && 'function' != fn.nodeName) { + fn = this.lookupFunction(call.name); + } + + // Undefined function? render literal CSS + if (!fn || fn.nodeName != 'function') { + debug('%s is undefined', call); + // Special case for `calc` + if ('calc' == this.unvendorize(call.name)) { + literal = call.args.nodes && call.args.nodes[0]; + if (literal) ret = new nodes.Literal(call.name + literal); + } else { + ret = this.literalCall(call); + } + this.ignoreColors = false; + return ret; + } + + this.calling.push(call.name); + + // Massive stack + if (this.calling.length > 200) { + throw new RangeError('Maximum stylus call stack size exceeded'); + } + + // First node in expression + if ('expression' == fn.nodeName) fn = fn.first; + + // Evaluate arguments + this.return++; + var args = this.visit(call.args) + , mapCopy = {}; + + for (var key in args.map) { + mapCopy[key] = args.map[key]; + args.map[key] = this.visit(mapCopy[key].clone()); + } + this.return--; + + // Built-in + if (fn.fn) { + debug('%s is built-in', call); + ret = this.invokeBuiltin(fn.fn, args); + // User-defined + } else if ('function' == fn.nodeName) { + debug('%s is user-defined', call); + ret = this.invokeFunction(fn, args); + } + + // restore kwargs + for (key in mapCopy) { + args.map[key] = mapCopy[key]; + } + + this.calling.pop(); + this.ignoreColors = false; + return ret; +}; + +/** + * Visit Ident. + */ + +Evaluator.prototype.visitIdent = function(ident){ + var prop; + // Property lookup + if (ident.property) { + if (prop = this.lookupProperty(ident.name)) { + return this.visit(prop.expr.clone()); + } + return nodes.null; + // Lookup + } else if (ident.val.isNull) { + var val = this.lookup(ident.name); + return val ? this.visit(val) : ident; + // Assign + } else { + this.return++; + ident.val = this.visit(ident.val); + this.return--; + this.currentScope.add(ident); + return ident.val; + } +}; + +/** + * Visit BinOp. + */ + +Evaluator.prototype.visitBinOp = function(binop){ + // Special-case "is defined" pseudo binop + if ('is defined' == binop.op) return this.isDefined(binop.left); + + this.return++; + // Visit operands + var op = binop.op + , left = this.visit(binop.left) + , right = this.visit(binop.right); + + // HACK: ternary + var val = binop.val + ? this.visit(binop.val) + : null; + this.return--; + + // Operate + try { + return this.visit(left.operate(op, right, val)); + } catch (err) { + // disregard coercion issues in equality + // checks, and simply return false + if ('CoercionError' == err.name) { + switch (op) { + case '==': + return nodes.false; + case '!=': + return nodes.true; + } + } + throw err; + } +}; + +/** + * Visit UnaryOp. + */ + +Evaluator.prototype.visitUnaryOp = function(unary){ + var op = unary.op + , node = this.visit(unary.expr); + + if ('!' != op) { + node = node.first.clone(); + utils.assertType(node, 'unit'); + } + + switch (op) { + case '-': + node.val = -node.val; + break; + case '+': + node.val = +node.val; + break; + case '~': + node.val = ~node.val; + break; + case '!': + return node.toBoolean().negate(); + } + + return node; +}; + +/** + * Visit TernaryOp. + */ + +Evaluator.prototype.visitTernary = function(ternary){ + var ok = this.visit(ternary.cond).toBoolean(); + return ok.isTrue + ? this.visit(ternary.trueExpr) + : this.visit(ternary.falseExpr); +}; + +/** + * Visit Expression. + */ + +Evaluator.prototype.visitExpression = function(expr){ + for (var i = 0, len = expr.nodes.length; i < len; ++i) { + expr.nodes[i] = this.visit(expr.nodes[i]); + } + + // support (n * 5)px etc + if (this.castable(expr)) expr = this.cast(expr); + + return expr; +}; + +/** + * Visit Arguments. + */ + +Evaluator.prototype.visitArguments = Evaluator.prototype.visitExpression; + +/** + * Visit Property. + */ + +Evaluator.prototype.visitProperty = function(prop){ + var name = this.interpolate(prop) + , fn = this.lookup(name) + , call = fn && 'function' == fn.nodeName + , literal = ~this.calling.indexOf(name); + + // Function of the same name + if (call && !literal && !prop.literal) { + var args = nodes.Arguments.fromExpression(utils.unwrap(prop.expr)); + var ret = this.visit(new nodes.Call(name, args)); + return ret; + // Regular property + } else { + this.return++; + prop.name = name; + prop.literal = true; + this.property = prop; + prop.expr = this.visit(prop.expr); + delete this.property; + this.return--; + return prop; + } +}; + +/** + * Visit Root. + */ + +Evaluator.prototype.visitRoot = function(block){ + for (var i = 0; i < block.nodes.length; ++i) { + block.index = this.rootIndex = i; + block.nodes[i] = this.visit(block.nodes[i]); + } + return block; +}; + +/** + * Visit Block. + */ + +Evaluator.prototype.visitBlock = function(block){ + this.stack.push(new Frame(block)); + for (block.index = 0; block.index < block.nodes.length; ++block.index) { + try { + block.nodes[block.index] = this.visit(block.nodes[block.index]); + } catch (err) { + if ('return' == err.nodeName) { + if (this.return) { + this.stack.pop(); + throw err; + } else { + block.nodes[block.index] = err; + break; + } + } else { + throw err; + } + } + } + this.stack.pop(); + return block; +}; + +/** + * Visit If. + */ + +Evaluator.prototype.visitIf = function(node){ + var ret + , block = this.currentBlock + , negate = node.negate; + + this.return++; + var ok = this.visit(node.cond).first.toBoolean(); + this.return--; + + // Evaluate body + if (negate) { + // unless + if (ok.isFalse) { + ret = this.visit(node.block); + } + } else { + // if + if (ok.isTrue) { + ret = this.visit(node.block); + // else + } else if (node.elses.length) { + var elses = node.elses + , len = elses.length; + for (var i = 0; i < len; ++i) { + // else if + if (elses[i].cond) { + if (this.visit(elses[i]).first.toBoolean().isTrue) { + ret = this.visit(elses[i].block); + break; + } + // else + } else { + ret = this.visit(elses[i]); + } + } + } + } + + // mixin conditional statements within a selector group + if (ret && !node.postfix && block.node && 'group' == block.node.nodeName) { + this.mixin(ret.nodes, block); + return nodes.null; + } + + return ret || nodes.null; +}; + +/** + * Visit Extend. + */ + +Evaluator.prototype.visitExtend = function(extend){ + // Cloning the selector for when we are in a loop and don't want it to affect + // the selector nodes and cause the values to be different to expected + var selector = this.interpolate(extend.selector.clone()); + var block = !this.currentBlock.node.extends && this.targetBlock.node.extends ? this.targetBlock : this.currentBlock; + if (!block.node.extends && this.extendBlock) block = this.extendBlock; + block.node.extends.push(selector); + return nodes.null; +}; + +/** + * Visit Import. + */ + +Evaluator.prototype.visitImport = function(imported){ + this.return++; + + var root = this.root + , Parser = require('../parser') + , path = this.visit(imported.path).first + , includeCSS = this.includeCSS + , importStack = this.importStack + , found + , literal + , index; + + this.return--; + debug('import %s', path); + + // url() passed + if ('url' == path.name) return imported; + + // Ensure string + if (!path.string) throw new Error('@import string expected'); + var name = path = path.string; + + // Absolute URL + if (/url\s*\(\s*['"]?(?:https?:)?\/\//i.test(path)) { + return imported; + } + + // Literal + if (~path.indexOf('.css') && !~path.indexOf('.css.')) { + literal = true; + if (!includeCSS) return imported; + } + + // support optional .styl + if (!literal && !/\.styl$/i.test(path)) path += '.styl'; + + // Lookup + found = utils.lookup(path, this.paths, this.filename); + if (!found) { + found = utils.lookup(join(name, 'index.styl'), this.paths, this.filename); + index = true; + } + + // Throw if import failed + if (!found) throw new Error('failed to locate @import file ' + path); + + // Expose imports + imported.path = found; + imported.dirname = dirname(found); + // Store the modified time + fs.stat(found, function(err, stat){ + if (err) return; + imported.mtime = stat.mtime; + }); + this.paths.push(imported.dirname); + + if (this.options._imports) this.options._imports.push(imported); + + // Parse the file + importStack.push(found); + nodes.filename = found; + + var str = fs.readFileSync(found, 'utf8'); + if (literal && !this.resolveURL) return new nodes.Literal(str.replace(/\r\n?/g, "\n")); + + // parse + var block = new nodes.Block + , parser = new Parser(str, utils.merge({ root: block }, this.options)); + + try { + block = parser.parse(); + } catch (err) { + err.filename = found; + err.lineno = parser.lexer.lineno; + err.input = str; + throw err; + } + + // Evaluate imported "root" + block.parent = root; + block.scope = false; + var ret = this.visit(block); + importStack.pop(); + if (importStack.length || index) this.paths.pop(); + + return ret; +}; + +/** + * Invoke `fn` with `args`. + * + * @param {Function} fn + * @param {Array} args + * @return {Node} + * @api private + */ + +Evaluator.prototype.invokeFunction = function(fn, args){ + var block = new nodes.Block(fn.block.parent); + fn.block.parent = block; + + // Clone the function body + // to prevent mutation of subsequent calls + var body = fn.block.clone(); + + // mixin block + var mixinBlock = this.stack.currentFrame.block; + + // new block scope + this.stack.push(new Frame(block)); + var scope = this.currentScope; + + // arguments local + scope.add(new nodes.Ident('arguments', args)); + + // mixin scope introspection + scope.add(new nodes.Ident('mixin', this.return + ? nodes.false + : new nodes.String(mixinBlock.nodeName))); + + // current property + if (this.property) { + var prop = this.propertyExpression(this.property, fn.name); + scope.add(new nodes.Ident('current-property', prop)); + } else { + scope.add(new nodes.Ident('current-property', nodes.null)); + } + + // inject arguments as locals + var i = 0 + , len = args.nodes.length; + fn.params.nodes.forEach(function(node){ + // rest param support + if (node.rest) { + node.val = new nodes.Expression; + for (; i < len; ++i) node.val.push(args.nodes[i]); + node.val.preserve = true; + // argument default support + } else { + var arg = args.map[node.name] || args.nodes[i++]; + node = node.clone(); + if (arg) { + if (!arg.isEmpty) node.val = arg; + } else { + args.push(node.val); + } + + // required argument not satisfied + if (node.val.isNull) { + throw new Error('argument "' + node + '" required for ' + fn); + } + } + + scope.add(node); + }); + + // invoke + return this.invoke(body, true, fn.filename); +}; + +/** + * Invoke built-in `fn` with `args`. + * + * @param {Function} fn + * @param {Array} args + * @return {Node} + * @api private + */ + +Evaluator.prototype.invokeBuiltin = function(fn, args){ + // Map arguments to first node + // providing a nicer js api for + // BIFs. Functions may specify that + // they wish to accept full expressions + // via .raw + if (fn.raw) { + args = args.nodes; + } else { + args = utils.params(fn).reduce(function(ret, param){ + var arg = args.map[param] || args.nodes.shift(); + if (arg) ret.push(arg.first); + return ret; + }, []); + } + + // Invoke the BIF + var body = utils.coerce(fn.apply(this, args)); + + // Always wrapping allows js functions + // to return several values with a single + // Expression node + var expr = new nodes.Expression; + expr.push(body); + body = expr; + + // Invoke + return this.invoke(body); +}; + +/** + * Invoke the given function `body`. + * + * @param {Block} body + * @return {Node} + * @api private + */ + +Evaluator.prototype.invoke = function(body, stack, filename){ + var self = this + , ret + , node; + + if (filename) this.paths.push(dirname(filename)); + + // Return + if (this.return) { + ret = this.eval(body.nodes); + if (stack) this.stack.pop(); + // Mixin + } else { + var targetFrame = this.stack[this.stack.length - 2]; + if (targetFrame) { + this.targetBlock = targetFrame.block; + node = this.targetBlock.node; + if (node && node.extends) this.extendBlock = this.targetBlock; + } + body = this.visit(body); + if (stack) this.stack.pop(); + this.mixin(body.nodes, this.currentBlock); + ret = nodes.null; + } + + if (filename) this.paths.pop(); + + return ret; +}; + +/** + * Mixin the given `nodes` to the given `block`. + * + * @param {Array} nodes + * @param {Block} block + * @api private + */ + +Evaluator.prototype.mixin = function(nodes, block){ + var len = block.nodes.length + , head = block.nodes.slice(0, block.index) + , tail = block.nodes.slice(block.index + 1, len); + this._mixin(nodes, head); + block.nodes = head.concat(tail); +}; + +/** + * Mixin the given `nodes` to the `dest` array. + * + * @param {Array} nodes + * @param {Array} dest + * @api private + */ + +Evaluator.prototype._mixin = function(nodes, dest){ + var node + , len = nodes.length; + for (var i = 0; i < len; ++i) { + switch ((node = nodes[i]).nodeName) { + case 'return': + return; + case 'block': + this._mixin(node.nodes, dest); + break; + default: + dest.push(node); + } + } +}; + +/** + * Evaluate the given `vals`. + * + * @param {Array} vals + * @return {Node} + * @api private + */ + +Evaluator.prototype.eval = function(vals){ + if (!vals) return nodes.null; + var len = vals.length + , node = nodes.null; + + try { + for (var i = 0; i < len; ++i) { + node = vals[i]; + switch (node.nodeName) { + case 'if': + if ('block' != node.block.nodeName) { + node = this.visit(node); + break; + } + case 'each': + case 'block': + node = this.visit(node); + if (node.nodes) node = this.eval(node.nodes); + break; + default: + node = this.visit(node); + } + } + } catch (err) { + if ('return' == err.nodeName) { + return err.expr; + } else { + throw err; + } + } + + return node; +}; + +/** + * Literal function `call`. + * + * @param {Call} call + * @return {call} + * @api private + */ + +Evaluator.prototype.literalCall = function(call){ + call.args = this.visit(call.args); + return call; +}; + +/** + * Lookup property `name`. + * + * @param {String} name + * @return {Property} + * @api private + */ + +Evaluator.prototype.lookupProperty = function(name){ + var i = this.stack.length + , prop = this.property + , curr = prop && prop.name + , index = this.currentBlock.index + , top = i + , nodes + , block + , len + , other; + + while (i--) { + block = this.stack[i].block; + if (!block.node) continue; + switch (block.node.nodeName) { + case 'group': + case 'function': + nodes = block.nodes; + // scan siblings from the property index up + if (i + 1 == top) { + while (index--) { + other = this.interpolate(nodes[index]); + if (name == other) return nodes[index].clone(); + } + // sequential lookup for non-siblings (for now) + } else { + len = nodes.length; + while (len--) { + if ('property' != nodes[len].nodeName) continue; + other = this.interpolate(nodes[len]); + if (name == other) return nodes[len].clone(); + } + } + break; + } + } + + return nodes.null; +}; + +/** + * Return the closest mixin-able `Block`. + * + * @return {Block} + * @api private + */ + +Evaluator.prototype.__defineGetter__('closestBlock', function(){ + var i = this.stack.length + , block; + while (i--) { + block = this.stack[i].block; + if (block.node) { + switch (block.node.nodeName) { + case 'group': + case 'function': + case 'media': + return block; + } + } + } +}); + +/** + * Lookup `name`, with support for JavaScript + * functions, and BIFs. + * + * @param {String} name + * @return {Node} + * @api private + */ + +Evaluator.prototype.lookup = function(name){ + var val; + if (this.ignoreColors && name in colors) return; + if (val = this.stack.lookup(name)) { + return utils.unwrap(val); + } else { + return this.lookupFunction(name); + } +}; + +/** + * Map segments in `node` returning a string. + * + * @param {Node} node + * @return {String} + * @api private + */ + +Evaluator.prototype.interpolate = function(node){ + var self = this; + function toString(node) { + switch (node.nodeName) { + case 'function': + case 'ident': + return node.name; + case 'literal': + case 'string': + case 'unit': + return node.val; + case 'expression': + self.return++; + var ret = toString(self.visit(node).first); + self.return--; + return ret; + } + } + + if (node.segments) { + return node.segments.map(toString).join(''); + } else { + return toString(node); + } +}; + +/** + * Lookup JavaScript user-defined or built-in function. + * + * @param {String} name + * @return {Function} + * @api private + */ + +Evaluator.prototype.lookupFunction = function(name){ + var fn = this.functions[name] || bifs[name]; + if (fn) return new nodes.Function(name, fn); +}; + +/** + * Check if the given `node` is an ident, and if it is defined. + * + * @param {Node} node + * @return {Boolean} + * @api private + */ + +Evaluator.prototype.isDefined = function(node){ + if ('ident' == node.nodeName) { + return nodes.Boolean(this.lookup(node.name)); + } else { + throw new Error('invalid "is defined" check on non-variable ' + node); + } +}; + +/** + * Return `Expression` based on the given `prop`, + * replacing cyclic calls to the given function `name` + * with "__CALL__". + * + * @param {Property} prop + * @param {String} name + * @return {Expression} + * @api private + */ + +Evaluator.prototype.propertyExpression = function(prop, name){ + var expr = new nodes.Expression + , val = prop.expr.clone(); + + // name + expr.push(new nodes.String(prop.name)); + + // replace cyclic call with __CALL__ + function replace(node) { + if ('call' == node.nodeName && name == node.name) { + return new nodes.Literal('__CALL__'); + } + + if (node.nodes) node.nodes = node.nodes.map(replace); + return node; + } + + replace(val); + expr.push(val); + return expr; +}; + +/** + * Cast `expr` to the trailing ident. + * + * @param {Expression} expr + * @return {Unit} + * @api private + */ + +Evaluator.prototype.cast = function(expr){ + return new nodes.Unit(expr.first.val, expr.nodes[1].name); +}; + +/** + * Check if `expr` is castable. + * + * @param {Expression} expr + * @return {Boolean} + * @api private + */ + +Evaluator.prototype.castable = function(expr){ + return 2 == expr.nodes.length + && 'unit' == expr.first.nodeName + && ~units.indexOf(expr.nodes[1].name); +}; + +/** + * Warn with the given `msg`. + * + * @param {String} msg + * @api private + */ + +Evaluator.prototype.warn = function(msg){ + if (!this.warnings) return; + console.warn('\033[33mWarning:\033[0m ' + msg); +}; + +/** + * Return the current `Block`. + * + * @return {Block} + * @api private + */ + +Evaluator.prototype.__defineGetter__('currentBlock', function(){ + return this.stack.currentFrame.block; +}); + +/** + * Return an array of vendor names. + * + * @return {Array} + * @api private + */ + +Evaluator.prototype.__defineGetter__('vendors', function(){ + return this.lookup('vendors').nodes.map(function(node){ + return node.string; + }); +}); + +/** + * Return the property name without vendor prefix. + * + * @param {String} prop + * @return {String} + * @api public + */ + +Evaluator.prototype.unvendorize = function(prop){ + for (var i = 0, len = this.vendors.length; i < len; i++) { + if ('official' != this.vendors[i]) { + var vendor = '-' + this.vendors[i] + '-'; + if (~prop.indexOf(vendor)) return prop.replace(vendor, ''); + } + } + return prop; +}; + +/** + * Return the current frame `Scope`. + * + * @return {Scope} + * @api private + */ + +Evaluator.prototype.__defineGetter__('currentScope', function(){ + return this.stack.currentFrame.scope; +}); + +/** + * Return the current `Frame`. + * + * @return {Frame} + * @api private + */ + +Evaluator.prototype.__defineGetter__('currentFrame', function(){ + return this.stack.currentFrame; +}); diff --git a/node_modules/stylus/lib/visitor/index.js b/node_modules/stylus/lib/visitor/index.js new file mode 100644 index 0000000..8b7c991 --- /dev/null +++ b/node_modules/stylus/lib/visitor/index.js @@ -0,0 +1,31 @@ + +/*! + * Stylus - Visitor + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Initialize a new `Visitor` with the given `root` Node. + * + * @param {Node} root + * @api private + */ + +var Visitor = module.exports = function Visitor(root) { + this.root = root; +}; + +/** + * Visit the given `node`. + * + * @param {Node|Array} node + * @api public + */ + +Visitor.prototype.visit = function(node, fn){ + var method = 'visit' + node.constructor.name; + if (this[method]) return this[method](node); + return node; +}; + diff --git a/node_modules/stylus/lib/visitor/normalizer.js b/node_modules/stylus/lib/visitor/normalizer.js new file mode 100644 index 0000000..9dc3518 --- /dev/null +++ b/node_modules/stylus/lib/visitor/normalizer.js @@ -0,0 +1,283 @@ + +/*! + * Stylus - Normalizer + * Copyright(c) 2010 LearnBoost + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var Visitor = require('./') + , nodes = require('../nodes') + , utils = require('../utils') + , fs = require('fs'); + +/** + * Initialize a new `Normalizer` with the given `root` Node. + * + * This visitor implements the first stage of the duel-stage + * compiler, tasked with stripping the "garbage" from + * the evaluated nodes, ditching null rules, resolving + * ruleset selectors etc. This step performs the logic + * necessary to facilitate the "@extend" functionality, + * as these must be resolved _before_ buffering output. + * + * @param {Node} root + * @api public + */ + +var Normalizer = module.exports = function Normalizer(root, options) { + options = options || {}; + Visitor.call(this, root); + this.stack = []; + this.extends = {}; + this.map = {}; +}; + +/** + * Inherit from `Visitor.prototype`. + */ + +Normalizer.prototype.__proto__ = Visitor.prototype; + +/** + * Normalize the node tree. + * + * @return {Node} + * @api private + */ + +Normalizer.prototype.normalize = function(){ + return this.visit(this.root); +}; + +/** + * Visit Root. + */ + +Normalizer.prototype.visitRoot = function(block){ + var ret = new nodes.Root + , node; + + for (var i = 0, len = block.nodes.length; i < len; ++i) { + node = block.nodes[i]; + switch (node.nodeName) { + case 'null': + case 'expression': + case 'function': + case 'jsliteral': + case 'unit': + continue; + default: + ret.push(this.visit(node)); + } + } + + return ret; +}; + +/** + * Visit Block. + */ + +Normalizer.prototype.visitBlock = function(block){ + var ret = new nodes.Block + , node; + + if (block.hasProperties) { + for (var i = 0, len = block.nodes.length; i < len; ++i) { + this.last = len - 1 == i; + node = block.nodes[i]; + switch (node.nodeName) { + case 'null': + case 'expression': + case 'function': + case 'jsliteral': + case 'group': + case 'unit': + continue; + default: + ret.push(this.visit(node)); + } + } + } + + // nesting + for (var i = 0, len = block.nodes.length; i < len; ++i) { + node = block.nodes[i]; + ret.push(this.visit(node)); + } + + return block; +}; + +/** + * Visit Group. + */ + +Normalizer.prototype.visitGroup = function(group){ + // TODO: clean this mess up + var stack = this.stack + , map = this.map + , self = this; + + stack.push(group.nodes); + + var selectors = this.compileSelectors(stack); + + // map for extension lookup + selectors.forEach(function(selector){ + map[selector] = map[selector] || []; + map[selector].push(group); + }); + + // extensions + this.extend(group, selectors); + + group.block = this.visit(group.block); + stack.pop(); + return group; +}; + +/** + * Visit Media. + */ + +Normalizer.prototype.visitMedia = function(media){ + var props = [] + , other = []; + + media.block.nodes.forEach(function(node, i) { + node = this.visit(node); + + if ('property' == node.nodeName) { + props.push(node); + } else { + other.push(node); + } + }, this); + + // Fake self-referencing group to contain + // any props that are floating + // directly on the @media declaration + if (props.length) { + var selfLiteral = new nodes.Literal('&'); + selfLiteral.lineno = media.lineno; + selfLiteral.filename = media.filename; + + var selfSelector = new nodes.Selector(selfLiteral); + selfSelector.lineno = media.lineno; + selfSelector.filename = media.filename; + selfSelector.val = selfLiteral.val; + + var propertyGroup = new nodes.Group; + propertyGroup.lineno = media.lineno; + propertyGroup.filename = media.filename; + + var propertyBlock = new nodes.Block(media.block, propertyGroup); + propertyBlock.lineno = media.lineno; + propertyBlock.filename = media.filename; + + props.forEach(function(prop){ + propertyBlock.push(prop); + }); + + propertyGroup.push(selfSelector); + propertyGroup.block = propertyBlock; + + media.block.nodes = []; + media.block.push(propertyGroup); + other.forEach(function(node){ + media.block.push(node); + }); + } + + return media; +} + +/** + * Apply `group` extensions. + * + * @param {Group} group + * @param {Array} selectors + * @api private + */ + +Normalizer.prototype.extend = function(group, selectors){ + var map = this.map + , self = this; + + group.block.node.extends.forEach(function(extend){ + var groups = map[extend]; + if (!groups) throw new Error('Failed to @extend "' + extend + '"'); + selectors.forEach(function(selector){ + var node = new nodes.Selector; + node.val = selector; + node.inherits = false; + groups.forEach(function(group){ + if (!group.nodes.some(function(n){ return n.val == selector })) { + self.extend(group, selectors); + group.push(node); + } + }); + }); + }); +}; + +/** + * Compile selector strings in `arr` from the bottom-up + * to produce the selector combinations. For example + * the following Stylus: + * + * ul + * li + * p + * a + * color: red + * + * Would return: + * + * [ 'ul li a', 'ul p a' ] + * + * @param {Array} arr + * @return {Array} + * @api private + */ + +Normalizer.prototype.compileSelectors = function(arr){ + // TODO: remove this duplication + var stack = this.stack + , self = this + , selectors = [] + , buf = []; + + function compile(arr, i) { + if (i) { + arr[i].forEach(function(selector){ + buf.unshift(selector.val); + compile(arr, i - 1); + buf.shift(); + }); + } else { + arr[0].forEach(function(selector){ + var str = selector.val.trim(); + if (buf.length) { + for (var i = 0, len = buf.length; i < len; ++i) { + if (~buf[i].indexOf('&')) { + str = buf[i].replace(/&/g, str).trim(); + } else { + str += ' ' + buf[i].trim(); + } + } + } + selectors.push(str.trimRight()); + }); + } + } + + compile(arr, arr.length - 1); + + return selectors; +}; diff --git a/node_modules/stylus/node_modules/cssom/.gitmodules b/node_modules/stylus/node_modules/cssom/.gitmodules new file mode 100644 index 0000000..6357c00 --- /dev/null +++ b/node_modules/stylus/node_modules/cssom/.gitmodules @@ -0,0 +1,6 @@ +[submodule "spec/vendor/objectDiff"] + path = spec/vendor/objectDiff + url = git://github.com/NV/objectDiff.js.git +[submodule "spec/vendor/jasmine-html-reporter"] + path = spec/vendor/jasmine-html-reporter + url = git://github.com/NV/jasmine-html-reporter.git diff --git a/node_modules/stylus/node_modules/cssom/.npmignore b/node_modules/stylus/node_modules/cssom/.npmignore new file mode 100644 index 0000000..9c8f462 --- /dev/null +++ b/node_modules/stylus/node_modules/cssom/.npmignore @@ -0,0 +1,7 @@ +docs/ +src/ +test/ +spec/ +Jakefile.js +MIT-LICENSE.txt +README.mdown diff --git a/node_modules/stylus/node_modules/cssom/README.mdown b/node_modules/stylus/node_modules/cssom/README.mdown new file mode 100644 index 0000000..31996f9 --- /dev/null +++ b/node_modules/stylus/node_modules/cssom/README.mdown @@ -0,0 +1,34 @@ +# CSSOM + +CSSOM.js is a CSS parser written in pure JavaScript. It also a partial implementation of [CSS Object Model](http://dev.w3.org/csswg/cssom/). + + CSSOM.parse("body {color: black}") + -> { + cssRules: [ + { + selectorText: "body", + style: { + 0: "color", + color: "black", + length: 1 + } + } + ] + } + + +## [Parser demo](http://nv.github.com/CSSOM/docs/parse.html) + +Works well in Google Chrome 6+, Safari 5+, Firefox 3.6+, Opera 10.63+. +Doesn't work in IE < 9 because of unsupported getters/setters. + +To use CSSOM.js in the browser you might want to build a one-file version with [Jake](http://github.com/mde/node-jake): + + ➤ jake + build/CSSOM.js is done + +To use it with Node.js: + + npm install cssom + +## [Specs](http://nv.github.com/CSSOM/spec/) diff --git a/node_modules/stylus/node_modules/cssom/lib/CSSFontFaceRule.js b/node_modules/stylus/node_modules/cssom/lib/CSSFontFaceRule.js new file mode 100644 index 0000000..b7a56cf --- /dev/null +++ b/node_modules/stylus/node_modules/cssom/lib/CSSFontFaceRule.js @@ -0,0 +1,34 @@ +//.CommonJS +var CSSOM = { + CSSStyleDeclaration: require("./CSSStyleDeclaration").CSSStyleDeclaration, + CSSRule: require("./CSSRule").CSSRule +}; +///CommonJS + + +/** + * @constructor + * @see http://dev.w3.org/csswg/cssom/#css-font-face-rule + */ +CSSOM.CSSFontFaceRule = function CSSFontFaceRule() { + CSSOM.CSSRule.call(this); + this.style = new CSSOM.CSSStyleDeclaration; + this.style.parentRule = this; +}; + +CSSOM.CSSFontFaceRule.prototype = new CSSOM.CSSRule; +CSSOM.CSSFontFaceRule.prototype.constructor = CSSOM.CSSFontFaceRule; +CSSOM.CSSFontFaceRule.prototype.type = 5; +//FIXME +//CSSOM.CSSFontFaceRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule; +//CSSOM.CSSFontFaceRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule; + +// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSFontFaceRule.cpp +CSSOM.CSSFontFaceRule.prototype.__defineGetter__("cssText", function() { + return "@font-face {" + this.style.cssText + "}"; +}); + + +//.CommonJS +exports.CSSFontFaceRule = CSSOM.CSSFontFaceRule; +///CommonJS diff --git a/node_modules/stylus/node_modules/cssom/lib/CSSImportRule.js b/node_modules/stylus/node_modules/cssom/lib/CSSImportRule.js new file mode 100644 index 0000000..3539b3e --- /dev/null +++ b/node_modules/stylus/node_modules/cssom/lib/CSSImportRule.js @@ -0,0 +1,131 @@ +//.CommonJS +var CSSOM = { + CSSRule: require("./CSSRule").CSSRule, + CSSStyleSheet: require("./CSSStyleSheet").CSSStyleSheet, + MediaList: require("./MediaList").MediaList +}; +///CommonJS + + +/** + * @constructor + * @see http://dev.w3.org/csswg/cssom/#cssimportrule + * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSImportRule + */ +CSSOM.CSSImportRule = function CSSImportRule() { + CSSOM.CSSRule.call(this); + this.href = ""; + this.media = new CSSOM.MediaList; + this.styleSheet = new CSSOM.CSSStyleSheet; +}; + +CSSOM.CSSImportRule.prototype = new CSSOM.CSSRule; +CSSOM.CSSImportRule.prototype.constructor = CSSOM.CSSImportRule; +CSSOM.CSSImportRule.prototype.type = 3; +CSSOM.CSSImportRule.prototype.__defineGetter__("cssText", function() { + var mediaText = this.media.mediaText; + return "@import url(" + this.href + ")" + (mediaText ? " " + mediaText : "") + ";"; +}); + +CSSOM.CSSImportRule.prototype.__defineSetter__("cssText", function(cssText) { + var i = 0; + + /** + * @import url(partial.css) screen, handheld; + * || | + * after-import media + * | + * url + */ + var state = ''; + + var buffer = ''; + var index; + var mediaText = ''; + for (var character; character = cssText.charAt(i); i++) { + + switch (character) { + case ' ': + case '\t': + case '\r': + case '\n': + case '\f': + if (state === 'after-import') { + state = 'url'; + } else { + buffer += character; + } + break; + + case '@': + if (!state && cssText.indexOf('@import', i) === i) { + state = 'after-import'; + i += 'import'.length; + buffer = ''; + } + break; + + case 'u': + if (state === 'url' && cssText.indexOf('url(', i) === i) { + index = cssText.indexOf(')', i + 1); + if (index === -1) { + throw i + ': ")" not found'; + } + i += 'url('.length; + var url = cssText.slice(i, index); + if (url[0] === url[url.length - 1]) { + if (url[0] === '"' || url[0] === "'") { + url = url.slice(1, -1); + } + } + this.href = url; + i = index; + state = 'media'; + } + break; + + case '"': + if (state === 'url') { + index = cssText.indexOf('"', i + 1); + if (!index) { + throw i + ": '\"' not found"; + } + this.href = cssText.slice(i + 1, index); + i = index; + state = 'media'; + } + break; + + case "'": + if (state === 'url') { + index = cssText.indexOf("'", i + 1); + if (!index) { + throw i + ': "\'" not found'; + } + this.href = cssText.slice(i + 1, index); + i = index; + state = 'media'; + } + break; + + case ';': + if (state === 'media') { + if (buffer) { + this.media.mediaText = buffer.trim(); + } + } + break; + + default: + if (state === 'media') { + buffer += character; + } + break; + } + } +}); + + +//.CommonJS +exports.CSSImportRule = CSSOM.CSSImportRule; +///CommonJS diff --git a/node_modules/stylus/node_modules/cssom/lib/CSSKeyframeRule.js b/node_modules/stylus/node_modules/cssom/lib/CSSKeyframeRule.js new file mode 100644 index 0000000..8238c6b --- /dev/null +++ b/node_modules/stylus/node_modules/cssom/lib/CSSKeyframeRule.js @@ -0,0 +1,35 @@ +//.CommonJS +var CSSOM = { + CSSRule: require("./CSSRule").CSSRule, + CSSStyleDeclaration: require('./CSSStyleDeclaration').CSSStyleDeclaration +}; +///CommonJS + + +/** + * @constructor + * @see http://www.w3.org/TR/css3-animations/#DOM-CSSKeyframeRule + */ +CSSOM.CSSKeyframeRule = function CSSKeyframeRule() { + CSSOM.CSSRule.call(this); + this.keyText = ''; + this.style = new CSSOM.CSSStyleDeclaration; + this.style.parentRule = this; +}; + +CSSOM.CSSKeyframeRule.prototype = new CSSOM.CSSRule; +CSSOM.CSSKeyframeRule.prototype.constructor = CSSOM.CSSKeyframeRule; +CSSOM.CSSKeyframeRule.prototype.type = 9; +//FIXME +//CSSOM.CSSKeyframeRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule; +//CSSOM.CSSKeyframeRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule; + +// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSKeyframeRule.cpp +CSSOM.CSSKeyframeRule.prototype.__defineGetter__("cssText", function() { + return this.keyText + " {" + this.style.cssText + "} "; +}); + + +//.CommonJS +exports.CSSKeyframeRule = CSSOM.CSSKeyframeRule; +///CommonJS diff --git a/node_modules/stylus/node_modules/cssom/lib/CSSKeyframesRule.js b/node_modules/stylus/node_modules/cssom/lib/CSSKeyframesRule.js new file mode 100644 index 0000000..0ae70ba --- /dev/null +++ b/node_modules/stylus/node_modules/cssom/lib/CSSKeyframesRule.js @@ -0,0 +1,37 @@ +//.CommonJS +var CSSOM = { + CSSRule: require("./CSSRule").CSSRule +}; +///CommonJS + + +/** + * @constructor + * @see http://www.w3.org/TR/css3-animations/#DOM-CSSKeyframesRule + */ +CSSOM.CSSKeyframesRule = function CSSKeyframesRule() { + CSSOM.CSSRule.call(this); + this.name = ''; + this.cssRules = []; +}; + +CSSOM.CSSKeyframesRule.prototype = new CSSOM.CSSRule; +CSSOM.CSSKeyframesRule.prototype.constructor = CSSOM.CSSKeyframesRule; +CSSOM.CSSKeyframesRule.prototype.type = 8; +//FIXME +//CSSOM.CSSKeyframesRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule; +//CSSOM.CSSKeyframesRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule; + +// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSKeyframesRule.cpp +CSSOM.CSSKeyframesRule.prototype.__defineGetter__("cssText", function() { + var cssTexts = []; + for (var i=0, length=this.cssRules.length; i < length; i++) { + cssTexts.push(" " + this.cssRules[i].cssText); + } + return "@" + (this._vendorPrefix || '') + "keyframes " + this.name + " { \n" + cssTexts.join("\n") + "\n}"; +}); + + +//.CommonJS +exports.CSSKeyframesRule = CSSOM.CSSKeyframesRule; +///CommonJS diff --git a/node_modules/stylus/node_modules/cssom/lib/CSSMediaRule.js b/node_modules/stylus/node_modules/cssom/lib/CSSMediaRule.js new file mode 100644 index 0000000..a6d15f8 --- /dev/null +++ b/node_modules/stylus/node_modules/cssom/lib/CSSMediaRule.js @@ -0,0 +1,39 @@ +//.CommonJS +var CSSOM = { + CSSRule: require("./CSSRule").CSSRule, + MediaList: require("./MediaList").MediaList +}; +///CommonJS + + +/** + * @constructor + * @see http://dev.w3.org/csswg/cssom/#cssmediarule + * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSMediaRule + */ +CSSOM.CSSMediaRule = function CSSMediaRule() { + CSSOM.CSSRule.call(this); + this.media = new CSSOM.MediaList; + this.cssRules = []; +}; + +CSSOM.CSSMediaRule.prototype = new CSSOM.CSSRule; +CSSOM.CSSMediaRule.prototype.constructor = CSSOM.CSSMediaRule; +CSSOM.CSSMediaRule.prototype.type = 4; +//FIXME +//CSSOM.CSSMediaRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule; +//CSSOM.CSSMediaRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule; + +// http://opensource.apple.com/source/WebCore/WebCore-658.28/css/CSSMediaRule.cpp +CSSOM.CSSMediaRule.prototype.__defineGetter__("cssText", function() { + var cssTexts = []; + for (var i=0, length=this.cssRules.length; i < length; i++) { + cssTexts.push(this.cssRules[i].cssText); + } + return "@media " + this.media.mediaText + " {" + cssTexts.join("") + "}"; +}); + + +//.CommonJS +exports.CSSMediaRule = CSSOM.CSSMediaRule; +///CommonJS diff --git a/node_modules/stylus/node_modules/cssom/lib/CSSRule.js b/node_modules/stylus/node_modules/cssom/lib/CSSRule.js new file mode 100644 index 0000000..4acff83 --- /dev/null +++ b/node_modules/stylus/node_modules/cssom/lib/CSSRule.js @@ -0,0 +1,39 @@ +//.CommonJS +var CSSOM = {}; +///CommonJS + + +/** + * @constructor + * @see http://dev.w3.org/csswg/cssom/#the-cssrule-interface + * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSRule + */ +CSSOM.CSSRule = function CSSRule() { + this.parentRule = null; + this.parentStyleSheet = null; +}; + +CSSOM.CSSRule.STYLE_RULE = 1; +CSSOM.CSSRule.IMPORT_RULE = 3; +CSSOM.CSSRule.MEDIA_RULE = 4; +CSSOM.CSSRule.FONT_FACE_RULE = 5; +CSSOM.CSSRule.PAGE_RULE = 6; +CSSOM.CSSRule.WEBKIT_KEYFRAMES_RULE = 8; +CSSOM.CSSRule.WEBKIT_KEYFRAME_RULE = 9; + +// Obsolete in CSSOM http://dev.w3.org/csswg/cssom/ +//CSSOM.CSSRule.UNKNOWN_RULE = 0; +//CSSOM.CSSRule.CHARSET_RULE = 2; + +// Never implemented +//CSSOM.CSSRule.VARIABLES_RULE = 7; + +CSSOM.CSSRule.prototype = { + constructor: CSSOM.CSSRule + //FIXME +}; + + +//.CommonJS +exports.CSSRule = CSSOM.CSSRule; +///CommonJS diff --git a/node_modules/stylus/node_modules/cssom/lib/CSSStyleDeclaration.js b/node_modules/stylus/node_modules/cssom/lib/CSSStyleDeclaration.js new file mode 100644 index 0000000..365a1d3 --- /dev/null +++ b/node_modules/stylus/node_modules/cssom/lib/CSSStyleDeclaration.js @@ -0,0 +1,148 @@ +//.CommonJS +var CSSOM = {}; +///CommonJS + + +/** + * @constructor + * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration + */ +CSSOM.CSSStyleDeclaration = function CSSStyleDeclaration(){ + this.length = 0; + this.parentRule = null; + + // NON-STANDARD + this._importants = {}; +}; + + +CSSOM.CSSStyleDeclaration.prototype = { + + constructor: CSSOM.CSSStyleDeclaration, + + /** + * + * @param {string} name + * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-getPropertyValue + * @return {string} the value of the property if it has been explicitly set for this declaration block. + * Returns the empty string if the property has not been set. + */ + getPropertyValue: function(name) { + return this[name] || ""; + }, + + /** + * + * @param {string} name + * @param {string} value + * @param {string} [priority=null] "important" or null + * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-setProperty + */ + setProperty: function(name, value, priority) { + if (this[name]) { + // Property already exist. Overwrite it. + var index = Array.prototype.indexOf.call(this, name); + if (index < 0) { + this[this.length] = name; + this.length++; + } + } else { + // New property. + this[this.length] = name; + this.length++; + } + this[name] = value; + this._importants[name] = priority; + }, + + /** + * + * @param {string} name + * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-removeProperty + * @return {string} the value of the property if it has been explicitly set for this declaration block. + * Returns the empty string if the property has not been set or the property name does not correspond to a known CSS property. + */ + removeProperty: function(name) { + if (!(name in this)) { + return ""; + } + var index = Array.prototype.indexOf.call(this, name); + if (index < 0) { + return ""; + } + var prevValue = this[name]; + this[name] = ""; + + // That's what WebKit and Opera do + Array.prototype.splice.call(this, index, 1); + + // That's what Firefox does + //this[index] = "" + + return prevValue; + }, + + getPropertyCSSValue: function() { + //FIXME + }, + + /** + * + * @param {String} name + */ + getPropertyPriority: function(name) { + return this._importants[name] || ""; + }, + + + /** + * element.style.overflow = "auto" + * element.style.getPropertyShorthand("overflow-x") + * -> "overflow" + */ + getPropertyShorthand: function() { + //FIXME + }, + + isPropertyImplicit: function() { + //FIXME + }, + + // Doesn't work in IE < 9 + get cssText(){ + var properties = []; + for (var i=0, length=this.length; i < length; ++i) { + var name = this[i]; + var value = this.getPropertyValue(name); + var priority = this.getPropertyPriority(name); + if (priority) { + priority = " !" + priority; + } + properties[i] = name + ": " + value + priority + ";"; + } + return properties.join(" "); + }, + + set cssText(cssText){ + var i, name; + for (i = this.length; i--;) { + name = this[i]; + this[name] = ""; + } + Array.prototype.splice.call(this, 0, this.length); + this._importants = {}; + + var dummyRule = CSSOM.parse('#bogus{' + cssText + '}').cssRules[0].style; + var length = dummyRule.length; + for (i = 0; i < length; ++i) { + name = dummyRule[i]; + this.setProperty(dummyRule[i], dummyRule.getPropertyValue(name), dummyRule.getPropertyPriority(name)); + } + } +}; + + +//.CommonJS +exports.CSSStyleDeclaration = CSSOM.CSSStyleDeclaration; +CSSOM.parse = require('./parse').parse; // Cannot be included sooner due to the mutual dependency between parse.js and CSSStyleDeclaration.js +///CommonJS diff --git a/node_modules/stylus/node_modules/cssom/lib/CSSStyleRule.js b/node_modules/stylus/node_modules/cssom/lib/CSSStyleRule.js new file mode 100644 index 0000000..4224397 --- /dev/null +++ b/node_modules/stylus/node_modules/cssom/lib/CSSStyleRule.js @@ -0,0 +1,189 @@ +//.CommonJS +var CSSOM = { + CSSStyleDeclaration: require("./CSSStyleDeclaration").CSSStyleDeclaration, + CSSRule: require("./CSSRule").CSSRule +}; +///CommonJS + + +/** + * @constructor + * @see http://dev.w3.org/csswg/cssom/#cssstylerule + * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleRule + */ +CSSOM.CSSStyleRule = function CSSStyleRule() { + CSSOM.CSSRule.call(this); + this.selectorText = ""; + this.style = new CSSOM.CSSStyleDeclaration; + this.style.parentRule = this; +}; + +CSSOM.CSSStyleRule.prototype = new CSSOM.CSSRule; +CSSOM.CSSStyleRule.prototype.constructor = CSSOM.CSSStyleRule; +CSSOM.CSSStyleRule.prototype.type = 1; + +CSSOM.CSSStyleRule.prototype.__defineGetter__("cssText", function() { + var text; + if (this.selectorText) { + text = this.selectorText + " {" + this.style.cssText + "}"; + } else { + text = ""; + } + return text; +}); + +CSSOM.CSSStyleRule.prototype.__defineSetter__("cssText", function(cssText) { + var rule = CSSOM.CSSStyleRule.parse(cssText); + this.style = rule.style; + this.selectorText = rule.selectorText; +}); + + +/** + * NON-STANDARD + * lightweight version of parse.js. + * @param {string} ruleText + * @return CSSStyleRule + */ +CSSOM.CSSStyleRule.parse = function(ruleText) { + var i = 0; + var state = "selector"; + var index; + var j = i; + var buffer = ""; + + var SIGNIFICANT_WHITESPACE = { + "selector": true, + "value": true + }; + + var styleRule = new CSSOM.CSSStyleRule; + var selector, name, value, priority=""; + + for (var character; character = ruleText.charAt(i); i++) { + + switch (character) { + + case " ": + case "\t": + case "\r": + case "\n": + case "\f": + if (SIGNIFICANT_WHITESPACE[state]) { + // Squash 2 or more white-spaces in the row into 1 + switch (ruleText.charAt(i - 1)) { + case " ": + case "\t": + case "\r": + case "\n": + case "\f": + break; + default: + buffer += " "; + break; + } + } + break; + + // String + case '"': + j = i + 1; + index = ruleText.indexOf('"', j) + 1; + if (!index) { + throw '" is missing'; + } + buffer += ruleText.slice(i, index); + i = index - 1; + break; + + case "'": + j = i + 1; + index = ruleText.indexOf("'", j) + 1; + if (!index) { + throw "' is missing"; + } + buffer += ruleText.slice(i, index); + i = index - 1; + break; + + // Comment + case "/": + if (ruleText.charAt(i + 1) === "*") { + i += 2; + index = ruleText.indexOf("*/", i); + if (index === -1) { + throw new SyntaxError("Missing */"); + } else { + i = index + 1; + } + } else { + buffer += character; + } + break; + + case "{": + if (state === "selector") { + styleRule.selectorText = buffer.trim(); + buffer = ""; + state = "name"; + } + break; + + case ":": + if (state === "name") { + name = buffer.trim(); + buffer = ""; + state = "value"; + } else { + buffer += character; + } + break; + + case "!": + if (state === "value" && ruleText.indexOf("!important", i) === i) { + priority = "important"; + i += "important".length; + } else { + buffer += character; + } + break; + + case ";": + if (state === "value") { + styleRule.style.setProperty(name, buffer.trim(), priority); + priority = ""; + buffer = ""; + state = "name"; + } else { + buffer += character; + } + break; + + case "}": + if (state === "value") { + styleRule.style.setProperty(name, buffer.trim(), priority); + priority = ""; + buffer = ""; + } else if (state === "name") { + break; + } else { + buffer += character; + } + state = "selector"; + break; + + default: + buffer += character; + break; + + } + } + + return styleRule; + +}; + + +//.CommonJS +exports.CSSStyleRule = CSSOM.CSSStyleRule; +///CommonJS diff --git a/node_modules/stylus/node_modules/cssom/lib/CSSStyleSheet.js b/node_modules/stylus/node_modules/cssom/lib/CSSStyleSheet.js new file mode 100644 index 0000000..3ec733f --- /dev/null +++ b/node_modules/stylus/node_modules/cssom/lib/CSSStyleSheet.js @@ -0,0 +1,87 @@ +//.CommonJS +var CSSOM = { + StyleSheet: require("./StyleSheet").StyleSheet, + CSSStyleRule: require("./CSSStyleRule").CSSStyleRule +}; +///CommonJS + + +/** + * @constructor + * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet + */ +CSSOM.CSSStyleSheet = function CSSStyleSheet() { + CSSOM.StyleSheet.call(this); + this.cssRules = []; +}; + + +CSSOM.CSSStyleSheet.prototype = new CSSOM.StyleSheet; +CSSOM.CSSStyleSheet.prototype.constructor = CSSOM.CSSStyleSheet; + + +/** + * Used to insert a new rule into the style sheet. The new rule now becomes part of the cascade. + * + * sheet = new Sheet("body {margin: 0}") + * sheet.toString() + * -> "body{margin:0;}" + * sheet.insertRule("img {border: none}", 0) + * -> 0 + * sheet.toString() + * -> "img{border:none;}body{margin:0;}" + * + * @param {string} rule + * @param {number} index + * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet-insertRule + * @return {number} The index within the style sheet's rule collection of the newly inserted rule. + */ +CSSOM.CSSStyleSheet.prototype.insertRule = function(rule, index) { + if (index < 0 || index > this.cssRules.length) { + throw new RangeError("INDEX_SIZE_ERR"); + } + var cssRule = CSSOM.parse(rule).cssRules[0]; + this.cssRules.splice(index, 0, cssRule); + return index; +}; + + +/** + * Used to delete a rule from the style sheet. + * + * sheet = new Sheet("img{border:none} body{margin:0}") + * sheet.toString() + * -> "img{border:none;}body{margin:0;}" + * sheet.deleteRule(0) + * sheet.toString() + * -> "body{margin:0;}" + * + * @param {number} index within the style sheet's rule list of the rule to remove. + * @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet-deleteRule + */ +CSSOM.CSSStyleSheet.prototype.deleteRule = function(index) { + if (index < 0 || index >= this.cssRules.length) { + throw new RangeError("INDEX_SIZE_ERR"); + } + this.cssRules.splice(index, 1); +}; + + +/** + * NON-STANDARD + * @return {string} serialize stylesheet + */ +CSSOM.CSSStyleSheet.prototype.toString = function() { + var result = ""; + var rules = this.cssRules; + for (var i=0; i=0.2.0" + }, + "devDependencies": { + "jake": "0.2.x" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://creativecommons.org/licenses/MIT/" + } + ], + "scripts": { + "prepublish": "jake lib/index.js" + }, + "readme": "# CSSOM\n\nCSSOM.js is a CSS parser written in pure JavaScript. It also a partial implementation of [CSS Object Model](http://dev.w3.org/csswg/cssom/). \n\n CSSOM.parse(\"body {color: black}\")\n -> {\n cssRules: [\n {\n selectorText: \"body\",\n style: {\n 0: \"color\",\n color: \"black\",\n length: 1\n }\n }\n ]\n }\n\n\n## [Parser demo](http://nv.github.com/CSSOM/docs/parse.html)\n\nWorks well in Google Chrome 6+, Safari 5+, Firefox 3.6+, Opera 10.63+.\nDoesn't work in IE < 9 because of unsupported getters/setters.\n\nTo use CSSOM.js in the browser you might want to build a one-file version with [Jake](http://github.com/mde/node-jake):\n\n ➤ jake\n build/CSSOM.js is done\n\nTo use it with Node.js:\n\n npm install cssom\n\n## [Specs](http://nv.github.com/CSSOM/spec/)\n", + "readmeFilename": "README.mdown", + "_id": "cssom@0.2.5", + "dist": { + "shasum": "a290e1d4d09149286a0fdc3198126a0f9a49712a" + }, + "_from": "cssom@0.2.x", + "_resolved": "https://registry.npmjs.org/cssom/-/cssom-0.2.5.tgz" +} diff --git a/node_modules/stylus/node_modules/debug/Readme.md b/node_modules/stylus/node_modules/debug/Readme.md new file mode 100644 index 0000000..c5a34e8 --- /dev/null +++ b/node_modules/stylus/node_modules/debug/Readme.md @@ -0,0 +1,115 @@ +# debug + + tiny node.js debugging utility modelled after node core's debugging technique. + +## Installation + +``` +$ npm install debug +``` + +## Usage + + With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility. + +Example _app.js_: + +```js +var debug = require('debug')('http') + , http = require('http') + , name = 'My App'; + +// fake app + +debug('booting %s', name); + +http.createServer(function(req, res){ + debug(req.method + ' ' + req.url); + res.end('hello\n'); +}).listen(3000, function(){ + debug('listening'); +}); + +// fake worker of some kind + +require('./worker'); +``` + +Example _worker.js_: + +```js +var debug = require('debug')('worker'); + +setInterval(function(){ + debug('doing some work'); +}, 1000); +``` + + The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples: + + ![debug http and worker](http://f.cl.ly/items/18471z1H402O24072r1J/Screenshot.png) + + ![debug worker](http://f.cl.ly/items/1X413v1a3M0d3C2c1E0i/Screenshot.png) + +## Millisecond diff + + When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls. + + ![](http://f.cl.ly/items/2i3h1d3t121M2Z1A3Q0N/Screenshot.png) + + When stderr is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below: + _(NOTE: Debug now uses stderr instead of stdout, so the correct shell command for this example is actually `DEBUG=* node example/worker 2> out &`)_ + + ![](http://f.cl.ly/items/112H3i0e0o0P0a2Q2r11/Screenshot.png) + +## Conventions + + If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser". + +## Wildcards + + The "*" character may be used as a wildcard. Suppose for example your library has debuggers named "connect:bodyParser", "connect:compress", "connect:session", instead of listing all three with `DEBUG=connect:bodyParser,connect.compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`. + + You can also exclude specific debuggers by prefixing them with a "-" character. For example, `DEBUG=* -connect:*` would include all debuggers except those starting with "connect:". + +## Browser support + + Debug works in the browser as well, currently persisted by `localStorage`. For example if you have `worker:a` and `worker:b` as shown below, and wish to debug both type `debug.enable('worker:*')` in the console and refresh the page, this will remain until you disable with `debug.disable()`. + +```js +a = debug('worker:a'); +b = debug('worker:b'); + +setInterval(function(){ + a('doing some work'); +}, 1000); + +setInterval(function(){ + a('doing some work'); +}, 1200); +``` + +## License + +(The MIT License) + +Copyright (c) 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/node_modules/stylus/node_modules/debug/debug.js b/node_modules/stylus/node_modules/debug/debug.js new file mode 100644 index 0000000..509dc0d --- /dev/null +++ b/node_modules/stylus/node_modules/debug/debug.js @@ -0,0 +1,137 @@ + +/** + * Expose `debug()` as the module. + */ + +module.exports = debug; + +/** + * Create a debugger with the given `name`. + * + * @param {String} name + * @return {Type} + * @api public + */ + +function debug(name) { + if (!debug.enabled(name)) return function(){}; + + return function(fmt){ + fmt = coerce(fmt); + + var curr = new Date; + var ms = curr - (debug[name] || curr); + debug[name] = curr; + + fmt = name + + ' ' + + fmt + + ' +' + debug.humanize(ms); + + // This hackery is required for IE8 + // where `console.log` doesn't have 'apply' + window.console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); + } +} + +/** + * The currently active debug mode names. + */ + +debug.names = []; +debug.skips = []; + +/** + * Enables a debug mode by name. This can include modes + * separated by a colon and wildcards. + * + * @param {String} name + * @api public + */ + +debug.enable = function(name) { + try { + localStorage.debug = name; + } catch(e){} + + var split = (name || '').split(/[\s,]+/) + , len = split.length; + + for (var i = 0; i < len; i++) { + name = split[i].replace('*', '.*?'); + if (name[0] === '-') { + debug.skips.push(new RegExp('^' + name.substr(1) + '$')); + } + else { + debug.names.push(new RegExp('^' + name + '$')); + } + } +}; + +/** + * Disable debug output. + * + * @api public + */ + +debug.disable = function(){ + debug.enable(''); +}; + +/** + * Humanize the given `ms`. + * + * @param {Number} m + * @return {String} + * @api private + */ + +debug.humanize = function(ms) { + var sec = 1000 + , min = 60 * 1000 + , hour = 60 * min; + + if (ms >= hour) return (ms / hour).toFixed(1) + 'h'; + if (ms >= min) return (ms / min).toFixed(1) + 'm'; + if (ms >= sec) return (ms / sec | 0) + 's'; + return ms + 'ms'; +}; + +/** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ + +debug.enabled = function(name) { + for (var i = 0, len = debug.skips.length; i < len; i++) { + if (debug.skips[i].test(name)) { + return false; + } + } + for (var i = 0, len = debug.names.length; i < len; i++) { + if (debug.names[i].test(name)) { + return true; + } + } + return false; +}; + +/** + * Coerce `val`. + */ + +function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; +} + +// persist + +try { + if (window.localStorage) debug.enable(localStorage.debug); +} catch(e){} diff --git a/node_modules/stylus/node_modules/debug/index.js b/node_modules/stylus/node_modules/debug/index.js new file mode 100644 index 0000000..e02c13b --- /dev/null +++ b/node_modules/stylus/node_modules/debug/index.js @@ -0,0 +1,5 @@ +if ('undefined' == typeof window) { + module.exports = require('./lib/debug'); +} else { + module.exports = require('./debug'); +} diff --git a/node_modules/stylus/node_modules/debug/lib/debug.js b/node_modules/stylus/node_modules/debug/lib/debug.js new file mode 100644 index 0000000..3b0a918 --- /dev/null +++ b/node_modules/stylus/node_modules/debug/lib/debug.js @@ -0,0 +1,147 @@ +/** + * Module dependencies. + */ + +var tty = require('tty'); + +/** + * Expose `debug()` as the module. + */ + +module.exports = debug; + +/** + * Enabled debuggers. + */ + +var names = [] + , skips = []; + +(process.env.DEBUG || '') + .split(/[\s,]+/) + .forEach(function(name){ + name = name.replace('*', '.*?'); + if (name[0] === '-') { + skips.push(new RegExp('^' + name.substr(1) + '$')); + } else { + names.push(new RegExp('^' + name + '$')); + } + }); + +/** + * Colors. + */ + +var colors = [6, 2, 3, 4, 5, 1]; + +/** + * Previous debug() call. + */ + +var prev = {}; + +/** + * Previously assigned color. + */ + +var prevColor = 0; + +/** + * Is stdout a TTY? Colored output is disabled when `true`. + */ + +var isatty = tty.isatty(2); + +/** + * Select a color. + * + * @return {Number} + * @api private + */ + +function color() { + return colors[prevColor++ % colors.length]; +} + +/** + * Humanize the given `ms`. + * + * @param {Number} m + * @return {String} + * @api private + */ + +function humanize(ms) { + var sec = 1000 + , min = 60 * 1000 + , hour = 60 * min; + + if (ms >= hour) return (ms / hour).toFixed(1) + 'h'; + if (ms >= min) return (ms / min).toFixed(1) + 'm'; + if (ms >= sec) return (ms / sec | 0) + 's'; + return ms + 'ms'; +} + +/** + * Create a debugger with the given `name`. + * + * @param {String} name + * @return {Type} + * @api public + */ + +function debug(name) { + function disabled(){} + disabled.enabled = false; + + var match = skips.some(function(re){ + return re.test(name); + }); + + if (match) return disabled; + + match = names.some(function(re){ + return re.test(name); + }); + + if (!match) return disabled; + var c = color(); + + function colored(fmt) { + fmt = coerce(fmt); + + var curr = new Date; + var ms = curr - (prev[name] || curr); + prev[name] = curr; + + fmt = ' \u001b[9' + c + 'm' + name + ' ' + + '\u001b[3' + c + 'm\u001b[90m' + + fmt + '\u001b[3' + c + 'm' + + ' +' + humanize(ms) + '\u001b[0m'; + + console.error.apply(this, arguments); + } + + function plain(fmt) { + fmt = coerce(fmt); + + fmt = new Date().toUTCString() + + ' ' + name + ' ' + fmt; + console.error.apply(this, arguments); + } + + colored.enabled = plain.enabled = true; + + return isatty || process.env.DEBUG_COLORS + ? colored + : plain; +} + +/** + * Coerce `val`. + */ + +function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; +} diff --git a/node_modules/stylus/node_modules/debug/package.json b/node_modules/stylus/node_modules/debug/package.json new file mode 100644 index 0000000..35553c9 --- /dev/null +++ b/node_modules/stylus/node_modules/debug/package.json @@ -0,0 +1,46 @@ +{ + "name": "debug", + "version": "0.7.3", + "repository": { + "type": "git", + "url": "git://github.com/visionmedia/debug.git" + }, + "description": "small debugging utility", + "keywords": [ + "debug", + "log", + "debugger" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "*" + }, + "main": "lib/debug.js", + "browserify": "debug.js", + "browser": "./debug.js", + "engines": { + "node": "*" + }, + "files": [ + "lib/debug.js", + "debug.js", + "index.js" + ], + "component": { + "scripts": { + "debug/index.js": "index.js", + "debug/debug.js": "debug.js" + } + }, + "readme": "# debug\n\n tiny node.js debugging utility modelled after node core's debugging technique.\n\n## Installation\n\n```\n$ npm install debug\n```\n\n## Usage\n\n With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility.\n \nExample _app.js_:\n\n```js\nvar debug = require('debug')('http')\n , http = require('http')\n , name = 'My App';\n\n// fake app\n\ndebug('booting %s', name);\n\nhttp.createServer(function(req, res){\n debug(req.method + ' ' + req.url);\n res.end('hello\\n');\n}).listen(3000, function(){\n debug('listening');\n});\n\n// fake worker of some kind\n\nrequire('./worker');\n```\n\nExample _worker.js_:\n\n```js\nvar debug = require('debug')('worker');\n\nsetInterval(function(){\n debug('doing some work');\n}, 1000);\n```\n\n The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples:\n\n ![debug http and worker](http://f.cl.ly/items/18471z1H402O24072r1J/Screenshot.png)\n\n ![debug worker](http://f.cl.ly/items/1X413v1a3M0d3C2c1E0i/Screenshot.png)\n\n## Millisecond diff\n\n When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the \"+NNNms\" will show you how much time was spent between calls.\n\n ![](http://f.cl.ly/items/2i3h1d3t121M2Z1A3Q0N/Screenshot.png)\n\n When stderr is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below:\n _(NOTE: Debug now uses stderr instead of stdout, so the correct shell command for this example is actually `DEBUG=* node example/worker 2> out &`)_\n \n ![](http://f.cl.ly/items/112H3i0e0o0P0a2Q2r11/Screenshot.png)\n \n## Conventions\n\n If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use \":\" to separate features. For example \"bodyParser\" from Connect would then be \"connect:bodyParser\". \n\n## Wildcards\n\n The \"*\" character may be used as a wildcard. Suppose for example your library has debuggers named \"connect:bodyParser\", \"connect:compress\", \"connect:session\", instead of listing all three with `DEBUG=connect:bodyParser,connect.compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.\n\n You can also exclude specific debuggers by prefixing them with a \"-\" character. For example, `DEBUG=* -connect:*` would include all debuggers except those starting with \"connect:\".\n\n## Browser support\n\n Debug works in the browser as well, currently persisted by `localStorage`. For example if you have `worker:a` and `worker:b` as shown below, and wish to debug both type `debug.enable('worker:*')` in the console and refresh the page, this will remain until you disable with `debug.disable()`. \n\n```js\na = debug('worker:a');\nb = debug('worker:b');\n\nsetInterval(function(){\n a('doing some work');\n}, 1000);\n\nsetInterval(function(){\n a('doing some work');\n}, 1200);\n```\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/debug/issues" + }, + "_id": "debug@0.7.3", + "_from": "debug@*" +} diff --git a/node_modules/stylus/node_modules/mkdirp/.npmignore b/node_modules/stylus/node_modules/mkdirp/.npmignore new file mode 100644 index 0000000..9303c34 --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/.npmignore @@ -0,0 +1,2 @@ +node_modules/ +npm-debug.log \ No newline at end of file diff --git a/node_modules/stylus/node_modules/mkdirp/.travis.yml b/node_modules/stylus/node_modules/mkdirp/.travis.yml new file mode 100644 index 0000000..84fd7ca --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - 0.6 + - 0.8 + - 0.9 diff --git a/node_modules/stylus/node_modules/mkdirp/LICENSE b/node_modules/stylus/node_modules/mkdirp/LICENSE new file mode 100644 index 0000000..432d1ae --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/LICENSE @@ -0,0 +1,21 @@ +Copyright 2010 James Halliday (mail@substack.net) + +This project is free software released under the MIT/X11 license: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/stylus/node_modules/mkdirp/examples/pow.js b/node_modules/stylus/node_modules/mkdirp/examples/pow.js new file mode 100644 index 0000000..e692421 --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/examples/pow.js @@ -0,0 +1,6 @@ +var mkdirp = require('mkdirp'); + +mkdirp('/tmp/foo/bar/baz', function (err) { + if (err) console.error(err) + else console.log('pow!') +}); diff --git a/node_modules/stylus/node_modules/mkdirp/index.js b/node_modules/stylus/node_modules/mkdirp/index.js new file mode 100644 index 0000000..fda6de8 --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/index.js @@ -0,0 +1,82 @@ +var path = require('path'); +var fs = require('fs'); + +module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP; + +function mkdirP (p, mode, f, made) { + if (typeof mode === 'function' || mode === undefined) { + f = mode; + mode = 0777 & (~process.umask()); + } + if (!made) made = null; + + var cb = f || function () {}; + if (typeof mode === 'string') mode = parseInt(mode, 8); + p = path.resolve(p); + + fs.mkdir(p, mode, function (er) { + if (!er) { + made = made || p; + return cb(null, made); + } + switch (er.code) { + case 'ENOENT': + mkdirP(path.dirname(p), mode, function (er, made) { + if (er) cb(er, made); + else mkdirP(p, mode, cb, made); + }); + break; + + // In the case of any other error, just see if there's a dir + // there already. If so, then hooray! If not, then something + // is borked. + default: + fs.stat(p, function (er2, stat) { + // if the stat fails, then that's super weird. + // let the original error be the failure reason. + if (er2 || !stat.isDirectory()) cb(er, made) + else cb(null, made); + }); + break; + } + }); +} + +mkdirP.sync = function sync (p, mode, made) { + if (mode === undefined) { + mode = 0777 & (~process.umask()); + } + if (!made) made = null; + + if (typeof mode === 'string') mode = parseInt(mode, 8); + p = path.resolve(p); + + try { + fs.mkdirSync(p, mode); + made = made || p; + } + catch (err0) { + switch (err0.code) { + case 'ENOENT' : + made = sync(path.dirname(p), mode, made); + sync(p, mode, made); + break; + + // In the case of any other error, just see if there's a dir + // there already. If so, then hooray! If not, then something + // is borked. + default: + var stat; + try { + stat = fs.statSync(p); + } + catch (err1) { + throw err0; + } + if (!stat.isDirectory()) throw err0; + break; + } + } + + return made; +}; diff --git a/node_modules/stylus/node_modules/mkdirp/package.json b/node_modules/stylus/node_modules/mkdirp/package.json new file mode 100644 index 0000000..bd9194b --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/package.json @@ -0,0 +1,33 @@ +{ + "name": "mkdirp", + "description": "Recursively mkdir, like `mkdir -p`", + "version": "0.3.5", + "author": { + "name": "James Halliday", + "email": "mail@substack.net", + "url": "http://substack.net" + }, + "main": "./index", + "keywords": [ + "mkdir", + "directory" + ], + "repository": { + "type": "git", + "url": "http://github.com/substack/node-mkdirp.git" + }, + "scripts": { + "test": "tap test/*.js" + }, + "devDependencies": { + "tap": "~0.4.0" + }, + "license": "MIT", + "readme": "# mkdirp\n\nLike `mkdir -p`, but in node.js!\n\n[![build status](https://secure.travis-ci.org/substack/node-mkdirp.png)](http://travis-ci.org/substack/node-mkdirp)\n\n# example\n\n## pow.js\n\n```js\nvar mkdirp = require('mkdirp');\n \nmkdirp('/tmp/foo/bar/baz', function (err) {\n if (err) console.error(err)\n else console.log('pow!')\n});\n```\n\nOutput\n\n```\npow!\n```\n\nAnd now /tmp/foo/bar/baz exists, huzzah!\n\n# methods\n\n```js\nvar mkdirp = require('mkdirp');\n```\n\n## mkdirp(dir, mode, cb)\n\nCreate a new directory and any necessary subdirectories at `dir` with octal\npermission string `mode`.\n\nIf `mode` isn't specified, it defaults to `0777 & (~process.umask())`.\n\n`cb(err, made)` fires with the error or the first directory `made`\nthat had to be created, if any.\n\n## mkdirp.sync(dir, mode)\n\nSynchronously create a new directory and any necessary subdirectories at `dir`\nwith octal permission string `mode`.\n\nIf `mode` isn't specified, it defaults to `0777 & (~process.umask())`.\n\nReturns the first directory that had to be created, if any.\n\n# install\n\nWith [npm](http://npmjs.org) do:\n\n```\nnpm install mkdirp\n```\n\n# license\n\nMIT\n", + "readmeFilename": "readme.markdown", + "bugs": { + "url": "https://github.com/substack/node-mkdirp/issues" + }, + "_id": "mkdirp@0.3.5", + "_from": "mkdirp@0.3.x" +} diff --git a/node_modules/stylus/node_modules/mkdirp/readme.markdown b/node_modules/stylus/node_modules/mkdirp/readme.markdown new file mode 100644 index 0000000..83b0216 --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/readme.markdown @@ -0,0 +1,63 @@ +# mkdirp + +Like `mkdir -p`, but in node.js! + +[![build status](https://secure.travis-ci.org/substack/node-mkdirp.png)](http://travis-ci.org/substack/node-mkdirp) + +# example + +## pow.js + +```js +var mkdirp = require('mkdirp'); + +mkdirp('/tmp/foo/bar/baz', function (err) { + if (err) console.error(err) + else console.log('pow!') +}); +``` + +Output + +``` +pow! +``` + +And now /tmp/foo/bar/baz exists, huzzah! + +# methods + +```js +var mkdirp = require('mkdirp'); +``` + +## mkdirp(dir, mode, cb) + +Create a new directory and any necessary subdirectories at `dir` with octal +permission string `mode`. + +If `mode` isn't specified, it defaults to `0777 & (~process.umask())`. + +`cb(err, made)` fires with the error or the first directory `made` +that had to be created, if any. + +## mkdirp.sync(dir, mode) + +Synchronously create a new directory and any necessary subdirectories at `dir` +with octal permission string `mode`. + +If `mode` isn't specified, it defaults to `0777 & (~process.umask())`. + +Returns the first directory that had to be created, if any. + +# install + +With [npm](http://npmjs.org) do: + +``` +npm install mkdirp +``` + +# license + +MIT diff --git a/node_modules/stylus/node_modules/mkdirp/test/chmod.js b/node_modules/stylus/node_modules/mkdirp/test/chmod.js new file mode 100644 index 0000000..520dcb8 --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/test/chmod.js @@ -0,0 +1,38 @@ +var mkdirp = require('../').mkdirp; +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +var ps = [ '', 'tmp' ]; + +for (var i = 0; i < 25; i++) { + var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + ps.push(dir); +} + +var file = ps.join('/'); + +test('chmod-pre', function (t) { + var mode = 0744 + mkdirp(file, mode, function (er) { + t.ifError(er, 'should not error'); + fs.stat(file, function (er, stat) { + t.ifError(er, 'should exist'); + t.ok(stat && stat.isDirectory(), 'should be directory'); + t.equal(stat && stat.mode & 0777, mode, 'should be 0744'); + t.end(); + }); + }); +}); + +test('chmod', function (t) { + var mode = 0755 + mkdirp(file, mode, function (er) { + t.ifError(er, 'should not error'); + fs.stat(file, function (er, stat) { + t.ifError(er, 'should exist'); + t.ok(stat && stat.isDirectory(), 'should be directory'); + t.end(); + }); + }); +}); diff --git a/node_modules/stylus/node_modules/mkdirp/test/clobber.js b/node_modules/stylus/node_modules/mkdirp/test/clobber.js new file mode 100644 index 0000000..0eb7099 --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/test/clobber.js @@ -0,0 +1,37 @@ +var mkdirp = require('../').mkdirp; +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +var ps = [ '', 'tmp' ]; + +for (var i = 0; i < 25; i++) { + var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + ps.push(dir); +} + +var file = ps.join('/'); + +// a file in the way +var itw = ps.slice(0, 3).join('/'); + + +test('clobber-pre', function (t) { + console.error("about to write to "+itw) + fs.writeFileSync(itw, 'I AM IN THE WAY, THE TRUTH, AND THE LIGHT.'); + + fs.stat(itw, function (er, stat) { + t.ifError(er) + t.ok(stat && stat.isFile(), 'should be file') + t.end() + }) +}) + +test('clobber', function (t) { + t.plan(2); + mkdirp(file, 0755, function (err) { + t.ok(err); + t.equal(err.code, 'ENOTDIR'); + t.end(); + }); +}); diff --git a/node_modules/stylus/node_modules/mkdirp/test/mkdirp.js b/node_modules/stylus/node_modules/mkdirp/test/mkdirp.js new file mode 100644 index 0000000..b07cd70 --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/test/mkdirp.js @@ -0,0 +1,28 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('woo', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); diff --git a/node_modules/stylus/node_modules/mkdirp/test/perm.js b/node_modules/stylus/node_modules/mkdirp/test/perm.js new file mode 100644 index 0000000..23a7abb --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/test/perm.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('async perm', function (t) { + t.plan(2); + var file = '/tmp/' + (Math.random() * (1<<30)).toString(16); + + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); + +test('async root perm', function (t) { + mkdirp('/tmp', 0755, function (err) { + if (err) t.fail(err); + t.end(); + }); + t.end(); +}); diff --git a/node_modules/stylus/node_modules/mkdirp/test/perm_sync.js b/node_modules/stylus/node_modules/mkdirp/test/perm_sync.js new file mode 100644 index 0000000..f685f60 --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/test/perm_sync.js @@ -0,0 +1,39 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('sync perm', function (t) { + t.plan(2); + var file = '/tmp/' + (Math.random() * (1<<30)).toString(16) + '.json'; + + mkdirp.sync(file, 0755); + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }); +}); + +test('sync root perm', function (t) { + t.plan(1); + + var file = '/tmp'; + mkdirp.sync(file, 0755); + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }); +}); diff --git a/node_modules/stylus/node_modules/mkdirp/test/race.js b/node_modules/stylus/node_modules/mkdirp/test/race.js new file mode 100644 index 0000000..96a0447 --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/test/race.js @@ -0,0 +1,41 @@ +var mkdirp = require('../').mkdirp; +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('race', function (t) { + t.plan(4); + var ps = [ '', 'tmp' ]; + + for (var i = 0; i < 25; i++) { + var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + ps.push(dir); + } + var file = ps.join('/'); + + var res = 2; + mk(file, function () { + if (--res === 0) t.end(); + }); + + mk(file, function () { + if (--res === 0) t.end(); + }); + + function mk (file, cb) { + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + if (cb) cb(); + } + }) + }) + }); + } +}); diff --git a/node_modules/stylus/node_modules/mkdirp/test/rel.js b/node_modules/stylus/node_modules/mkdirp/test/rel.js new file mode 100644 index 0000000..7985824 --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/test/rel.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('rel', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var cwd = process.cwd(); + process.chdir('/tmp'); + + var file = [x,y,z].join('/'); + + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + process.chdir(cwd); + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); diff --git a/node_modules/stylus/node_modules/mkdirp/test/return.js b/node_modules/stylus/node_modules/mkdirp/test/return.js new file mode 100644 index 0000000..bce68e5 --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/test/return.js @@ -0,0 +1,25 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('return value', function (t) { + t.plan(4); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + // should return the first dir created. + // By this point, it would be profoundly surprising if /tmp didn't + // already exist, since every other test makes things in there. + mkdirp(file, function (err, made) { + t.ifError(err); + t.equal(made, '/tmp/' + x); + mkdirp(file, function (err, made) { + t.ifError(err); + t.equal(made, null); + }); + }); +}); diff --git a/node_modules/stylus/node_modules/mkdirp/test/return_sync.js b/node_modules/stylus/node_modules/mkdirp/test/return_sync.js new file mode 100644 index 0000000..7c222d3 --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/test/return_sync.js @@ -0,0 +1,24 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('return value', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + // should return the first dir created. + // By this point, it would be profoundly surprising if /tmp didn't + // already exist, since every other test makes things in there. + // Note that this will throw on failure, which will fail the test. + var made = mkdirp.sync(file); + t.equal(made, '/tmp/' + x); + + // making the same file again should have no effect. + made = mkdirp.sync(file); + t.equal(made, null); +}); diff --git a/node_modules/stylus/node_modules/mkdirp/test/root.js b/node_modules/stylus/node_modules/mkdirp/test/root.js new file mode 100644 index 0000000..97ad7a2 --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/test/root.js @@ -0,0 +1,18 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('root', function (t) { + // '/' on unix, 'c:/' on windows. + var file = path.resolve('/'); + + mkdirp(file, 0755, function (err) { + if (err) throw err + fs.stat(file, function (er, stat) { + if (er) throw er + t.ok(stat.isDirectory(), 'target is a directory'); + t.end(); + }) + }); +}); diff --git a/node_modules/stylus/node_modules/mkdirp/test/sync.js b/node_modules/stylus/node_modules/mkdirp/test/sync.js new file mode 100644 index 0000000..7530cad --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/test/sync.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('sync', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + try { + mkdirp.sync(file, 0755); + } catch (err) { + t.fail(err); + return t.end(); + } + + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }); + }); +}); diff --git a/node_modules/stylus/node_modules/mkdirp/test/umask.js b/node_modules/stylus/node_modules/mkdirp/test/umask.js new file mode 100644 index 0000000..64ccafe --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/test/umask.js @@ -0,0 +1,28 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('implicit mode from umask', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + mkdirp(file, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0777 & (~process.umask())); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); diff --git a/node_modules/stylus/node_modules/mkdirp/test/umask_sync.js b/node_modules/stylus/node_modules/mkdirp/test/umask_sync.js new file mode 100644 index 0000000..35bd5cb --- /dev/null +++ b/node_modules/stylus/node_modules/mkdirp/test/umask_sync.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('umask sync modes', function (t) { + t.plan(2); + var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + + var file = '/tmp/' + [x,y,z].join('/'); + + try { + mkdirp.sync(file); + } catch (err) { + t.fail(err); + return t.end(); + } + + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, (0777 & (~process.umask()))); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }); + }); +}); diff --git a/node_modules/stylus/node_modules/sax/AUTHORS b/node_modules/stylus/node_modules/sax/AUTHORS new file mode 100644 index 0000000..7145cbc --- /dev/null +++ b/node_modules/stylus/node_modules/sax/AUTHORS @@ -0,0 +1,10 @@ +# contributors sorted by whether or not they're me. +Isaac Z. Schlueter +Stein Martin Hustad +Mikeal Rogers +Laurie Harper +Jann Horn +Elijah Insua +Henry Rawas +Justin Makeig +Mike Schilling diff --git a/node_modules/stylus/node_modules/sax/LICENSE b/node_modules/stylus/node_modules/sax/LICENSE new file mode 100644 index 0000000..62e4ccf --- /dev/null +++ b/node_modules/stylus/node_modules/sax/LICENSE @@ -0,0 +1,32 @@ +Copyright (c) Isaac Z. Schlueter ("Author") +All rights reserved. + +The BSD License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +The file "examples/strict.dtd" is licensed by the W3C and used according +to the terms of the W3C SOFTWARE NOTICE AND LICENSE. See LICENSE-W3C.html +for details. diff --git a/node_modules/stylus/node_modules/sax/LICENSE-W3C.html b/node_modules/stylus/node_modules/sax/LICENSE-W3C.html new file mode 100644 index 0000000..a611e3f --- /dev/null +++ b/node_modules/stylus/node_modules/sax/LICENSE-W3C.html @@ -0,0 +1,188 @@ + +W3C Software Notice and License
    + +
    diff --git a/node_modules/stylus/node_modules/sax/README.md b/node_modules/stylus/node_modules/sax/README.md new file mode 100644 index 0000000..c965242 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/README.md @@ -0,0 +1,216 @@ +# sax js + +A sax-style parser for XML and HTML. + +Designed with [node](http://nodejs.org/) in mind, but should work fine in +the browser or other CommonJS implementations. + +## What This Is + +* A very simple tool to parse through an XML string. +* A stepping stone to a streaming HTML parser. +* A handy way to deal with RSS and other mostly-ok-but-kinda-broken XML + docs. + +## What This Is (probably) Not + +* An HTML Parser - That's a fine goal, but this isn't it. It's just + XML. +* A DOM Builder - You can use it to build an object model out of XML, + but it doesn't do that out of the box. +* XSLT - No DOM = no querying. +* 100% Compliant with (some other SAX implementation) - Most SAX + implementations are in Java and do a lot more than this does. +* An XML Validator - It does a little validation when in strict mode, but + not much. +* A Schema-Aware XSD Thing - Schemas are an exercise in fetishistic + masochism. +* A DTD-aware Thing - Fetching DTDs is a much bigger job. + +## Regarding `Hello, world!').close(); + + // stream usage + // takes the same options as the parser + var saxStream = require("sax").createStream(strict, options) + saxStream.on("error", function (e) { + // unhandled errors will throw, since this is a proper node + // event emitter. + console.error("error!", e) + // clear the error + this._parser.error = null + this._parser.resume() + }) + saxStream.on("opentag", function (node) { + // same object as above + }) + // pipe is supported, and it's readable/writable + // same chunks coming in also go out. + fs.createReadStream("file.xml") + .pipe(saxStream) + .pipe(fs.createWriteStream("file-copy.xml")) + + + +## Arguments + +Pass the following arguments to the parser function. All are optional. + +`strict` - Boolean. Whether or not to be a jerk. Default: `false`. + +`opt` - Object bag of settings regarding string formatting. All default to `false`. + +Settings supported: + +* `trim` - Boolean. Whether or not to trim text and comment nodes. +* `normalize` - Boolean. If true, then turn any whitespace into a single + space. +* `lowercase` - Boolean. If true, then lowercase tag names and attribute names + in loose mode, rather than uppercasing them. +* `xmlns` - Boolean. If true, then namespaces are supported. +* `position` - Boolean. If false, then don't track line/col/position. + +## Methods + +`write` - Write bytes onto the stream. You don't have to do this all at +once. You can keep writing as much as you want. + +`close` - Close the stream. Once closed, no more data may be written until +it is done processing the buffer, which is signaled by the `end` event. + +`resume` - To gracefully handle errors, assign a listener to the `error` +event. Then, when the error is taken care of, you can call `resume` to +continue parsing. Otherwise, the parser will not continue while in an error +state. + +## Members + +At all times, the parser object will have the following members: + +`line`, `column`, `position` - Indications of the position in the XML +document where the parser currently is looking. + +`startTagPosition` - Indicates the position where the current tag starts. + +`closed` - Boolean indicating whether or not the parser can be written to. +If it's `true`, then wait for the `ready` event to write again. + +`strict` - Boolean indicating whether or not the parser is a jerk. + +`opt` - Any options passed into the constructor. + +`tag` - The current tag being dealt with. + +And a bunch of other stuff that you probably shouldn't touch. + +## Events + +All events emit with a single argument. To listen to an event, assign a +function to `on`. Functions get executed in the this-context of +the parser object. The list of supported events are also in the exported +`EVENTS` array. + +When using the stream interface, assign handlers using the EventEmitter +`on` function in the normal fashion. + +`error` - Indication that something bad happened. The error will be hanging +out on `parser.error`, and must be deleted before parsing can continue. By +listening to this event, you can keep an eye on that kind of stuff. Note: +this happens *much* more in strict mode. Argument: instance of `Error`. + +`text` - Text node. Argument: string of text. + +`doctype` - The ``. Argument: +object with `name` and `body` members. Attributes are not parsed, as +processing instructions have implementation dependent semantics. + +`sgmldeclaration` - Random SGML declarations. Stuff like `` +would trigger this kind of event. This is a weird thing to support, so it +might go away at some point. SAX isn't intended to be used to parse SGML, +after all. + +`opentag` - An opening tag. Argument: object with `name` and `attributes`. +In non-strict mode, tag names are uppercased, unless the `lowercase` +option is set. If the `xmlns` option is set, then it will contain +namespace binding information on the `ns` member, and will have a +`local`, `prefix`, and `uri` member. + +`closetag` - A closing tag. In loose mode, tags are auto-closed if their +parent closes. In strict mode, well-formedness is enforced. Note that +self-closing tags will have `closeTag` emitted immediately after `openTag`. +Argument: tag name. + +`attribute` - An attribute node. Argument: object with `name` and `value`. +In non-strict mode, attribute names are uppercased, unless the `lowercase` +option is set. If the `xmlns` option is set, it will also contains namespace +information. + +`comment` - A comment node. Argument: the string of the comment. + +`opencdata` - The opening tag of a ``) of a `` tags trigger a `"script"` +event, and their contents are not checked for special xml characters. +If you pass `noscript: true`, then this behavior is suppressed. + +## Reporting Problems + +It's best to write a failing test if you find an issue. I will always +accept pull requests with failing tests if they demonstrate intended +behavior, but it is very hard to figure out what issue you're describing +without a test. Writing a test is also the best way for you yourself +to figure out if you really understand the issue you think you have with +sax-js. diff --git a/node_modules/stylus/node_modules/sax/component.json b/node_modules/stylus/node_modules/sax/component.json new file mode 100644 index 0000000..96b5d73 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/component.json @@ -0,0 +1,12 @@ +{ + "name": "sax", + "description": "An evented streaming XML parser in JavaScript", + "author": "Isaac Z. Schlueter (http://blog.izs.me/)", + "version": "0.5.2", + "main": "lib/sax.js", + "license": "BSD", + "scripts": [ + "lib/sax.js" + ], + "repository": "git://github.com/isaacs/sax-js.git" +} diff --git a/node_modules/stylus/node_modules/sax/examples/big-not-pretty.xml b/node_modules/stylus/node_modules/sax/examples/big-not-pretty.xml new file mode 100644 index 0000000..fb5265d --- /dev/null +++ b/node_modules/stylus/node_modules/sax/examples/big-not-pretty.xml @@ -0,0 +1,8002 @@ + + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + + something blerm a bit down here + diff --git a/node_modules/stylus/node_modules/sax/examples/example.js b/node_modules/stylus/node_modules/sax/examples/example.js new file mode 100644 index 0000000..7b0246e --- /dev/null +++ b/node_modules/stylus/node_modules/sax/examples/example.js @@ -0,0 +1,29 @@ + +var fs = require("fs"), + util = require("util"), + path = require("path"), + xml = fs.readFileSync(path.join(__dirname, "test.xml"), "utf8"), + sax = require("../lib/sax"), + strict = sax.parser(true), + loose = sax.parser(false, {trim:true}), + inspector = function (ev) { return function (data) { + console.error("%s %s %j", this.line+":"+this.column, ev, data); + }}; + +sax.EVENTS.forEach(function (ev) { + loose["on"+ev] = inspector(ev); +}); +loose.onend = function () { + console.error("end"); + console.error(loose); +}; + +// do this in random bits at a time to verify that it works. +(function () { + if (xml) { + var c = Math.ceil(Math.random() * 1000) + loose.write(xml.substr(0,c)); + xml = xml.substr(c); + process.nextTick(arguments.callee); + } else loose.close(); +})(); diff --git a/node_modules/stylus/node_modules/sax/examples/get-products.js b/node_modules/stylus/node_modules/sax/examples/get-products.js new file mode 100644 index 0000000..9e8d74a --- /dev/null +++ b/node_modules/stylus/node_modules/sax/examples/get-products.js @@ -0,0 +1,58 @@ +// pull out /GeneralSearchResponse/categories/category/items/product tags +// the rest we don't care about. + +var sax = require("../lib/sax.js") +var fs = require("fs") +var path = require("path") +var xmlFile = path.resolve(__dirname, "shopping.xml") +var util = require("util") +var http = require("http") + +fs.readFile(xmlFile, function (er, d) { + http.createServer(function (req, res) { + if (er) throw er + var xmlstr = d.toString("utf8") + + var parser = sax.parser(true) + var products = [] + var product = null + var currentTag = null + + parser.onclosetag = function (tagName) { + if (tagName === "product") { + products.push(product) + currentTag = product = null + return + } + if (currentTag && currentTag.parent) { + var p = currentTag.parent + delete currentTag.parent + currentTag = p + } + } + + parser.onopentag = function (tag) { + if (tag.name !== "product" && !product) return + if (tag.name === "product") { + product = tag + } + tag.parent = currentTag + tag.children = [] + tag.parent && tag.parent.children.push(tag) + currentTag = tag + } + + parser.ontext = function (text) { + if (currentTag) currentTag.children.push(text) + } + + parser.onend = function () { + var out = util.inspect(products, false, 3, true) + res.writeHead(200, {"content-type":"application/json"}) + res.end("{\"ok\":true}") + // res.end(JSON.stringify(products)) + } + + parser.write(xmlstr).end() + }).listen(1337) +}) diff --git a/node_modules/stylus/node_modules/sax/examples/hello-world.js b/node_modules/stylus/node_modules/sax/examples/hello-world.js new file mode 100644 index 0000000..cbfa518 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/examples/hello-world.js @@ -0,0 +1,4 @@ +require("http").createServer(function (req, res) { + res.writeHead(200, {"content-type":"application/json"}) + res.end(JSON.stringify({ok: true})) +}).listen(1337) diff --git a/node_modules/stylus/node_modules/sax/examples/not-pretty.xml b/node_modules/stylus/node_modules/sax/examples/not-pretty.xml new file mode 100644 index 0000000..9592852 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/examples/not-pretty.xml @@ -0,0 +1,8 @@ + + something blerm a bit down here diff --git a/node_modules/stylus/node_modules/sax/examples/pretty-print.js b/node_modules/stylus/node_modules/sax/examples/pretty-print.js new file mode 100644 index 0000000..cd6aca9 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/examples/pretty-print.js @@ -0,0 +1,74 @@ +var sax = require("../lib/sax") + , printer = sax.createStream(false, {lowercasetags:true, trim:true}) + , fs = require("fs") + +function entity (str) { + return str.replace('"', '"') +} + +printer.tabstop = 2 +printer.level = 0 +printer.indent = function () { + print("\n") + for (var i = this.level; i > 0; i --) { + for (var j = this.tabstop; j > 0; j --) { + print(" ") + } + } +} +printer.on("opentag", function (tag) { + this.indent() + this.level ++ + print("<"+tag.name) + for (var i in tag.attributes) { + print(" "+i+"=\""+entity(tag.attributes[i])+"\"") + } + print(">") +}) + +printer.on("text", ontext) +printer.on("doctype", ontext) +function ontext (text) { + this.indent() + print(text) +} + +printer.on("closetag", function (tag) { + this.level -- + this.indent() + print("") +}) + +printer.on("cdata", function (data) { + this.indent() + print("") +}) + +printer.on("comment", function (comment) { + this.indent() + print("") +}) + +printer.on("error", function (error) { + console.error(error) + throw error +}) + +if (!process.argv[2]) { + throw new Error("Please provide an xml file to prettify\n"+ + "TODO: read from stdin or take a file") +} +var xmlfile = require("path").join(process.cwd(), process.argv[2]) +var fstr = fs.createReadStream(xmlfile, { encoding: "utf8" }) + +function print (c) { + if (!process.stdout.write(c)) { + fstr.pause() + } +} + +process.stdout.on("drain", function () { + fstr.resume() +}) + +fstr.pipe(printer) diff --git a/node_modules/stylus/node_modules/sax/examples/shopping.xml b/node_modules/stylus/node_modules/sax/examples/shopping.xml new file mode 100644 index 0000000..223c6c6 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/examples/shopping.xml @@ -0,0 +1,2 @@ + +sandbox3.1 r31.Kadu4DC.phase357782011.10.06 15:37:23 PSTp2.a121bc2aaf029435dce62011-10-21T18:38:45.982-04:00P0Y0M0DT0H0M0.169S1112You are currently using the SDC API sandbox environment! No clicks to merchant URLs from this response will be paid. Please change the host of your API requests to 'publisher.api.shopping.com' when you have finished development and testinghttp://statTest.dealtime.com/pixel/noscript?PV_EvnTyp=APPV&APPV_APITSP=10%2F21%2F11_06%3A38%3A45_PM&APPV_DSPRQSID=p2.a121bc2aaf029435dce6&APPV_IMGURL=http://img.shopping.com/sc/glb/sdc_logo_106x19.gif&APPV_LI_LNKINID=7000610&APPV_LI_SBMKYW=nikon&APPV_MTCTYP=1000&APPV_PRTID=2002&APPV_BrnID=14804http://www.shopping.com/digital-cameras/productsDigital CamerasDigital CamerasElectronicshttp://www.shopping.com/xCH-electronics-nikon~linkin_id-7000610?oq=nikonCameras and Photographyhttp://www.shopping.com/xCH-cameras_and_photography-nikon~linkin_id-7000610?oq=nikonDigital Camerashttp://www.shopping.com/digital-cameras/nikon/products?oq=nikon&linkin_id=7000610nikonnikonDigital Camerashttp://www.shopping.com/digital-cameras/nikon/products?oq=nikon&linkin_id=7000610Nikon D3100 Digital Camera14.2 Megapixel, SLR Camera, 3 in. LCD Screen, With High Definition Video, Weight: 1 lb.The Nikon D3100 digital SLR camera speaks to the growing ranks of enthusiastic D-SLR users and aspiring photographers by providing an easy-to-use and affordable entrance to the world of Nikon D-SLR’s. The 14.2-megapixel D3100 has powerful features, such as the enhanced Guide Mode that makes it easy to unleash creative potential and capture memories with still images and full HD video. Like having a personal photo tutor at your fingertips, this unique feature provides a simple graphical interface on the camera’s LCD that guides users by suggesting and/or adjusting camera settings to achieve the desired end result images. The D3100 is also the world’s first D-SLR to introduce full time auto focus (AF) in Live View and D-Movie mode to effortlessly achieve the critical focus needed when shooting Full HD 1080p video.http://di1.shopping.com/images/pi/93/bc/04/101677489-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=1http://di1.shopping.com/images/pi/93/bc/04/101677489-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=1http://di1.shopping.com/images/pi/93/bc/04/101677489-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=1http://di1.shopping.com/images/pi/93/bc/04/101677489-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=1http://di1.shopping.com/images/pi/93/bc/04/101677489-606x500-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=194.56http://img.shopping.com/sc/pr/sdc_stars_sm_4.5.gifhttp://www.shopping.com/Nikon-D3100/reviews~linkin_id-7000610429.001360.00http://www.shopping.com/Nikon-D3100/prices~linkin_id-7000610http://www.shopping.com/Nikon-D3100/info~linkin_id-7000610Nikon D3100 Digital SLR Camera with 18-55mm NIKKOR VR LensThe Nikon D3100 Digital SLR Camera is an affordable compact and lightweight photographic power-house. It features the all-purpose 18-55mm VR lens a high-resolution 14.2 MP CMOS sensor along with a feature set that's comprehensive yet easy to navigate - the intuitive onboard learn-as-you grow guide mode allows the photographer to understand what the 3100 can do quickly and easily. Capture beautiful pictures and amazing Full HD 1080p movies with sound and full-time autofocus. Availabilty: In Stock!7185Nikonhttp://di102.shopping.com/images/di/2d/5a/57/36424d5a717a366662532d61554c7767615f67-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di102.shopping.com/images/di/2d/5a/57/36424d5a717a366662532d61554c7767615f67-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di102.shopping.com/images/di/2d/5a/57/36424d5a717a366662532d61554c7767615f67-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di102.shopping.com/images/di/2d/5a/57/36424d5a717a366662532d61554c7767615f67-350x350-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1in-stockFree Shipping with Any Purchase!529.000.00799.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=647&BEFID=7185&aon=%5E1&MerchantID=475674&crawler_id=475674&dealId=-ZW6BMZqz6fbS-aULwga_g%3D%3D&url=http%3A%2F%2Fwww.fumfie.com%2Fproduct%2F343.5%2Fshopping-com%3F&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D3100+Digital+SLR+Camera+with+18-55mm+NIKKOR+VR+Lens&dlprc=529.0&crn=&istrsmrc=1&isathrsl=0&AR=1&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=101677489&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=1&cid=&semid1=&semid2=&IsLps=0&CC=1&SL=1&FS=1&code=&acode=658&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=FumFiehttp://img.shopping.com/cctool/merch_logos/475674.gif866 666 91985604.27http://img.shopping.com/sc/mr/sdc_checks_45.gifhttp://www.shopping.com/xMR-store_fumfie~MRD-475674~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUSF343C5Nikon Nikon D3100 14.2MP Digital SLR Camera with 18-55mm f/3.5-5.6 AF-S DX VR, CamerasNikon D3100 14.2MP Digital SLR Camera with 18-55mm f/3.5-5.6 AF-S DX VR7185Nikonhttp://di109.shopping.com/images/di/6d/64/31/65396c443876644f7534464851664a714b6e67-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di109.shopping.com/images/di/6d/64/31/65396c443876644f7534464851664a714b6e67-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di109.shopping.com/images/di/6d/64/31/65396c443876644f7534464851664a714b6e67-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di109.shopping.com/images/di/6d/64/31/65396c443876644f7534464851664a714b6e67-385x352-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2in-stock549.000.00549.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=779&BEFID=7185&aon=%5E1&MerchantID=305814&crawler_id=305814&dealId=md1e9lD8vdOu4FHQfJqKng%3D%3D&url=http%3A%2F%2Fwww.electronics-expo.com%2Findex.php%3Fpage%3Ditem%26id%3DNIKD3100%26source%3DSideCar%26scpid%3D8%26scid%3Dscsho318727%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+Nikon+D3100+14.2MP+Digital+SLR+Camera+with+18-55mm+f%2F3.5-5.6+AF-S+DX+VR%2C+Cameras&dlprc=549.0&crn=&istrsmrc=1&isathrsl=0&AR=9&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=101677489&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=9&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=771&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Electronics Expohttp://img.shopping.com/cctool/merch_logos/305814.gif1-888-707-EXPO3713.90http://img.shopping.com/sc/mr/sdc_checks_4.gifhttp://www.shopping.com/xMR-store_electronics_expo~MRD-305814~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUSNIKD3100Nikon D3100 14.2-Megapixel Digital SLR Camera With 18-55mm Zoom-Nikkor Lens, BlackSplit-second shutter response captures shots other cameras may have missed Helps eliminate the frustration of shutter delay! 14.2-megapixels for enlargements worth framing and hanging. Takes breathtaking 1080p HD movies. ISO sensitivity from 100-1600 for bright or dimly lit settings. 3.0in. color LCD for beautiful, wide-angle framing and viewing. In-camera image editing lets you retouch with no PC. Automatic scene modes include Child, Sports, Night Portrait and more. Accepts SDHC memory cards. Nikon D3100 14.2-Megapixel Digital SLR Camera With 18-55mm Zoom-Nikkor Lens, Black is one of many Digital SLR Cameras available through Office Depot. Made by Nikon.7185Nikonhttp://di109.shopping.com/images/di/79/59/75/61586e4446744359377244556a6b5932616177-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di109.shopping.com/images/di/79/59/75/61586e4446744359377244556a6b5932616177-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di109.shopping.com/images/di/79/59/75/61586e4446744359377244556a6b5932616177-250x250-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3in-stock549.990.00699.99http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=698&BEFID=7185&aon=%5E1&MerchantID=467671&crawler_id=467671&dealId=yYuaXnDFtCY7rDUjkY2aaw%3D%3D&url=http%3A%2F%2Flink.mercent.com%2Fredirect.ashx%3Fmr%3AmerchantID%3DOfficeDepot%26mr%3AtrackingCode%3DCEC9669E-6ABC-E011-9F24-0019B9C043EB%26mr%3AtargetUrl%3Dhttp%3A%2F%2Fwww.officedepot.com%2Fa%2Fproducts%2F486292%2FNikon-D3100-142-Megapixel-Digital-SLR%2F%253fcm_mmc%253dMercent-_-Shopping-_-Cameras_and_Camcorders-_-486292&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D3100+14.2-Megapixel+Digital+SLR+Camera+With+18-55mm+Zoom-Nikkor+Lens%2C+Black&dlprc=549.99&crn=&istrsmrc=1&isathrsl=0&AR=10&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=101677489&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=10&cid=&semid1=&semid2=&IsLps=0&CC=1&SL=1&FS=1&code=&acode=690&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Office Depothttp://img.shopping.com/cctool/merch_logos/467671.gif1-800-GO-DEPOT1352.37http://img.shopping.com/sc/mr/sdc_checks_25.gifhttp://www.shopping.com/xMR-store_office_depot_4158555~MRD-467671~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS486292Nikon® D3100™ 14.2MP Digital SLR with 18-55mm LensThe Nikon D3100 DSLR will surprise you with its simplicity and impress you with superb results.7185Nikonhttp://di103.shopping.com/images/di/52/6c/35/36553743756954597348344d475a30326c7851-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di103.shopping.com/images/di/52/6c/35/36553743756954597348344d475a30326c7851-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di103.shopping.com/images/di/52/6c/35/36553743756954597348344d475a30326c7851-220x220-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4in-stock549.996.05549.99http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=504&BEFID=7185&aon=%5E1&MerchantID=332477&crawler_id=332477&dealId=Rl56U7CuiTYsH4MGZ02lxQ%3D%3D&url=http%3A%2F%2Ftracking.searchmarketing.com%2Fgsic.asp%3Faid%3D903483107%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon%C2%AE+D3100%E2%84%A2+14.2MP+Digital+SLR+with+18-55mm+Lens&dlprc=549.99&crn=&istrsmrc=0&isathrsl=0&AR=11&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=101677489&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=11&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=0&code=&acode=496&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=RadioShackhttp://img.shopping.com/cctool/merch_logos/332477.gif242.25http://img.shopping.com/sc/mr/sdc_checks_25.gifhttp://www.shopping.com/xMR-store_radioshack_9689~MRD-332477~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS9614867Nikon D3100 SLR w/Nikon 18-55mm VR & 55-200mm VR Lenses14.2 Megapixels3" LCDLive ViewHD 1080p Video w/ Sound & Autofocus11-point Autofocus3 Frames per Second ShootingISO 100 to 3200 (Expand to 12800-Hi2)Self Cleaning SensorEXPEED 2, Image Processing EngineScene Recognition System7185Nikonhttp://di105.shopping.com/images/di/68/75/53/36785a4b444b614b4d544d5037316549364441-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di105.shopping.com/images/di/68/75/53/36785a4b444b614b4d544d5037316549364441-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di105.shopping.com/images/di/68/75/53/36785a4b444b614b4d544d5037316549364441-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di105.shopping.com/images/di/68/75/53/36785a4b444b614b4d544d5037316549364441-345x345-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5in-stock695.000.00695.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=371&BEFID=7185&aon=%5E1&MerchantID=487342&crawler_id=487342&dealId=huS6xZKDKaKMTMP71eI6DA%3D%3D&url=http%3A%2F%2Fwww.rythercamera.com%2Fcatalog%2Fproduct_info.php%3Fcsv%3Dsh%26products_id%3D32983%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D3100+SLR+w%2FNikon+18-55mm+VR+%26+55-200mm+VR+Lenses&dlprc=695.0&crn=&istrsmrc=0&isathrsl=0&AR=15&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=101677489&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=15&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=379&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=RytherCamera.comhttp://img.shopping.com/cctool/merch_logos/487342.gif1-877-644-75930http://img.shopping.com/sc/glb/flag/US.gifUS32983Nikon COOLPIX S203 Digital Camera10 Megapixel, Ultra-Compact Camera, 2.5 in. LCD Screen, 3x Optical Zoom, With Video Capability, Weight: 0.23 lb.With 10.34 mega pixel, electronic VR vibration reduction, 5-level brightness adjustment, 3x optical zoom, and TFT LCD, Nikon Coolpix s203 fulfills all the demands of any photographer. The digital camera has an inbuilt memory of 44MB and an external memory slot made for all kinds of SD (Secure Digital) cards.http://di1.shopping.com/images/pi/c4/ef/1b/95397883-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=2http://di1.shopping.com/images/pi/c4/ef/1b/95397883-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=2http://di1.shopping.com/images/pi/c4/ef/1b/95397883-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=2http://di1.shopping.com/images/pi/c4/ef/1b/95397883-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=2http://di1.shopping.com/images/pi/c4/ef/1b/95397883-500x499-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=20139.00139.00http://www.shopping.com/Nikon-Coolpix-S203/prices~linkin_id-7000610http://www.shopping.com/Nikon-Coolpix-S203/info~linkin_id-7000610Nikon Coolpix S203 Digital Camera (Red)With 10.34 mega pixel, electronic VR vibration reduction, 5-level brightness adjustment, 3x optical zoom, and TFT LCD, Nikon Coolpix s203 fulfills all the demands of any photographer. The digital camera has an inbuilt memory of 44MB and an external memory slot made for all kinds of SD (Secure Digital) cards.7185Nikonhttp://di108.shopping.com/images/di/73/42/64/324a6e4945504d2d415f6c42414d31525a6751-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di108.shopping.com/images/di/73/42/64/324a6e4945504d2d415f6c42414d31525a6751-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di108.shopping.com/images/di/73/42/64/324a6e4945504d2d415f6c42414d31525a6751-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di108.shopping.com/images/di/73/42/64/324a6e4945504d2d415f6c42414d31525a6751-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di108.shopping.com/images/di/73/42/64/324a6e4945504d2d415f6c42414d31525a6751-500x500-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1in-stockFantastic prices with ease & comfort of Amazon.com!139.009.50139.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=566&BEFID=7185&aon=%5E1&MerchantID=301531&crawler_id=1903313&dealId=sBd2JnIEPM-A_lBAM1RZgQ%3D%3D&url=http%3A%2F%2Fwww.amazon.com%2Fdp%2FB002T964IM%2Fref%3Dasc_df_B002T964IM1751618%3Fsmid%3DA22UHVNXG98FAT%26tag%3Ddealtime-ce-mp01feed-20%26linkCode%3Dasn%26creative%3D395105%26creativeASIN%3DB002T964IM&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+Coolpix+S203+Digital+Camera+%28Red%29&dlprc=139.0&crn=&istrsmrc=0&isathrsl=0&AR=63&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=95397883&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=63&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=0&code=&acode=518&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Amazon Marketplacehttp://img.shopping.com/cctool/merch_logos/301531.gif2132.73http://img.shopping.com/sc/mr/sdc_checks_25.gifhttp://www.shopping.com/xMR-store_amazon_marketplace_9689~MRD-301531~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUSB002T964IMNikon S3100 Digital Camera14.5 Megapixel, Compact Camera, 2.7 in. LCD Screen, 5x Optical Zoom, With High Definition Video, Weight: 0.23 lb.This digital camera features a wide-angle optical Zoom-NIKKOR glass lens that allows you to capture anything from landscapes to portraits to action shots. The high-definition movie mode with one-touch recording makes it easy to capture video clips.http://di1.shopping.com/images/pi/66/2d/33/106834268-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=3http://di1.shopping.com/images/pi/66/2d/33/106834268-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=3http://di1.shopping.com/images/pi/66/2d/33/106834268-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=3http://di1.shopping.com/images/pi/66/2d/33/106834268-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=3http://di1.shopping.com/images/pi/66/2d/33/106834268-507x387-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=312.00http://img.shopping.com/sc/pr/sdc_stars_sm_2.gifhttp://www.shopping.com/nikon-s3100/reviews~linkin_id-700061099.95134.95http://www.shopping.com/nikon-s3100/prices~linkin_id-7000610http://www.shopping.com/nikon-s3100/info~linkin_id-7000610CoolPix S3100 14 Megapixel Compact Digital Camera- RedNikon Coolpix S3100 - Digital camera - compact - 14.0 Mpix - optical zoom: 5 x - supported memory: SD, SDXC, SDHC - red7185Nikonhttp://di111.shopping.com/images/di/55/55/79/476f71563872302d78726b6e2d726e474e6267-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di111.shopping.com/images/di/55/55/79/476f71563872302d78726b6e2d726e474e6267-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di111.shopping.com/images/di/55/55/79/476f71563872302d78726b6e2d726e474e6267-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di111.shopping.com/images/di/55/55/79/476f71563872302d78726b6e2d726e474e6267-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1in-stockGet 30 days FREE SHIPPING w/ ShipVantage119.956.95139.95http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=578&BEFID=7185&aon=%5E1&MerchantID=485615&crawler_id=485615&dealId=UUyGoqV8r0-xrkn-rnGNbg%3D%3D&url=http%3A%2F%2Fsears.rdr.channelintelligence.com%2Fgo.asp%3FfVhzOGNRAAQIASNiE1NbQBJpFHJ3Yx0CTAICI2BbH1lEFmgKP3QvUVpEREdlfUAUHAQPLVpFTVdtJzxAHUNYW3AhQBM0QhFvEXAbYh8EAAVmDAJeU1oyGG0GcBdhGwUGCAVqYF9SO0xSN1sZdmA7dmMdBQAJB24qX1NbQxI6AjA2ME5dVFULPDsGPFcQTTdaLTA6SR0OFlQvPAwMDxYcYlxIVkcoLTcCDA%3D%3D%26nAID%3D13736960%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=CoolPix+S3100+14+Megapixel+Compact+Digital+Camera-+Red&dlprc=119.95&crn=&istrsmrc=1&isathrsl=0&AR=28&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=106834268&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=28&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=1&FS=0&code=&acode=583&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Searshttp://img.shopping.com/cctool/merch_logos/485615.gif1-800-349-43588882.85http://img.shopping.com/sc/mr/sdc_checks_3.gifhttp://www.shopping.com/xMR-store_sears_4189479~MRD-485615~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS00337013000COOLPIX S3100 PinkNikon Coolpix S3100 - Digital camera - compact - 14.0 Mpix - optical zoom: 5 x - supported memory: SD, SDXC, SDHC - pink7185Nikonhttp://di111.shopping.com/images/di/58/38/37/4177586c573164586f4d586b34515144546f51-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di111.shopping.com/images/di/58/38/37/4177586c573164586f4d586b34515144546f51-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di111.shopping.com/images/di/58/38/37/4177586c573164586f4d586b34515144546f51-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di111.shopping.com/images/di/58/38/37/4177586c573164586f4d586b34515144546f51-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2in-stockGet 30 days FREE SHIPPING w/ ShipVantage119.956.95139.95http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=578&BEFID=7185&aon=%5E1&MerchantID=485615&crawler_id=485615&dealId=X87AwXlW1dXoMXk4QQDToQ%3D%3D&url=http%3A%2F%2Fsears.rdr.channelintelligence.com%2Fgo.asp%3FfVhzOGNRAAQIASNiE1NbQBJpFHJxYx0CTAICI2BbH1lEFmgKP3QvUVpEREdlfUAUHAQPLVpFTVdtJzxAHUNYW3AhQBM0QhFvEXAbYh8EAAVmb2JcUFxDEGsPc3QDEkFZVQ0WFhdRW0MWbgYWDlxzdGMdAVQWRi0xDAwPFhw9TSobb05eWVVYKzsLTFVVQi5RICs3SA8MU1s2MQQKD1wf%26nAID%3D13736960%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=COOLPIX+S3100+Pink&dlprc=119.95&crn=&istrsmrc=1&isathrsl=0&AR=31&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=106834268&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=31&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=1&FS=0&code=&acode=583&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Searshttp://img.shopping.com/cctool/merch_logos/485615.gif1-800-349-43588882.85http://img.shopping.com/sc/mr/sdc_checks_3.gifhttp://www.shopping.com/xMR-store_sears_4189479~MRD-485615~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS00337015000Nikon Coolpix S3100 14.0 MP Digital Camera - SilverNikon Coolpix S3100 14.0 MP Digital Camera - Silver7185Nikonhttp://di109.shopping.com/images/di/6e/76/46/776e70664134726c413144626b736473613077-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di109.shopping.com/images/di/6e/76/46/776e70664134726c413144626b736473613077-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di109.shopping.com/images/di/6e/76/46/776e70664134726c413144626b736473613077-270x270-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3in-stock109.970.00109.97http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=803&BEFID=7185&aon=%5E&MerchantID=475774&crawler_id=475774&dealId=nvFwnpfA4rlA1Dbksdsa0w%3D%3D&url=http%3A%2F%2Fwww.thewiz.com%2Fcatalog%2Fproduct.jsp%3FmodelNo%3DS3100SILVER%26gdftrk%3DgdfV2677_a_7c996_a_7c4049_a_7c26262&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+Coolpix+S3100+14.0+MP+Digital+Camera+-+Silver&dlprc=109.97&crn=&istrsmrc=0&isathrsl=0&AR=33&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=106834268&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=33&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=797&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=TheWiz.comhttp://img.shopping.com/cctool/merch_logos/475774.gif877-542-69880http://img.shopping.com/sc/glb/flag/US.gifUS26262Nikon� COOLPIX� S3100 14MP Digital Camera (Silver)The Nikon COOLPIX S3100 is the easy way to share your life and stay connected.7185Nikonhttp://di102.shopping.com/images/di/35/47/74/614e324e6572794b7770732d5365326c2d3467-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di102.shopping.com/images/di/35/47/74/614e324e6572794b7770732d5365326c2d3467-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di102.shopping.com/images/di/35/47/74/614e324e6572794b7770732d5365326c2d3467-220x220-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4in-stock119.996.05119.99http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=504&BEFID=7185&aon=%5E1&MerchantID=332477&crawler_id=332477&dealId=5GtaN2NeryKwps-Se2l-4g%3D%3D&url=http%3A%2F%2Ftracking.searchmarketing.com%2Fgsic.asp%3Faid%3D848064082%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon%C3%AF%C2%BF%C2%BD+COOLPIX%C3%AF%C2%BF%C2%BD+S3100+14MP+Digital+Camera+%28Silver%29&dlprc=119.99&crn=&istrsmrc=0&isathrsl=0&AR=37&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=106834268&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=37&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=0&code=&acode=509&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=RadioShackhttp://img.shopping.com/cctool/merch_logos/332477.gif242.25http://img.shopping.com/sc/mr/sdc_checks_25.gifhttp://www.shopping.com/xMR-store_radioshack_9689~MRD-332477~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS10101095COOLPIX S3100 YellowNikon Coolpix S3100 - Digital camera - compact - 14.0 Mpix - optical zoom: 5 x - supported memory: SD, SDXC, SDHC - yellow7185Nikonhttp://di107.shopping.com/images/di/61/34/33/6d305258756c5833387a436e516a5535396a77-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di107.shopping.com/images/di/61/34/33/6d305258756c5833387a436e516a5535396a77-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di107.shopping.com/images/di/61/34/33/6d305258756c5833387a436e516a5535396a77-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di107.shopping.com/images/di/61/34/33/6d305258756c5833387a436e516a5535396a77-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5in-stockGet 30 days FREE SHIPPING w/ ShipVantage119.956.95139.95http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=578&BEFID=7185&aon=%5E1&MerchantID=485615&crawler_id=485615&dealId=a43m0RXulX38zCnQjU59jw%3D%3D&url=http%3A%2F%2Fsears.rdr.channelintelligence.com%2Fgo.asp%3FfVhzOGNRAAQIASNiE1NbQBJpFHJwYx0CTAICI2BbH1lEFmgKP3QvUVpEREdlfUAUHAQPLVpFTVdtJzxAHUNYW3AhQBM0QhFvEXAbYh8EAAVmb2JcUFxDEGoPc3QDEkFZVQ0WFhdRW0MWbgYWDlxzdGMdAVQWRi0xDAwPFhw9TSobb05eWVVYKzsLTFVVQi5RICs3SA8MU1s2MQQKD1wf%26nAID%3D13736960%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=COOLPIX+S3100+Yellow&dlprc=119.95&crn=&istrsmrc=1&isathrsl=0&AR=38&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=106834268&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=38&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=1&FS=0&code=&acode=583&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Searshttp://img.shopping.com/cctool/merch_logos/485615.gif1-800-349-43588882.85http://img.shopping.com/sc/mr/sdc_checks_3.gifhttp://www.shopping.com/xMR-store_sears_4189479~MRD-485615~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS00337014000Nikon D90 Digital Camera12.3 Megapixel, Point and Shoot Camera, 3 in. LCD Screen, With Video Capability, Weight: 1.36 lb.Untitled Document Nikon D90 SLR Digital Camera With 28-80mm 75-300mm Lens Kit The Nikon D90 SLR Digital Camera, with its 12.3-megapixel DX-format CMOS, 3" High resolution LCD display, Scene Recognition System, Picture Control, Active D-Lighting, and one-button Live View, provides photo enthusiasts with the image quality and performance they need to pursue their own vision while still being intuitive enough for use as an everyday camera.http://di1.shopping.com/images/pi/52/fb/d3/99671132-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=4http://di1.shopping.com/images/pi/52/fb/d3/99671132-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=4http://di1.shopping.com/images/pi/52/fb/d3/99671132-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=4http://di1.shopping.com/images/pi/52/fb/d3/99671132-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=4http://di1.shopping.com/images/pi/52/fb/d3/99671132-499x255-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=475.00http://img.shopping.com/sc/pr/sdc_stars_sm_5.gifhttp://www.shopping.com/Nikon-D90-with-18-270mm-Lens/reviews~linkin_id-7000610689.002299.00http://www.shopping.com/Nikon-D90-with-18-270mm-Lens/prices~linkin_id-7000610http://www.shopping.com/Nikon-D90-with-18-270mm-Lens/info~linkin_id-7000610Nikon® D90 12.3MP Digital SLR Camera (Body Only)The Nikon D90 will make you rethink what a digital SLR camera can achieve.7185Nikonhttp://di106.shopping.com/images/di/47/55/35/4a4a6b70554178653548756a4237666b774141-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di106.shopping.com/images/di/47/55/35/4a4a6b70554178653548756a4237666b774141-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di106.shopping.com/images/di/47/55/35/4a4a6b70554178653548756a4237666b774141-220x220-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1in-stock1015.996.051015.99http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=504&BEFID=7185&aon=%5E1&MerchantID=332477&crawler_id=332477&dealId=GU5JJkpUAxe5HujB7fkwAA%3D%3D&url=http%3A%2F%2Ftracking.searchmarketing.com%2Fgsic.asp%3Faid%3D851830266%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon%C2%AE+D90+12.3MP+Digital+SLR+Camera+%28Body+Only%29&dlprc=1015.99&crn=&istrsmrc=0&isathrsl=0&AR=14&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=99671132&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=14&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=0&code=&acode=496&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=RadioShackhttp://img.shopping.com/cctool/merch_logos/332477.gif242.25http://img.shopping.com/sc/mr/sdc_checks_25.gifhttp://www.shopping.com/xMR-store_radioshack_9689~MRD-332477~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS10148659Nikon D90 SLR Digital Camera (Camera Body)The Nikon D90 SLR Digital Camera with its 12.3-megapixel DX-format CCD 3" High resolution LCD display Scene Recognition System Picture Control Active D-Lighting and one-button Live View provides photo enthusiasts with the image quality and performance they need to pursue their own vision while still being intuitive enough for use as an everyday camera. In addition the D90 introduces the D-Movie mode allowing for the first time an interchangeable lens SLR camera that is capable of recording 720p HD movie clips. Availabilty: In Stock7185Nikonhttp://di109.shopping.com/images/di/58/68/55/527553432d73704262544944666f3471667a51-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di109.shopping.com/images/di/58/68/55/527553432d73704262544944666f3471667a51-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di109.shopping.com/images/di/58/68/55/527553432d73704262544944666f3471667a51-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di109.shopping.com/images/di/58/68/55/527553432d73704262544944666f3471667a51-350x350-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2in-stockFree Shipping with Any Purchase!689.000.00900.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=647&BEFID=7185&aon=%5E1&MerchantID=475674&crawler_id=475674&dealId=XhURuSC-spBbTIDfo4qfzQ%3D%3D&url=http%3A%2F%2Fwww.fumfie.com%2Fproduct%2F169.5%2Fshopping-com%3F&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D90+SLR+Digital+Camera+%28Camera+Body%29&dlprc=689.0&crn=&istrsmrc=1&isathrsl=0&AR=16&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=99671132&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=16&cid=&semid1=&semid2=&IsLps=0&CC=1&SL=1&FS=1&code=&acode=658&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=FumFiehttp://img.shopping.com/cctool/merch_logos/475674.gif866 666 91985604.27http://img.shopping.com/sc/mr/sdc_checks_45.gifhttp://www.shopping.com/xMR-store_fumfie~MRD-475674~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUSF169C5Nikon D90 SLR w/Nikon 18-105mm VR & 55-200mm VR Lenses12.3 MegapixelDX Format CMOS Sensor3" VGA LCD DisplayLive ViewSelf Cleaning SensorD-Movie ModeHigh Sensitivity (ISO 3200)4.5 fps BurstIn-Camera Image Editing7185Nikonhttp://di101.shopping.com/images/di/6f/30/50/785f584c5744627278415952793372436d7951-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di101.shopping.com/images/di/6f/30/50/785f584c5744627278415952793372436d7951-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di101.shopping.com/images/di/6f/30/50/785f584c5744627278415952793372436d7951-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di101.shopping.com/images/di/6f/30/50/785f584c5744627278415952793372436d7951-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di101.shopping.com/images/di/6f/30/50/785f584c5744627278415952793372436d7951-500x500-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3in-stock1189.000.001189.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=371&BEFID=7185&aon=%5E1&MerchantID=487342&crawler_id=487342&dealId=o0Px_XLWDbrxAYRy3rCmyQ%3D%3D&url=http%3A%2F%2Fwww.rythercamera.com%2Fcatalog%2Fproduct_info.php%3Fcsv%3Dsh%26products_id%3D30619%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D90+SLR+w%2FNikon+18-105mm+VR+%26+55-200mm+VR+Lenses&dlprc=1189.0&crn=&istrsmrc=0&isathrsl=0&AR=20&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=99671132&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=20&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=379&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=RytherCamera.comhttp://img.shopping.com/cctool/merch_logos/487342.gif1-877-644-75930http://img.shopping.com/sc/glb/flag/US.gifUS30619Nikon D90 12.3 Megapixel Digital SLR Camera (Body Only)Fusing 12.3 megapixel image quality and a cinematic 24fps D-Movie Mode, the Nikon D90 exceeds the demands of passionate photographers. Coupled with Nikon's EXPEED image processing technologies and NIKKOR optics, breathtaking image fidelity is assured. Combined with fast 0.15ms power-up and split-second 65ms shooting lag, dramatic action and decisive moments are captured easily. Effective 4-frequency, ultrasonic sensor cleaning frees image degrading dust particles from the sensor's optical low pass filter.7185Nikonhttp://di110.shopping.com/images/di/34/48/67/62574a534a3873736749663842304d58497741-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di110.shopping.com/images/di/34/48/67/62574a534a3873736749663842304d58497741-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di110.shopping.com/images/di/34/48/67/62574a534a3873736749663842304d58497741-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4in-stockFREE FEDEX 2-3 DAY DELIVERY899.950.00899.95http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=269&BEFID=7185&aon=%5E&MerchantID=9296&crawler_id=811558&dealId=4HgbWJSJ8ssgIf8B0MXIwA%3D%3D&url=http%3A%2F%2Fwww.pcnation.com%2Foptics-gallery%2Fdetails.asp%3Faffid%3D305%26item%3D2N145P&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D90+12.3+Megapixel+Digital+SLR+Camera+%28Body+Only%29&dlprc=899.95&crn=&istrsmrc=1&isathrsl=0&AR=21&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=99671132&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=21&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=257&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=PCNationhttp://img.shopping.com/cctool/merch_logos/9296.gif800-470-707916224.43http://img.shopping.com/sc/mr/sdc_checks_45.gifhttp://www.shopping.com/xMR-store_pcnation_9689~MRD-9296~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS2N145PNikon D90 12.3MP Digital SLR Camera (Body Only)Fusing 12.3-megapixel image quality inherited from the award-winning D300 with groundbreaking features, the D90's breathtaking, low-noise image quality is further advanced with EXPEED image processing. Split-second shutter response and continuous shooting at up to 4.5 frames-per-second provide the power to capture fast action and precise moments perfectly, while Nikon's exclusive Scene Recognition System contributes to faster 11-area autofocus performance, finer white balance detection and more. The D90 delivers the control passionate photographers demand, utilizing comprehensive exposure functions and the intelligence of 3D Color Matrix Metering II. Stunning results come to life on a 3-inch 920,000-dot color LCD monitor, providing accurate image review, Live View composition and brilliant playback of the D90's cinematic-quality 24-fps HD D-Movie mode.7185Nikonhttp://di102.shopping.com/images/di/55/4e/44/6133754d445a584f6e76445f377354494c5967-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di102.shopping.com/images/di/55/4e/44/6133754d445a584f6e76445f377354494c5967-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di102.shopping.com/images/di/55/4e/44/6133754d445a584f6e76445f377354494c5967-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di102.shopping.com/images/di/55/4e/44/6133754d445a584f6e76445f377354494c5967-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di102.shopping.com/images/di/55/4e/44/6133754d445a584f6e76445f377354494c5967-500x500-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5in-stockFantastic prices with ease & comfort of Amazon.com!780.000.00780.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=566&BEFID=7185&aon=%5E1&MerchantID=301531&crawler_id=1903313&dealId=UNDa3uMDZXOnvD_7sTILYg%3D%3D&url=http%3A%2F%2Fwww.amazon.com%2Fdp%2FB001ET5U92%2Fref%3Dasc_df_B001ET5U921751618%3Fsmid%3DAHF4SYKP09WBH%26tag%3Ddealtime-ce-mp01feed-20%26linkCode%3Dasn%26creative%3D395105%26creativeASIN%3DB001ET5U92&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D90+12.3MP+Digital+SLR+Camera+%28Body+Only%29&dlprc=780.0&crn=&istrsmrc=0&isathrsl=0&AR=29&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=99671132&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=29&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=520&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Amazon Marketplacehttp://img.shopping.com/cctool/merch_logos/301531.gif2132.73http://img.shopping.com/sc/mr/sdc_checks_25.gifhttp://www.shopping.com/xMR-store_amazon_marketplace_9689~MRD-301531~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUSB001ET5U92Nikon D90 Digital Camera with 18-105mm lens12.9 Megapixel, SLR Camera, 3 in. LCD Screen, 5.8x Optical Zoom, With Video Capability, Weight: 2.3 lb.Its 12.3 megapixel DX-format CMOS image sensor and EXPEED image processing system offer outstanding image quality across a wide ISO light sensitivity range. Live View mode lets you compose and shoot via the high-resolution 3-inch LCD monitor, and an advanced Scene Recognition System and autofocus performance help capture images with astounding accuracy. Movies can be shot in Motion JPEG format using the D-Movie function. The camera’s large image sensor ensures exceptional movie image quality and you can create dramatic effects by shooting with a wide range of interchangeable NIKKOR lenses, from wide-angle to macro to fisheye, or by adjusting the lens aperture and experimenting with depth-of-field. The D90 – designed to fuel your passion for photography.http://di1.shopping.com/images/pi/57/6a/4f/70621646-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=5http://di1.shopping.com/images/pi/57/6a/4f/70621646-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=5http://di1.shopping.com/images/pi/57/6a/4f/70621646-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=5http://di1.shopping.com/images/pi/57/6a/4f/70621646-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=5http://di1.shopping.com/images/pi/57/6a/4f/70621646-490x489-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=2&c=1&l=7000610&t=111021183845&r=5324.81http://img.shopping.com/sc/pr/sdc_stars_sm_5.gifhttp://www.shopping.com/Nikon-D90-with-18-105mm-lens/reviews~linkin_id-7000610849.951599.95http://www.shopping.com/Nikon-D90-with-18-105mm-lens/prices~linkin_id-7000610http://www.shopping.com/Nikon-D90-with-18-105mm-lens/info~linkin_id-7000610Nikon D90 18-105mm VR LensThe Nikon D90 SLR Digital Camera with its 12.3-megapixel DX-format CMOS 3" High resolution LCD display Scene Recognition System Picture Control Active D-Lighting and one-button Live View prov7185Nikonhttp://di111.shopping.com/images/di/33/6f/35/6531566768674a5066684c7654314a464b5441-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di111.shopping.com/images/di/33/6f/35/6531566768674a5066684c7654314a464b5441-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1http://di111.shopping.com/images/di/33/6f/35/6531566768674a5066684c7654314a464b5441-260x260-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=1in-stock849.950.00849.95http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=419&BEFID=7185&aon=%5E1&MerchantID=9390&crawler_id=1905054&dealId=3o5e1VghgJPfhLvT1JFKTA%3D%3D&url=http%3A%2F%2Fwww.ajrichard.com%2FNikon-D90-18-105mm-VR-Lens%2Fp-292%3Frefid%3DShopping%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D90+18-105mm+VR+Lens&dlprc=849.95&crn=&istrsmrc=0&isathrsl=0&AR=2&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=70621646&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=2&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=425&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=AJRichardhttp://img.shopping.com/cctool/merch_logos/9390.gif1-888-871-125631244.48http://img.shopping.com/sc/mr/sdc_checks_45.gifhttp://www.shopping.com/xMR-store_ajrichard~MRD-9390~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS292Nikon D90 SLR w/Nikon 18-105mm VR Lens12.3 MegapixelDX Format CMOS Sensor3" VGA LCD DisplayLive ViewSelf Cleaning SensorD-Movie ModeHigh Sensitivity (ISO 3200)4.5 fps BurstIn-Camera Image Editing7185Nikonhttp://di108.shopping.com/images/di/5f/6c/59/576a5f6a62776673536b666377556344757777-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di108.shopping.com/images/di/5f/6c/59/576a5f6a62776673536b666377556344757777-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di108.shopping.com/images/di/5f/6c/59/576a5f6a62776673536b666377556344757777-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di108.shopping.com/images/di/5f/6c/59/576a5f6a62776673536b666377556344757777-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2http://di108.shopping.com/images/di/5f/6c/59/576a5f6a62776673536b666377556344757777-500x500-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=2in-stock909.000.00909.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=371&BEFID=7185&aon=%5E1&MerchantID=487342&crawler_id=487342&dealId=_lYWj_jbwfsSkfcwUcDuww%3D%3D&url=http%3A%2F%2Fwww.rythercamera.com%2Fcatalog%2Fproduct_info.php%3Fcsv%3Dsh%26products_id%3D30971%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D90+SLR+w%2FNikon+18-105mm+VR+Lens&dlprc=909.0&crn=&istrsmrc=0&isathrsl=0&AR=3&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=70621646&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=3&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=1&code=&acode=379&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=RytherCamera.comhttp://img.shopping.com/cctool/merch_logos/487342.gif1-877-644-75930http://img.shopping.com/sc/glb/flag/US.gifUS3097125448/D90 12.3 Megapixel Digital Camera 18-105mm Zoom Lens w/ 3" Screen - BlackNikon D90 - Digital camera - SLR - 12.3 Mpix - Nikon AF-S DX 18-105mm lens - optical zoom: 5.8 x - supported memory: SD, SDHC7185Nikonhttp://di110.shopping.com/images/di/31/4b/43/636c4347755776747932584b5539736b616467-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di110.shopping.com/images/di/31/4b/43/636c4347755776747932584b5539736b616467-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di110.shopping.com/images/di/31/4b/43/636c4347755776747932584b5539736b616467-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3http://di110.shopping.com/images/di/31/4b/43/636c4347755776747932584b5539736b616467-400x400-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=3in-stockGet 30 days FREE SHIPPING w/ ShipVantage1199.008.201199.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=578&BEFID=7185&aon=%5E1&MerchantID=485615&crawler_id=485615&dealId=1KCclCGuWvty2XKU9skadg%3D%3D&url=http%3A%2F%2Fsears.rdr.channelintelligence.com%2Fgo.asp%3FfVhzOGNRAAQIASNiE1NbQBRtFXpzYx0CTAICI2BbH1lEFmgKP3QvUVpEREdlfUAUHAQPLVpFTVdtJzxAHUNYW3AhQBM0QhFvEXAbYh8EAAVmb2JcVlhCGGkPc3QDEkFZVQ0WFhdRW0MWbgYWDlxzdGMdAVQWRi0xDAwPFhw9TSobb05eWVVYKzsLTFVVQi5RICs3SA8MU1s2MQQKD1wf%26nAID%3D13736960%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=25448%2FD90+12.3+Megapixel+Digital+Camera+18-105mm+Zoom+Lens+w%2F+3%22+Screen+-+Black&dlprc=1199.0&crn=&istrsmrc=1&isathrsl=0&AR=4&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=70621646&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=4&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=0&code=&acode=586&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=Searshttp://img.shopping.com/cctool/merch_logos/485615.gif1-800-349-43588882.85http://img.shopping.com/sc/mr/sdc_checks_3.gifhttp://www.shopping.com/xMR-store_sears_4189479~MRD-485615~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS00353197000Nikon® D90 12.3MP Digital SLR with 18-105mm LensThe Nikon D90 will make you rethink what a digital SLR camera can achieve.7185Nikonhttp://di101.shopping.com/images/di/33/2d/56/4f53665656354a6f37486c41346b4a74616e41-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di101.shopping.com/images/di/33/2d/56/4f53665656354a6f37486c41346b4a74616e41-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4http://di101.shopping.com/images/di/33/2d/56/4f53665656354a6f37486c41346b4a74616e41-220x220-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=4in-stock1350.996.051350.99http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=504&BEFID=7185&aon=%5E1&MerchantID=332477&crawler_id=332477&dealId=3-VOSfVV5Jo7HlA4kJtanA%3D%3D&url=http%3A%2F%2Ftracking.searchmarketing.com%2Fgsic.asp%3Faid%3D982673361%26&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon%C2%AE+D90+12.3MP+Digital+SLR+with+18-105mm+Lens&dlprc=1350.99&crn=&istrsmrc=0&isathrsl=0&AR=5&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=70621646&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=5&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=0&FS=0&code=&acode=496&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=RadioShackhttp://img.shopping.com/cctool/merch_logos/332477.gif242.25http://img.shopping.com/sc/mr/sdc_checks_25.gifhttp://www.shopping.com/xMR-store_radioshack_9689~MRD-332477~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS11148905Nikon D90 Kit 12.3-megapixel Digital SLR with 18-105mm VR LensPhotographers, take your passion further!Now is the time for new creativity, and to rethink what a digital SLR camera can achieve. It's time for the D90, a camera with everything you would expect from Nikon's next-generation D-SLRs, and some unexpected surprises, as well. The stunning image quality is inherited from the D300, Nikon's DX-format flagship. The D90 also has Nikon's unmatched ergonomics and high performance, and now takes high-quality movies with beautifully cinematic results. The world of photography has changed, and with the D90 in your hands, it's time to make your own rules.AF-S DX NIKKOR 18-105mm f/3.5-5.6G ED VR LensWide-ratio 5.8x zoom Compact, versatile and ideal for a broad range of shooting situations, ranging from interiors and landscapes to beautiful portraits� a perfect everyday zoom. Nikon VR (Vibration Reduction) image stabilization Vibration Reduction is engineered specifically for each VR NIKKOR lens and enables handheld shooting at up to 3 shutter speeds slower than would7185Nikonhttp://di110.shopping.com/images/di/6b/51/6e/4236725334416a4e3564783568325f36333167-100x100-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di110.shopping.com/images/di/6b/51/6e/4236725334416a4e3564783568325f36333167-200x200-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di110.shopping.com/images/di/6b/51/6e/4236725334416a4e3564783568325f36333167-300x300-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://img.shopping.com/sc/ds/no_image_100X100.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5http://di110.shopping.com/images/di/6b/51/6e/4236725334416a4e3564783568325f36333167-300x232-0-0.jpg?p=p2.a121bc2aaf029435dce6&a=1&c=1&l=7000610&t=111021183845&r=5in-stockShipping Included!1050.000.001199.00http://statTest.dealtime.com/DealFrame/DealFrame.cmp?bm=135&BEFID=7185&aon=%5E1&MerchantID=313162&crawler_id=313162&dealId=kQnB6rS4AjN5dx5h2_631g%3D%3D&url=http%3A%2F%2Fonecall.rdr.channelintelligence.com%2Fgo.asp%3FfVhzOGNRAAQIASNiE1pZSxNoWHFwLx8GTAICa2ZeH1sPXTZLNzRpAh1HR0BxPQEGCBJNMhFHUElsFCFCVkVTTHAcBggEHQ4aHXNpGERGH3RQODsbAgdechJtbBt8fx8JAwhtZFAzJj1oGgIWCxRlNyFOUV9UUGIxBgo0T0IyTSYqJ0RWHw4QPCIBAAQXRGMDICg6TllZVBhh%26nAID%3D13736960&linkin_id=7000610&Issdt=111021183845&searchID=p2.a121bc2aaf029435dce6&DealName=Nikon+D90+Kit+12.3-megapixel+Digital+SLR+with+18-105mm+VR+Lens&dlprc=1050.0&crn=&istrsmrc=1&isathrsl=0&AR=6&NG=20&NDP=200&PN=1&ST=7&DB=sdcprod&MT=phx-pkadudc2&FPT=DSP&NDS=&NMS=&MRS=&PD=70621646&brnId=14804&IsFtr=0&IsSmart=0&DMT=&op=&CM=&DlLng=1&RR=6&cid=&semid1=&semid2=&IsLps=0&CC=0&SL=1&FS=1&code=&acode=143&category=&HasLink=&frameId=&ND=&MN=&PT=&prjID=&GR=&lnkId=&VK=OneCallhttp://img.shopping.com/cctool/merch_logos/313162.gif1.800.398.07661804.44http://img.shopping.com/sc/mr/sdc_checks_45.gifhttp://www.shopping.com/xMR-store_onecall_9689~MRD-313162~S-1~linkin_id-7000610http://img.shopping.com/sc/glb/flag/US.gifUS92826Price rangehttp://www.shopping.com/digital-cameras/nikon/products?oq=nikon&linkin_id=7000610$24 - $4012http://www.shopping.com/digital-cameras/nikon/products?minPrice=24&maxPrice=4012&linkin_id=7000610$4012 - $7999http://www.shopping.com/digital-cameras/nikon/products?minPrice=4012&maxPrice=7999&linkin_id=7000610Brandhttp://www.shopping.com/digital-cameras/nikon/products~all-9688-brand~MS-1?oq=nikon&linkin_id=7000610Nikonhttp://www.shopping.com/digital-cameras/nikon+brand-nikon/products~linkin_id-7000610Cranehttp://www.shopping.com/digital-cameras/nikon+9688-brand-crane/products~linkin_id-7000610Ikelitehttp://www.shopping.com/digital-cameras/nikon+ikelite/products~linkin_id-7000610Bowerhttp://www.shopping.com/digital-cameras/nikon+bower/products~linkin_id-7000610FUJIFILMhttp://www.shopping.com/digital-cameras/nikon+brand-fuji/products~linkin_id-7000610Storehttp://www.shopping.com/digital-cameras/nikon/products~all-store~MS-1?oq=nikon&linkin_id=7000610Amazon Marketplacehttp://www.shopping.com/digital-cameras/nikon+store-amazon-marketplace-9689/products~linkin_id-7000610Amazonhttp://www.shopping.com/digital-cameras/nikon+store-amazon/products~linkin_id-7000610Adoramahttp://www.shopping.com/digital-cameras/nikon+store-adorama/products~linkin_id-7000610J&R Music and Computer Worldhttp://www.shopping.com/digital-cameras/nikon+store-j-r-music-and-computer-world/products~linkin_id-7000610RytherCamera.comhttp://www.shopping.com/digital-cameras/nikon+store-rythercamera-com/products~linkin_id-7000610Resolutionhttp://www.shopping.com/digital-cameras/nikon/products~all-21885-resolution~MS-1?oq=nikon&linkin_id=7000610Under 4 Megapixelhttp://www.shopping.com/digital-cameras/nikon+under-4-megapixel/products~linkin_id-7000610At least 5 Megapixelhttp://www.shopping.com/digital-cameras/nikon+5-megapixel-digital-cameras/products~linkin_id-7000610At least 6 Megapixelhttp://www.shopping.com/digital-cameras/nikon+6-megapixel-digital-cameras/products~linkin_id-7000610At least 7 Megapixelhttp://www.shopping.com/digital-cameras/nikon+7-megapixel-digital-cameras/products~linkin_id-7000610At least 8 Megapixelhttp://www.shopping.com/digital-cameras/nikon+8-megapixel-digital-cameras/products~linkin_id-7000610Featureshttp://www.shopping.com/digital-cameras/nikon/products~all-32804-features~MS-1?oq=nikon&linkin_id=7000610Shockproofhttp://www.shopping.com/digital-cameras/nikon+32804-features-shockproof/products~linkin_id-7000610Waterproofhttp://www.shopping.com/digital-cameras/nikon+32804-features-waterproof/products~linkin_id-7000610Freezeproofhttp://www.shopping.com/digital-cameras/nikon+32804-features-freezeproof/products~linkin_id-7000610Dust proofhttp://www.shopping.com/digital-cameras/nikon+32804-features-dust-proof/products~linkin_id-7000610Image Stabilizationhttp://www.shopping.com/digital-cameras/nikon+32804-features-image-stabilization/products~linkin_id-7000610hybriddigital camerag1sonycameracanonnikonkodak digital camerakodaksony cybershotkodak easyshare digital cameranikon coolpixolympuspink digital cameracanon powershot \ No newline at end of file diff --git a/node_modules/stylus/node_modules/sax/examples/strict.dtd b/node_modules/stylus/node_modules/sax/examples/strict.dtd new file mode 100644 index 0000000..b274559 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/examples/strict.dtd @@ -0,0 +1,870 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +%HTMLlat1; + + +%HTMLsymbol; + + +%HTMLspecial; + + + + + + + + + + + + + +]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/node_modules/stylus/node_modules/sax/examples/test.html b/node_modules/stylus/node_modules/sax/examples/test.html new file mode 100644 index 0000000..61f8f1a --- /dev/null +++ b/node_modules/stylus/node_modules/sax/examples/test.html @@ -0,0 +1,15 @@ + + + + + testing the parser + + + +

    hello + + + + diff --git a/node_modules/stylus/node_modules/sax/examples/test.xml b/node_modules/stylus/node_modules/sax/examples/test.xml new file mode 100644 index 0000000..801292d --- /dev/null +++ b/node_modules/stylus/node_modules/sax/examples/test.xml @@ -0,0 +1,1254 @@ + + +]> + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + + Some Text + + + + + + + are ok in here. ]]> + + Pre-Text & Inlined text Post-text. +  + + \ No newline at end of file diff --git a/node_modules/stylus/node_modules/sax/lib/sax.js b/node_modules/stylus/node_modules/sax/lib/sax.js new file mode 100644 index 0000000..77e20ae --- /dev/null +++ b/node_modules/stylus/node_modules/sax/lib/sax.js @@ -0,0 +1,1329 @@ +// wrapper for non-node envs +;(function (sax) { + +sax.parser = function (strict, opt) { return new SAXParser(strict, opt) } +sax.SAXParser = SAXParser +sax.SAXStream = SAXStream +sax.createStream = createStream + +// When we pass the MAX_BUFFER_LENGTH position, start checking for buffer overruns. +// When we check, schedule the next check for MAX_BUFFER_LENGTH - (max(buffer lengths)), +// since that's the earliest that a buffer overrun could occur. This way, checks are +// as rare as required, but as often as necessary to ensure never crossing this bound. +// Furthermore, buffers are only tested at most once per write(), so passing a very +// large string into write() might have undesirable effects, but this is manageable by +// the caller, so it is assumed to be safe. Thus, a call to write() may, in the extreme +// edge case, result in creating at most one complete copy of the string passed in. +// Set to Infinity to have unlimited buffers. +sax.MAX_BUFFER_LENGTH = 64 * 1024 + +var buffers = [ + "comment", "sgmlDecl", "textNode", "tagName", "doctype", + "procInstName", "procInstBody", "entity", "attribName", + "attribValue", "cdata", "script" +] + +sax.EVENTS = // for discoverability. + [ "text" + , "processinginstruction" + , "sgmldeclaration" + , "doctype" + , "comment" + , "attribute" + , "opentag" + , "closetag" + , "opencdata" + , "cdata" + , "closecdata" + , "error" + , "end" + , "ready" + , "script" + , "opennamespace" + , "closenamespace" + ] + +function SAXParser (strict, opt) { + if (!(this instanceof SAXParser)) return new SAXParser(strict, opt) + + var parser = this + clearBuffers(parser) + parser.q = parser.c = "" + parser.bufferCheckPosition = sax.MAX_BUFFER_LENGTH + parser.opt = opt || {} + parser.opt.lowercase = parser.opt.lowercase || parser.opt.lowercasetags + parser.looseCase = parser.opt.lowercase ? "toLowerCase" : "toUpperCase" + parser.tags = [] + parser.closed = parser.closedRoot = parser.sawRoot = false + parser.tag = parser.error = null + parser.strict = !!strict + parser.noscript = !!(strict || parser.opt.noscript) + parser.state = S.BEGIN + parser.ENTITIES = Object.create(sax.ENTITIES) + parser.attribList = [] + + // namespaces form a prototype chain. + // it always points at the current tag, + // which protos to its parent tag. + if (parser.opt.xmlns) parser.ns = Object.create(rootNS) + + // mostly just for error reporting + parser.trackPosition = parser.opt.position !== false + if (parser.trackPosition) { + parser.position = parser.line = parser.column = 0 + } + emit(parser, "onready") +} + +if (!Object.create) Object.create = function (o) { + function f () { this.__proto__ = o } + f.prototype = o + return new f +} + +if (!Object.getPrototypeOf) Object.getPrototypeOf = function (o) { + return o.__proto__ +} + +if (!Object.keys) Object.keys = function (o) { + var a = [] + for (var i in o) if (o.hasOwnProperty(i)) a.push(i) + return a +} + +function checkBufferLength (parser) { + var maxAllowed = Math.max(sax.MAX_BUFFER_LENGTH, 10) + , maxActual = 0 + for (var i = 0, l = buffers.length; i < l; i ++) { + var len = parser[buffers[i]].length + if (len > maxAllowed) { + // Text/cdata nodes can get big, and since they're buffered, + // we can get here under normal conditions. + // Avoid issues by emitting the text node now, + // so at least it won't get any bigger. + switch (buffers[i]) { + case "textNode": + closeText(parser) + break + + case "cdata": + emitNode(parser, "oncdata", parser.cdata) + parser.cdata = "" + break + + case "script": + emitNode(parser, "onscript", parser.script) + parser.script = "" + break + + default: + error(parser, "Max buffer length exceeded: "+buffers[i]) + } + } + maxActual = Math.max(maxActual, len) + } + // schedule the next check for the earliest possible buffer overrun. + parser.bufferCheckPosition = (sax.MAX_BUFFER_LENGTH - maxActual) + + parser.position +} + +function clearBuffers (parser) { + for (var i = 0, l = buffers.length; i < l; i ++) { + parser[buffers[i]] = "" + } +} + +SAXParser.prototype = + { end: function () { end(this) } + , write: write + , resume: function () { this.error = null; return this } + , close: function () { return this.write(null) } + } + +try { + var Stream = require("stream").Stream +} catch (ex) { + var Stream = function () {} +} + + +var streamWraps = sax.EVENTS.filter(function (ev) { + return ev !== "error" && ev !== "end" +}) + +function createStream (strict, opt) { + return new SAXStream(strict, opt) +} + +function SAXStream (strict, opt) { + if (!(this instanceof SAXStream)) return new SAXStream(strict, opt) + + Stream.apply(this) + + this._parser = new SAXParser(strict, opt) + this.writable = true + this.readable = true + + + var me = this + + this._parser.onend = function () { + me.emit("end") + } + + this._parser.onerror = function (er) { + me.emit("error", er) + + // if didn't throw, then means error was handled. + // go ahead and clear error, so we can write again. + me._parser.error = null + } + + this._decoder = null; + + streamWraps.forEach(function (ev) { + Object.defineProperty(me, "on" + ev, { + get: function () { return me._parser["on" + ev] }, + set: function (h) { + if (!h) { + me.removeAllListeners(ev) + return me._parser["on"+ev] = h + } + me.on(ev, h) + }, + enumerable: true, + configurable: false + }) + }) +} + +SAXStream.prototype = Object.create(Stream.prototype, + { constructor: { value: SAXStream } }) + +SAXStream.prototype.write = function (data) { + if (typeof Buffer === 'function' && + typeof Buffer.isBuffer === 'function' && + Buffer.isBuffer(data)) { + if (!this._decoder) { + var SD = require('string_decoder').StringDecoder + this._decoder = new SD('utf8') + } + data = this._decoder.write(data); + } + + this._parser.write(data.toString()) + this.emit("data", data) + return true +} + +SAXStream.prototype.end = function (chunk) { + if (chunk && chunk.length) this.write(chunk) + else if (this.leftovers) this._parser.write(this.leftovers.toString()) + this._parser.end() + return true +} + +SAXStream.prototype.on = function (ev, handler) { + var me = this + if (!me._parser["on"+ev] && streamWraps.indexOf(ev) !== -1) { + me._parser["on"+ev] = function () { + var args = arguments.length === 1 ? [arguments[0]] + : Array.apply(null, arguments) + args.splice(0, 0, ev) + me.emit.apply(me, args) + } + } + + return Stream.prototype.on.call(me, ev, handler) +} + + + +// character classes and tokens +var whitespace = "\r\n\t " + // this really needs to be replaced with character classes. + // XML allows all manner of ridiculous numbers and digits. + , number = "0124356789" + , letter = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + // (Letter | "_" | ":") + , quote = "'\"" + , entity = number+letter+"#" + , attribEnd = whitespace + ">" + , CDATA = "[CDATA[" + , DOCTYPE = "DOCTYPE" + , XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace" + , XMLNS_NAMESPACE = "http://www.w3.org/2000/xmlns/" + , rootNS = { xml: XML_NAMESPACE, xmlns: XMLNS_NAMESPACE } + +// turn all the string character sets into character class objects. +whitespace = charClass(whitespace) +number = charClass(number) +letter = charClass(letter) + +// http://www.w3.org/TR/REC-xml/#NT-NameStartChar +// This implementation works on strings, a single character at a time +// as such, it cannot ever support astral-plane characters (10000-EFFFF) +// without a significant breaking change to either this parser, or the +// JavaScript language. Implementation of an emoji-capable xml parser +// is left as an exercise for the reader. +var nameStart = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/ + +var nameBody = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040\.\d-]/ + +quote = charClass(quote) +entity = charClass(entity) +attribEnd = charClass(attribEnd) + +function charClass (str) { + return str.split("").reduce(function (s, c) { + s[c] = true + return s + }, {}) +} + +function isRegExp (c) { + return Object.prototype.toString.call(c) === '[object RegExp]' +} + +function is (charclass, c) { + return isRegExp(charclass) ? !!c.match(charclass) : charclass[c] +} + +function not (charclass, c) { + return !is(charclass, c) +} + +var S = 0 +sax.STATE = +{ BEGIN : S++ +, TEXT : S++ // general stuff +, TEXT_ENTITY : S++ // & and such. +, OPEN_WAKA : S++ // < +, SGML_DECL : S++ // +, SCRIPT : S++ // " + , expect : + [ [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ] + , [ "opentag", { name: "script", attributes: {}, isSelfClosing: false } ] + , [ "text", "hello world" ] + , [ "closetag", "script" ] + , [ "closetag", "xml" ] + ] + , strict : false + , opt : { lowercasetags: true, noscript: true } + } + ) + +require(__dirname).test + ( { xml : "" + , expect : + [ [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ] + , [ "opentag", { name: "script", attributes: {}, isSelfClosing: false } ] + , [ "opencdata", undefined ] + , [ "cdata", "hello world" ] + , [ "closecdata", undefined ] + , [ "closetag", "script" ] + , [ "closetag", "xml" ] + ] + , strict : false + , opt : { lowercasetags: true, noscript: true } + } + ) + diff --git a/node_modules/stylus/node_modules/sax/test/issue-84.js b/node_modules/stylus/node_modules/sax/test/issue-84.js new file mode 100644 index 0000000..0e7ee69 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/issue-84.js @@ -0,0 +1,13 @@ +// https://github.com/isaacs/sax-js/issues/49 +require(__dirname).test + ( { xml : "body" + , expect : + [ [ "processinginstruction", { name: "has", body: "unbalanced \"quotes" } ], + [ "opentag", { name: "xml", attributes: {}, isSelfClosing: false } ] + , [ "text", "body" ] + , [ "closetag", "xml" ] + ] + , strict : false + , opt : { lowercasetags: true, noscript: true } + } + ) diff --git a/node_modules/stylus/node_modules/sax/test/parser-position.js b/node_modules/stylus/node_modules/sax/test/parser-position.js new file mode 100644 index 0000000..e4a68b1 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/parser-position.js @@ -0,0 +1,28 @@ +var sax = require("../lib/sax"), + assert = require("assert") + +function testPosition(chunks, expectedEvents) { + var parser = sax.parser(); + expectedEvents.forEach(function(expectation) { + parser['on' + expectation[0]] = function() { + for (var prop in expectation[1]) { + assert.equal(parser[prop], expectation[1][prop]); + } + } + }); + chunks.forEach(function(chunk) { + parser.write(chunk); + }); +}; + +testPosition(['

    abcdefgh
    '], + [ ['opentag', { position: 5, startTagPosition: 1 }] + , ['text', { position: 19, startTagPosition: 14 }] + , ['closetag', { position: 19, startTagPosition: 14 }] + ]); + +testPosition(['
    abcde','fgh
    '], + [ ['opentag', { position: 5, startTagPosition: 1 }] + , ['text', { position: 19, startTagPosition: 14 }] + , ['closetag', { position: 19, startTagPosition: 14 }] + ]); diff --git a/node_modules/stylus/node_modules/sax/test/script-close-better.js b/node_modules/stylus/node_modules/sax/test/script-close-better.js new file mode 100644 index 0000000..f4887b9 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/script-close-better.js @@ -0,0 +1,12 @@ +require(__dirname).test({ + xml : "", + expect : [ + ["opentag", {"name": "HTML","attributes": {}, isSelfClosing: false}], + ["opentag", {"name": "HEAD","attributes": {}, isSelfClosing: false}], + ["opentag", {"name": "SCRIPT","attributes": {}, isSelfClosing: false}], + ["script", "'
    foo
    ", + expect : [ + ["opentag", {"name": "HTML","attributes": {}, "isSelfClosing": false}], + ["opentag", {"name": "HEAD","attributes": {}, "isSelfClosing": false}], + ["opentag", {"name": "SCRIPT","attributes": {}, "isSelfClosing": false}], + ["script", "if (1 < 0) { console.log('elo there'); }"], + ["closetag", "SCRIPT"], + ["closetag", "HEAD"], + ["closetag", "HTML"] + ] +}); diff --git a/node_modules/stylus/node_modules/sax/test/self-closing-child-strict.js b/node_modules/stylus/node_modules/sax/test/self-closing-child-strict.js new file mode 100644 index 0000000..3d6e985 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/self-closing-child-strict.js @@ -0,0 +1,44 @@ + +require(__dirname).test({ + xml : + ""+ + "" + + "" + + "" + + "" + + "=(|)" + + "" + + "", + expect : [ + ["opentag", { + "name": "root", + "attributes": {}, + "isSelfClosing": false + }], + ["opentag", { + "name": "child", + "attributes": {}, + "isSelfClosing": false + }], + ["opentag", { + "name": "haha", + "attributes": {}, + "isSelfClosing": true + }], + ["closetag", "haha"], + ["closetag", "child"], + ["opentag", { + "name": "monkey", + "attributes": {}, + "isSelfClosing": false + }], + ["text", "=(|)"], + ["closetag", "monkey"], + ["closetag", "root"], + ["end"], + ["ready"] + ], + strict : true, + opt : {} +}); + diff --git a/node_modules/stylus/node_modules/sax/test/self-closing-child.js b/node_modules/stylus/node_modules/sax/test/self-closing-child.js new file mode 100644 index 0000000..f31c366 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/self-closing-child.js @@ -0,0 +1,44 @@ + +require(__dirname).test({ + xml : + ""+ + "" + + "" + + "" + + "" + + "=(|)" + + "" + + "", + expect : [ + ["opentag", { + "name": "ROOT", + "attributes": {}, + "isSelfClosing": false + }], + ["opentag", { + "name": "CHILD", + "attributes": {}, + "isSelfClosing": false + }], + ["opentag", { + "name": "HAHA", + "attributes": {}, + "isSelfClosing": true + }], + ["closetag", "HAHA"], + ["closetag", "CHILD"], + ["opentag", { + "name": "MONKEY", + "attributes": {}, + "isSelfClosing": false + }], + ["text", "=(|)"], + ["closetag", "MONKEY"], + ["closetag", "ROOT"], + ["end"], + ["ready"] + ], + strict : false, + opt : {} +}); + diff --git a/node_modules/stylus/node_modules/sax/test/self-closing-tag.js b/node_modules/stylus/node_modules/sax/test/self-closing-tag.js new file mode 100644 index 0000000..d1d8b7c --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/self-closing-tag.js @@ -0,0 +1,25 @@ + +require(__dirname).test({ + xml : + " "+ + " "+ + " "+ + " "+ + "=(|) "+ + ""+ + " ", + expect : [ + ["opentag", {name:"ROOT", attributes:{}, isSelfClosing: false}], + ["opentag", {name:"HAHA", attributes:{}, isSelfClosing: true}], + ["closetag", "HAHA"], + ["opentag", {name:"HAHA", attributes:{}, isSelfClosing: true}], + ["closetag", "HAHA"], + // ["opentag", {name:"HAHA", attributes:{}}], + // ["closetag", "HAHA"], + ["opentag", {name:"MONKEY", attributes:{}, isSelfClosing: false}], + ["text", "=(|)"], + ["closetag", "MONKEY"], + ["closetag", "ROOT"] + ], + opt : { trim : true } +}); \ No newline at end of file diff --git a/node_modules/stylus/node_modules/sax/test/stray-ending.js b/node_modules/stylus/node_modules/sax/test/stray-ending.js new file mode 100644 index 0000000..bec467b --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/stray-ending.js @@ -0,0 +1,17 @@ +// stray ending tags should just be ignored in non-strict mode. +// https://github.com/isaacs/sax-js/issues/32 +require(__dirname).test + ( { xml : + "" + , expect : + [ [ "opentag", { name: "A", attributes: {}, isSelfClosing: false } ] + , [ "opentag", { name: "B", attributes: {}, isSelfClosing: false } ] + , [ "text", "" ] + , [ "closetag", "B" ] + , [ "closetag", "A" ] + ] + , strict : false + , opt : {} + } + ) + diff --git a/node_modules/stylus/node_modules/sax/test/trailing-attribute-no-value.js b/node_modules/stylus/node_modules/sax/test/trailing-attribute-no-value.js new file mode 100644 index 0000000..222837f --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/trailing-attribute-no-value.js @@ -0,0 +1,10 @@ + +require(__dirname).test({ + xml : + "", + expect : [ + ["attribute", {name:"ATTRIB", value:"attrib"}], + ["opentag", {name:"ROOT", attributes:{"ATTRIB":"attrib"}, isSelfClosing: false}] + ], + opt : { trim : true } +}); diff --git a/node_modules/stylus/node_modules/sax/test/trailing-non-whitespace.js b/node_modules/stylus/node_modules/sax/test/trailing-non-whitespace.js new file mode 100644 index 0000000..619578b --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/trailing-non-whitespace.js @@ -0,0 +1,18 @@ + +require(__dirname).test({ + xml : "Welcome, to monkey land", + expect : [ + ["opentag", { + "name": "SPAN", + "attributes": {}, + isSelfClosing: false + }], + ["text", "Welcome,"], + ["closetag", "SPAN"], + ["text", " to monkey land"], + ["end"], + ["ready"] + ], + strict : false, + opt : {} +}); diff --git a/node_modules/stylus/node_modules/sax/test/unclosed-root.js b/node_modules/stylus/node_modules/sax/test/unclosed-root.js new file mode 100644 index 0000000..f4eeac6 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/unclosed-root.js @@ -0,0 +1,11 @@ +require(__dirname).test + ( { xml : "" + + , expect : + [ [ "opentag", { name: "root", attributes: {}, isSelfClosing: false } ] + , [ "error", "Unclosed root tag\nLine: 0\nColumn: 6\nChar: " ] + ] + , strict : true + , opt : {} + } + ) diff --git a/node_modules/stylus/node_modules/sax/test/unquoted.js b/node_modules/stylus/node_modules/sax/test/unquoted.js new file mode 100644 index 0000000..b3a9a81 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/unquoted.js @@ -0,0 +1,18 @@ +// unquoted attributes should be ok in non-strict mode +// https://github.com/isaacs/sax-js/issues/31 +require(__dirname).test + ( { xml : + "" + , expect : + [ [ "attribute", { name: "CLASS", value: "test" } ] + , [ "attribute", { name: "HELLO", value: "world" } ] + , [ "opentag", { name: "SPAN", + attributes: { CLASS: "test", HELLO: "world" }, + isSelfClosing: false } ] + , [ "closetag", "SPAN" ] + ] + , strict : false + , opt : {} + } + ) + diff --git a/node_modules/stylus/node_modules/sax/test/utf8-split.js b/node_modules/stylus/node_modules/sax/test/utf8-split.js new file mode 100644 index 0000000..e22bc10 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/utf8-split.js @@ -0,0 +1,32 @@ +var assert = require('assert') +var saxStream = require('../lib/sax').createStream() + +var b = new Buffer('误') + +saxStream.on('text', function(text) { + assert.equal(text, b.toString()) +}) + +saxStream.write(new Buffer('')) +saxStream.write(b.slice(0, 1)) +saxStream.write(b.slice(1)) +saxStream.write(new Buffer('')) +saxStream.write(b.slice(0, 2)) +saxStream.write(b.slice(2)) +saxStream.write(new Buffer('')) +saxStream.write(b) +saxStream.write(new Buffer('')) +saxStream.write(Buffer.concat([new Buffer(''), b.slice(0, 1)])) +saxStream.end(Buffer.concat([b.slice(1), new Buffer('')])) + +var saxStream2 = require('../lib/sax').createStream() + +saxStream2.on('text', function(text) { + assert.equal(text, '�') +}); + +saxStream2.write(new Buffer('')); +saxStream2.write(new Buffer([0xC0])); +saxStream2.write(new Buffer('')); +saxStream2.write(Buffer.concat([new Buffer(''), b.slice(0,1)])); +saxStream2.end(); diff --git a/node_modules/stylus/node_modules/sax/test/xmlns-issue-41.js b/node_modules/stylus/node_modules/sax/test/xmlns-issue-41.js new file mode 100644 index 0000000..17ab45a --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/xmlns-issue-41.js @@ -0,0 +1,68 @@ +var t = require(__dirname) + + , xmls = // should be the same both ways. + [ "" + , "" ] + + , ex1 = + [ [ "opennamespace" + , { prefix: "a" + , uri: "http://ATTRIBUTE" + } + ] + , [ "attribute" + , { name: "xmlns:a" + , value: "http://ATTRIBUTE" + , prefix: "xmlns" + , local: "a" + , uri: "http://www.w3.org/2000/xmlns/" + } + ] + , [ "attribute" + , { name: "a:attr" + , local: "attr" + , prefix: "a" + , uri: "http://ATTRIBUTE" + , value: "value" + } + ] + , [ "opentag" + , { name: "parent" + , uri: "" + , prefix: "" + , local: "parent" + , attributes: + { "a:attr": + { name: "a:attr" + , local: "attr" + , prefix: "a" + , uri: "http://ATTRIBUTE" + , value: "value" + } + , "xmlns:a": + { name: "xmlns:a" + , local: "a" + , prefix: "xmlns" + , uri: "http://www.w3.org/2000/xmlns/" + , value: "http://ATTRIBUTE" + } + } + , ns: {"a": "http://ATTRIBUTE"} + , isSelfClosing: true + } + ] + , ["closetag", "parent"] + , ["closenamespace", { prefix: "a", uri: "http://ATTRIBUTE" }] + ] + + // swap the order of elements 2 and 1 + , ex2 = [ex1[0], ex1[2], ex1[1]].concat(ex1.slice(3)) + , expected = [ex1, ex2] + +xmls.forEach(function (x, i) { + t.test({ xml: x + , expect: expected[i] + , strict: true + , opt: { xmlns: true } + }) +}) diff --git a/node_modules/stylus/node_modules/sax/test/xmlns-rebinding.js b/node_modules/stylus/node_modules/sax/test/xmlns-rebinding.js new file mode 100644 index 0000000..07e0425 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/xmlns-rebinding.js @@ -0,0 +1,63 @@ + +require(__dirname).test + ( { xml : + ""+ + ""+ + ""+ + ""+ + ""+ + "" + + , expect : + [ [ "opennamespace", { prefix: "x", uri: "x1" } ] + , [ "opennamespace", { prefix: "y", uri: "y1" } ] + , [ "attribute", { name: "xmlns:x", value: "x1", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "x" } ] + , [ "attribute", { name: "xmlns:y", value: "y1", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "y" } ] + , [ "attribute", { name: "x:a", value: "x1", uri: "x1", prefix: "x", local: "a" } ] + , [ "attribute", { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } ] + , [ "opentag", { name: "root", uri: "", prefix: "", local: "root", + attributes: { "xmlns:x": { name: "xmlns:x", value: "x1", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "x" } + , "xmlns:y": { name: "xmlns:y", value: "y1", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "y" } + , "x:a": { name: "x:a", value: "x1", uri: "x1", prefix: "x", local: "a" } + , "y:a": { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } }, + ns: { x: 'x1', y: 'y1' }, + isSelfClosing: false } ] + + , [ "opennamespace", { prefix: "x", uri: "x2" } ] + , [ "attribute", { name: "xmlns:x", value: "x2", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "x" } ] + , [ "opentag", { name: "rebind", uri: "", prefix: "", local: "rebind", + attributes: { "xmlns:x": { name: "xmlns:x", value: "x2", uri: "http://www.w3.org/2000/xmlns/", prefix: "xmlns", local: "x" } }, + ns: { x: 'x2' }, + isSelfClosing: false } ] + + , [ "attribute", { name: "x:a", value: "x2", uri: "x2", prefix: "x", local: "a" } ] + , [ "attribute", { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } ] + , [ "opentag", { name: "check", uri: "", prefix: "", local: "check", + attributes: { "x:a": { name: "x:a", value: "x2", uri: "x2", prefix: "x", local: "a" } + , "y:a": { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } }, + ns: { x: 'x2' }, + isSelfClosing: true } ] + + , [ "closetag", "check" ] + + , [ "closetag", "rebind" ] + , [ "closenamespace", { prefix: "x", uri: "x2" } ] + + , [ "attribute", { name: "x:a", value: "x1", uri: "x1", prefix: "x", local: "a" } ] + , [ "attribute", { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } ] + , [ "opentag", { name: "check", uri: "", prefix: "", local: "check", + attributes: { "x:a": { name: "x:a", value: "x1", uri: "x1", prefix: "x", local: "a" } + , "y:a": { name: "y:a", value: "y1", uri: "y1", prefix: "y", local: "a" } }, + ns: { x: 'x1', y: 'y1' }, + isSelfClosing: true } ] + , [ "closetag", "check" ] + + , [ "closetag", "root" ] + , [ "closenamespace", { prefix: "x", uri: "x1" } ] + , [ "closenamespace", { prefix: "y", uri: "y1" } ] + ] + , strict : true + , opt : { xmlns: true } + } + ) + diff --git a/node_modules/stylus/node_modules/sax/test/xmlns-strict.js b/node_modules/stylus/node_modules/sax/test/xmlns-strict.js new file mode 100644 index 0000000..b5e3e51 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/xmlns-strict.js @@ -0,0 +1,74 @@ + +require(__dirname).test + ( { xml : + ""+ + ""+ + ""+ + ""+ + ""+ + ""+ + ""+ + ""+ + ""+ + "" + + , expect : + [ [ "opentag", { name: "root", prefix: "", local: "root", uri: "", + attributes: {}, ns: {}, isSelfClosing: false } ] + + , [ "attribute", { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } ] + , [ "opentag", { name: "plain", prefix: "", local: "plain", uri: "", + attributes: { "attr": { name: "attr", value: "normal", uri: "", prefix: "", local: "attr", uri: "" } }, + ns: {}, isSelfClosing: true } ] + , [ "closetag", "plain" ] + + , [ "opennamespace", { prefix: "", uri: "uri:default" } ] + + , [ "attribute", { name: "xmlns", value: "uri:default", prefix: "xmlns", local: "", uri: "http://www.w3.org/2000/xmlns/" } ] + , [ "opentag", { name: "ns1", prefix: "", local: "ns1", uri: "uri:default", + attributes: { "xmlns": { name: "xmlns", value: "uri:default", prefix: "xmlns", local: "", uri: "http://www.w3.org/2000/xmlns/" } }, + ns: { "": "uri:default" }, isSelfClosing: false } ] + + , [ "attribute", { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } ] + , [ "opentag", { name: "plain", prefix: "", local: "plain", uri: "uri:default", ns: { '': 'uri:default' }, + attributes: { "attr": { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } }, + isSelfClosing: true } ] + , [ "closetag", "plain" ] + + , [ "closetag", "ns1" ] + + , [ "closenamespace", { prefix: "", uri: "uri:default" } ] + + , [ "opennamespace", { prefix: "a", uri: "uri:nsa" } ] + + , [ "attribute", { name: "xmlns:a", value: "uri:nsa", prefix: "xmlns", local: "a", uri: "http://www.w3.org/2000/xmlns/" } ] + + , [ "opentag", { name: "ns2", prefix: "", local: "ns2", uri: "", + attributes: { "xmlns:a": { name: "xmlns:a", value: "uri:nsa", prefix: "xmlns", local: "a", uri: "http://www.w3.org/2000/xmlns/" } }, + ns: { a: "uri:nsa" }, isSelfClosing: false } ] + + , [ "attribute", { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } ] + , [ "opentag", { name: "plain", prefix: "", local: "plain", uri: "", + attributes: { "attr": { name: "attr", value: "normal", prefix: "", local: "attr", uri: "" } }, + ns: { a: 'uri:nsa' }, + isSelfClosing: true } ] + , [ "closetag", "plain" ] + + , [ "attribute", { name: "a:attr", value: "namespaced", prefix: "a", local: "attr", uri: "uri:nsa" } ] + , [ "opentag", { name: "a:ns", prefix: "a", local: "ns", uri: "uri:nsa", + attributes: { "a:attr": { name: "a:attr", value: "namespaced", prefix: "a", local: "attr", uri: "uri:nsa" } }, + ns: { a: 'uri:nsa' }, + isSelfClosing: true } ] + , [ "closetag", "a:ns" ] + + , [ "closetag", "ns2" ] + + , [ "closenamespace", { prefix: "a", uri: "uri:nsa" } ] + + , [ "closetag", "root" ] + ] + , strict : true + , opt : { xmlns: true } + } + ) + diff --git a/node_modules/stylus/node_modules/sax/test/xmlns-unbound-element.js b/node_modules/stylus/node_modules/sax/test/xmlns-unbound-element.js new file mode 100644 index 0000000..9d031a2 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/xmlns-unbound-element.js @@ -0,0 +1,33 @@ +require(__dirname).test( + { strict : true + , opt : { xmlns: true } + , expect : + [ [ "error", "Unbound namespace prefix: \"unbound:root\"\nLine: 0\nColumn: 15\nChar: >"] + , [ "opentag", { name: "unbound:root", uri: "unbound", prefix: "unbound", local: "root" + , attributes: {}, ns: {}, isSelfClosing: true } ] + , [ "closetag", "unbound:root" ] + ] + } +).write(""); + +require(__dirname).test( + { strict : true + , opt : { xmlns: true } + , expect : + [ [ "opennamespace", { prefix: "unbound", uri: "someuri" } ] + , [ "attribute", { name: 'xmlns:unbound', value: 'someuri' + , prefix: 'xmlns', local: 'unbound' + , uri: 'http://www.w3.org/2000/xmlns/' } ] + , [ "opentag", { name: "unbound:root", uri: "someuri", prefix: "unbound", local: "root" + , attributes: { 'xmlns:unbound': { + name: 'xmlns:unbound' + , value: 'someuri' + , prefix: 'xmlns' + , local: 'unbound' + , uri: 'http://www.w3.org/2000/xmlns/' } } + , ns: { "unbound": "someuri" }, isSelfClosing: true } ] + , [ "closetag", "unbound:root" ] + , [ "closenamespace", { prefix: 'unbound', uri: 'someuri' }] + ] + } +).write(""); diff --git a/node_modules/stylus/node_modules/sax/test/xmlns-unbound.js b/node_modules/stylus/node_modules/sax/test/xmlns-unbound.js new file mode 100644 index 0000000..b740e26 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/xmlns-unbound.js @@ -0,0 +1,15 @@ + +require(__dirname).test( + { strict : true + , opt : { xmlns: true } + , expect : + [ ["error", "Unbound namespace prefix: \"unbound\"\nLine: 0\nColumn: 28\nChar: >"] + + , [ "attribute", { name: "unbound:attr", value: "value", uri: "unbound", prefix: "unbound", local: "attr" } ] + , [ "opentag", { name: "root", uri: "", prefix: "", local: "root", + attributes: { "unbound:attr": { name: "unbound:attr", value: "value", uri: "unbound", prefix: "unbound", local: "attr" } }, + ns: {}, isSelfClosing: true } ] + , [ "closetag", "root" ] + ] + } +).write("") diff --git a/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-ns.js b/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-ns.js new file mode 100644 index 0000000..b1984d2 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-ns.js @@ -0,0 +1,31 @@ +var xmlns_attr = +{ + name: "xmlns", value: "http://foo", prefix: "xmlns", + local: "", uri : "http://www.w3.org/2000/xmlns/" +}; + +var attr_attr = +{ + name: "attr", value: "bar", prefix: "", + local : "attr", uri : "" +}; + + +require(__dirname).test + ( { xml : + "" + , expect : + [ [ "opennamespace", { prefix: "", uri: "http://foo" } ] + , [ "attribute", xmlns_attr ] + , [ "attribute", attr_attr ] + , [ "opentag", { name: "elm", prefix: "", local: "elm", uri : "http://foo", + ns : { "" : "http://foo" }, + attributes: { xmlns: xmlns_attr, attr: attr_attr }, + isSelfClosing: true } ] + , [ "closetag", "elm" ] + , [ "closenamespace", { prefix: "", uri: "http://foo"} ] + ] + , strict : true + , opt : {xmlns: true} + } + ) diff --git a/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-prefix-attribute.js b/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-prefix-attribute.js new file mode 100644 index 0000000..e41f218 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-prefix-attribute.js @@ -0,0 +1,36 @@ +require(__dirname).test( + { xml : "" + , expect : + [ [ "attribute" + , { name: "xml:lang" + , local: "lang" + , prefix: "xml" + , uri: "http://www.w3.org/XML/1998/namespace" + , value: "en" + } + ] + , [ "opentag" + , { name: "root" + , uri: "" + , prefix: "" + , local: "root" + , attributes: + { "xml:lang": + { name: "xml:lang" + , local: "lang" + , prefix: "xml" + , uri: "http://www.w3.org/XML/1998/namespace" + , value: "en" + } + } + , ns: {} + , isSelfClosing: true + } + ] + , ["closetag", "root"] + ] + , strict : true + , opt : { xmlns: true } + } +) + diff --git a/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-prefix.js b/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-prefix.js new file mode 100644 index 0000000..a85b478 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-prefix.js @@ -0,0 +1,21 @@ +require(__dirname).test( + { xml : "" + , expect : + [ + [ "opentag" + , { name: "xml:root" + , uri: "http://www.w3.org/XML/1998/namespace" + , prefix: "xml" + , local: "root" + , attributes: {} + , ns: {} + , isSelfClosing: true + } + ] + , ["closetag", "xml:root"] + ] + , strict : true + , opt : { xmlns: true } + } +) + diff --git a/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-redefine.js b/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-redefine.js new file mode 100644 index 0000000..d35d5a0 --- /dev/null +++ b/node_modules/stylus/node_modules/sax/test/xmlns-xml-default-redefine.js @@ -0,0 +1,41 @@ +require(__dirname).test( + { xml : "" + , expect : + [ ["error" + , "xml: prefix must be bound to http://www.w3.org/XML/1998/namespace\n" + + "Actual: ERROR\n" + + "Line: 0\nColumn: 27\nChar: '" + ] + , [ "attribute" + , { name: "xmlns:xml" + , local: "xml" + , prefix: "xmlns" + , uri: "http://www.w3.org/2000/xmlns/" + , value: "ERROR" + } + ] + , [ "opentag" + , { name: "xml:root" + , uri: "http://www.w3.org/XML/1998/namespace" + , prefix: "xml" + , local: "root" + , attributes: + { "xmlns:xml": + { name: "xmlns:xml" + , local: "xml" + , prefix: "xmlns" + , uri: "http://www.w3.org/2000/xmlns/" + , value: "ERROR" + } + } + , ns: {} + , isSelfClosing: true + } + ] + , ["closetag", "xml:root"] + ] + , strict : true + , opt : { xmlns: true } + } +) + diff --git a/node_modules/stylus/package.json b/node_modules/stylus/package.json new file mode 100644 index 0000000..09626dc --- /dev/null +++ b/node_modules/stylus/package.json @@ -0,0 +1,54 @@ +{ + "name": "stylus", + "description": "Robust, expressive, and feature-rich CSS superset", + "version": "0.40.0", + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "keywords": [ + "css", + "parser", + "style", + "stylesheets", + "jade", + "language" + ], + "repository": { + "type": "git", + "url": "git://github.com/LearnBoost/stylus" + }, + "main": "./index.js", + "browserify": "./lib/browserify.js", + "engines": { + "node": "*" + }, + "bin": { + "stylus": "./bin/stylus" + }, + "scripts": { + "prepublish": "npm prune", + "test": "make test" + }, + "dependencies": { + "cssom": "0.2.x", + "mkdirp": "0.3.x", + "debug": "*", + "sax": "0.5.x" + }, + "devDependencies": { + "should": "*", + "mocha": "*" + }, + "readme": "# Stylus [![Build Status](https://travis-ci.org/LearnBoost/stylus.png?branch=master)](https://travis-ci.org/LearnBoost/stylus)\n\n Stylus is a revolutionary new language, providing an efficient, dynamic, and expressive way to generate CSS. Supporting both an indented syntax and regular CSS style.\n\n## Installation\n\n```bash\n$ npm install stylus\n```\n\n### Example\n\n```\nborder-radius()\n -webkit-border-radius: arguments\n -moz-border-radius: arguments\n border-radius: arguments\n\nbody a\n font: 12px/1.4 \"Lucida Grande\", Arial, sans-serif\n background: black\n color: #ccc\n\nform input\n padding: 5px\n border: 1px solid\n border-radius: 5px\n```\n\ncompiles to:\n\n```css\nbody a {\n font: 12px/1.4 \"Lucida Grande\", Arial, sans-serif;\n background: #000;\n color: #ccc;\n}\nform input {\n padding: 5px;\n border: 1px solid;\n -webkit-border-radius: 5px;\n -moz-border-radius: 5px;\n border-radius: 5px;\n}\n```\n\nthe following is equivalent to the indented version of Stylus source, using the CSS syntax instead:\n\n```\nborder-radius() {\n -webkit-border-radius: arguments\n -moz-border-radius: arguments\n border-radius: arguments\n}\n\nbody a {\n font: 12px/1.4 \"Lucida Grande\", Arial, sans-serif;\n background: black;\n color: #ccc;\n}\n\nform input {\n padding: 5px;\n border: 1px solid;\n border-radius: 5px;\n}\n```\n\n### Features\n\n Stylus has _many_ features. Detailed documentation links follow:\n\n - [css syntax](docs/css-style.md) support\n - [mixins](docs/mixins.md)\n - [keyword arguments](docs/kwargs.md)\n - [variables](docs/variables.md)\n - [interpolation](docs/interpolation.md)\n - arithmetic, logical, and equality [operators](docs/operators.md)\n - [importing](docs/import.md) of other stylus sheets\n - [introspection api](docs/introspection.md)\n - type coercion\n - [@extend](docs/extend.md)\n - [conditionals](docs/conditionals.md)\n - [iteration](docs/iteration.md)\n - nested [selectors](docs/selectors.md)\n - parent reference\n - in-language [functions](docs/functions.md)\n - [variable arguments](docs/vargs.md)\n - built-in [functions](docs/bifs.md) (over 25)\n - optional [image inlining](docs/functions.url.md)\n - optional compression\n - JavaScript [API](docs/js.md)\n - extremely terse syntax\n - stylus [executable](docs/executable.md)\n - [error reporting](docs/error-reporting.md)\n - single-line and multi-line [comments](docs/comments.md)\n - css [literal](docs/literal.md)\n - character [escaping](docs/escape.md)\n - [@keyframes](docs/keyframes.md) support & expansion\n - [@font-face](docs/font-face.md) support\n - [@media](docs/media.md) support\n - Connect [Middleware](docs/middleware.md)\n - TextMate [bundle](docs/textmate.md)\n - Coda/SubEtha Edit [Syntax mode](https://github.com/atljeremy/Stylus.mode)\n - gedit [language-spec](docs/gedit.md)\n - VIM [Syntax](https://github.com/wavded/vim-stylus)\n - [Firebug extension](docs/firebug.md)\n - heroku [web service](http://styl.heroku.com) for compiling stylus\n - [style guide](https://github.com/lepture/ganam) parser and generator\n - transparent vendor-specific function expansion\n\n### Community modules\n\n - https://github.com/LearnBoost/stylus/wiki\n\n### Framework Support\n\n - [Connect](docs/middleware.md)\n - [Play! 2.0](https://github.com/patiencelabs/play-stylus)\n - [Ruby On Rails](https://github.com/lucasmazza/ruby-stylus)\n\n### CMS Support\n\n - [DocPad](https://github.com/bevry/docpad)\n - [Punch](https://github.com/laktek/punch-stylus-compiler)\n\n### Screencasts\n\n - [Stylus Intro](http://screenr.com/bNY)\n - [CSS Syntax & Postfix Conditionals](http://screenr.com/A8v)\n\n### Authors\n\n - [TJ Holowaychuk (visionmedia)](http://github.com/visionmedia)\n\n### More Information\n\n - Language [comparisons](docs/compare.md)\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2010 LearnBoost <dev@learnboost.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/LearnBoost/stylus/issues" + }, + "_id": "stylus@0.40.0", + "dist": { + "shasum": "dddcee8d222f21c55d3d07d2e514162179be74cb" + }, + "_from": "stylus@0.40.x", + "_resolved": "https://registry.npmjs.org/stylus/-/stylus-0.40.0.tgz" +} diff --git a/node_modules/useragent/.npmignore b/node_modules/useragent/.npmignore new file mode 100644 index 0000000..ad02c13 --- /dev/null +++ b/node_modules/useragent/.npmignore @@ -0,0 +1,3 @@ +tests +benchmark +node_modules diff --git a/node_modules/useragent/.travis.yml b/node_modules/useragent/.travis.yml new file mode 100644 index 0000000..6875969 --- /dev/null +++ b/node_modules/useragent/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.7 + - 0.8 diff --git a/node_modules/useragent/CHANGELOG.md b/node_modules/useragent/CHANGELOG.md new file mode 100644 index 0000000..9262b3c --- /dev/null +++ b/node_modules/useragent/CHANGELOG.md @@ -0,0 +1,63 @@ +## Version 2.0 +* __v2.0.0__ *breaking* + - Added support for Operating System version parsing + - Added support for Device parsing + - Introduced deferred OnDemand parsing for Operating and Devices + - The `Agent#toJSON` method now returns an object instread of JSON string. Use + `JSON.stringify(agent)` instead. + - Removed the fromAgent method + - semver is removed from the dependencies, if you use the useragent/features + you should add it to your own dependencies. + +* __v2.0.1__ + - Fixed broken reference to the update module. + - Updated with some new parsers. + +* __v2.0.2__ + - Use LRU-cache for the lookups so it doesn't create a memory "leak" #22 + - Updated with some new parsers. + +* __v2.0.3__ + - Updated regexp library with new parsers as Opera's latest browser which runs + WebKit was detected as Chrome Mobile. + +* __v2.0.4__ + - Added support for IE11 and PhantomJS. In addition to that when you run the + updater without the correct dependencies it will just output an error + instead of throwing an error. + +* __v2.0.5__ + - Upgraded the regular expressions to support Opera Next + +* __v2.0.6__ + - Only write the parse file when there isn't an error. #30 + - Output an error in the console when we fail to compile new parsers #30 + +## Version 1.0 +* __v1.1.0__ + - Removed the postupdate hook, it was causing to much issues #9 + +* __v1.0.6__ + - Updated the agent parser, JHint issues and leaking globals. + +* __v1.0.5__ + - Potential fix for #11 where it doesn't install the stuff in windows this also + brings a fresh update of the agents.js. + +* __v1.0.3__ + - Rewritten the `is` method so it doesn't display IE as true for firefox, chrome + etc fixes #10 and #7. + +* __v1.0.3__ + - A fix for bug #6, updated the semver dependency for browserify support. + +* __v1.0.2__ + - Don't throw errors when .parse is called without a useragent string. It now + defaults to a empty Agent instance. + +* __v1.0.1__ + - Added support for cURL, Wget and thunderbird using a custom useragent + definition file. + +* __v1.0.0__ *breaking* + - Complete rewrite of the API and major performance improvements. diff --git a/node_modules/useragent/CREDITS b/node_modules/useragent/CREDITS new file mode 100644 index 0000000..b564154 --- /dev/null +++ b/node_modules/useragent/CREDITS @@ -0,0 +1,16 @@ +The regex library that the useragent parser uses if from; code.google.com/p/ua-parser/ +which is released under Apache license: + +# Copyright 2009 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +#     http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/node_modules/useragent/LICENSE b/node_modules/useragent/LICENSE new file mode 100644 index 0000000..a4d6a95 --- /dev/null +++ b/node_modules/useragent/LICENSE @@ -0,0 +1,19 @@ +# MIT LICENSED Copyright (c) 2013 Arnout Kazemier (http://3rd-Eden.com) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. diff --git a/node_modules/useragent/README.md b/node_modules/useragent/README.md new file mode 100644 index 0000000..52ba479 --- /dev/null +++ b/node_modules/useragent/README.md @@ -0,0 +1,393 @@ +# useragent - high performance user agent parser for Node.js + +Useragent originated as port of [browserscope.org][browserscope]'s user agent +parser project also known as ua-parser. Useragent allows you to parse user agent +string with high accuracy by using hand tuned dedicated regular expressions for +browser matching. This database is needed to ensure that every browser is +correctly parsed as every browser vendor implements it's own user agent schema. +This is why regular user agent parsers have major issues because they will +most likely parse out the wrong browser name or confuse the render engine version +with the actual version of the browser. + +--- + +### Build status [![BuildStatus](https://secure.travis-ci.org/3rd-Eden/useragent.png?branch=master)](http://travis-ci.org/3rd-Eden/useragent) + +--- + +### High performance + +The module has been developed with a benchmark driven approach. It has a +pre-compiled library that contains all the Regular Expressions and uses deferred +or on demand parsing for Operating System and device information. All this +engineering effort has been worth it as [this benchmark shows][benchmark]: + +``` +Starting the benchmark, parsing 62 useragent strings per run + +Executed benchmark against node module: "useragent" +Count (61), Cycles (5), Elapsed (5.559), Hz (1141.3739447904327) + +Executed benchmark against node module: "useragent_parser" +Count (29), Cycles (3), Elapsed (5.448), Hz (545.6817291171243) + +Executed benchmark against node module: "useragent-parser" +Count (16), Cycles (4), Elapsed (5.48), Hz (304.5373431830105) + +Executed benchmark against node module: "ua-parser" +Count (54), Cycles (3), Elapsed (5.512), Hz (1018.7561434659247) + +Module: "useragent" is the user agent fastest parser. +``` + +--- + +### Installation + +Installation is done using the Node Package Manager (NPM). If you don't have +NPM installed on your system you can download it from +[npmjs.org][npm] + +``` +npm install useragent --save +``` + +The `--save` flag tells NPM to automatically add it to your `package.json` file. + +--- + +### API + + +Include the `useragent` parser in you node.js application: + +```js +var useragent = require('useragent'); +``` + +The `useragent` library allows you do use the automatically installed RegExp +library or you can fetch it live from the remote servers. So if you are +paranoid and always want your RegExp library to be up to date to match with +agent the widest range of `useragent` strings you can do: + +```js +var useragent = require('useragent'); +useragent(true); +``` + +This will async load the database from the server and compile it to a proper +JavaScript supported format. If it fails to compile or load it from the remote +location it will just fall back silently to the shipped version. If you want to +use this feature you need to add `yamlparser` and `request` to your package.json + +``` +npm install yamlparser --save +npm install request --save +``` + +#### useragent.parse(useragent string[, js useragent]); + +This is the actual user agent parser, this is where all the magic is happening. +The function accepts 2 arguments, both should be a `string`. The first argument +should the user agent string that is known on the server from the +`req.headers.useragent` header. The other argument is optional and should be +the user agent string that you see in the browser, this can be send from the +browser using a xhr request or something like this. This allows you detect if +the user is browsing the web using the `Chrome Frame` extension. + +The parser returns a Agent instance, this allows you to output user agent +information in different predefined formats. See the Agent section for more +information. + +```js +var agent = useragent.parse(req.headers['user-agent']); + +// example for parsing both the useragent header and a optional js useragent +var agent2 = useragent.parse(req.headers['user-agent'], req.query.jsuseragent); +``` + +The parse method returns a `Agent` instance which contains all details about the +user agent. See the Agent section of the API documentation for the available +methods. + +#### useragent.lookup(useragent string[, js useragent]); + +This provides the same functionality as above, but it caches the user agent +string and it's parsed result in memory to provide faster lookups in the +future. This can be handy if you expect to parse a lot of user agent strings. + +It uses the same arguments as the `useragent.parse` method and returns exactly +the same result, but it's just cached. + +```js +var agent = useragent.lookup(req.headers['user-agent']); +``` + +And this is a serious performance improvement as shown in this benchmark: + +``` +Executed benchmark against method: "useragent.parse" +Count (49), Cycles (3), Elapsed (5.534), Hz (947.6844321931629) + +Executed benchmark against method: "useragent.lookup" +Count (11758), Cycles (3), Elapsed (5.395), Hz (229352.03831239208) +``` + +#### useragent.fromJSON(obj); + +Transforms the JSON representation of a `Agent` instance back in to a working +`Agent` instance + +```js +var agent = useragent.parse(req.headers['user-agent']) + , another = useragent.fromJSON(JSON.stringify(agent)); + +console.log(agent == another); +``` + +#### useragent.is(useragent string).browsername; + +This api provides you with a quick and dirty browser lookup. The underlying +code is usually found on client side scripts so it's not the same quality as +our `useragent.parse` method but it might be needed for legacy reasons. + +`useragent.is` returns a object with potential matched browser names + +```js +useragent.is(req.headers['user-agent']).firefox // true +useragent.is(req.headers['user-agent']).safari // false +var ua = useragent.is(req.headers['user-agent']) + +// the object +{ + version: '3' + webkit: false + opera: false + ie: false + chrome: false + safari: false + mobile_safari: false + firefox: true +} +``` + +--- + +### Agents, OperatingSystem and Device instances + +Most of the methods mentioned above return a Agent instance. The Agent exposes +the parsed out information from the user agent strings. This allows us to +extend the agent with more methods that do not necessarily need to be in the +core agent instance, allowing us to expose a plugin interface for third party +developers and at the same time create a uniform interface for all versioning. + +The Agent has the following property + +- `family` The browser family, or browser name, it defaults to Other. +- `major` The major version number of the family, it defaults to 0. +- `minor` The minor version number of the family, it defaults to 0. +- `patch` The patch version number of the family, it defaults to 0. + +In addition to the properties mentioned above, it also has 2 special properties, +which are: + +- `os` OperatingSystem instance +- `device` Device instance + +When you access those 2 properties the agent will do on demand parsing of the +Operating System or/and Device information. + +The OperatingSystem has the same properties as the Agent, for the Device we +don't have any versioning information available, so only the `family` property is +set there. If we cannot find the family, they will default to `Other`. + +The following methods are available: + +#### Agent.toAgent(); + +Returns the family and version number concatinated in a nice human readable +string. + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.toAgent(); // 'Chrome 15.0.874' +``` + +#### Agent.toString(); + +Returns the results of the `Agent.toAgent()` but also adds the parsed operating +system to the string in a human readable format. + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.toString(); // 'Chrome 15.0.874 / Mac OS X 10.8.1' + +// as it's a to string method you can also concat it with another string +'your useragent is ' + agent; +// 'your useragent is Chrome 15.0.874 / Mac OS X 10.8.1' +``` +#### Agent.toVersion(); + +Returns the version of the browser in a human readable string. + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.toVersion(); // '15.0.874' +``` + +#### Agent.toJSON(); + +Generates a JSON representation of the Agent. By using the `toJSON` method we +automatically allow it to be stringified when supplying as to the +`JSON.stringify` method. + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.toJSON(); // returns an object + +JSON.stringify(agent); +``` + +#### OperatingSystem.toString(); + +Generates a stringified version of operating system; + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.os.toString(); // 'Mac OSX 10.8.1' +``` + +#### OperatingSystem.toVersion(); + +Generates a stringified version of operating system's version; + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.os.toVersion(); // '10.8.1' +``` + +#### OperatingSystem.toJSON(); + +Generates a JSON representation of the OperatingSystem. By using the `toJSON` +method we automatically allow it to be stringified when supplying as to the +`JSON.stringify` method. + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.os.toJSON(); // returns an object + +JSON.stringify(agent.os); +``` + +#### Device.toString(); + +Generates a stringified version of device; + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.device.toString(); // 'Asus A100' +``` + +#### Device.toVersion(); + +Generates a stringified version of device's version; + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.device.toVersion(); // '' , no version found but could also be '0.0.0' +``` + +#### Device.toJSON(); + +Generates a JSON representation of the Device. By using the `toJSON` method we +automatically allow it to be stringified when supplying as to the +`JSON.stringify` method. + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.device.toJSON(); // returns an object + +JSON.stringify(agent.device); +``` + +### Adding more features to the useragent + +As I wanted to keep the core of the user agent parser as clean and fast as +possible I decided to move some of the initially planned features to a new +`plugin` file. + +These extensions to the Agent prototype can be loaded by requiring the +`useragent/features` file: + +```js +var useragent = require('useragent'); +require('useragent/features'); +``` + +The initial release introduces 1 new method, satisfies, which allows you to see +if the version number of the browser satisfies a certain range. It uses the +semver library to do all the range calculations but here is a small summary of +the supported range styles: + +* `>1.2.3` Greater than a specific version. +* `<1.2.3` Less than. +* `1.2.3 - 2.3.4` := `>=1.2.3 <=2.3.4`. +* `~1.2.3` := `>=1.2.3 <1.3.0`. +* `~1.2` := `>=1.2.0 <2.0.0`. +* `~1` := `>=1.0.0 <2.0.0`. +* `1.2.x` := `>=1.2.0 <1.3.0`. +* `1.x` := `>=1.0.0 <2.0.0`. + +As it requires the `semver` module to function you need to install it +seperately: + +``` +npm install semver --save +``` + +#### Agent.satisfies('range style here'); + +Check if the agent matches the supplied range. + +```js +var agent = useragent.parse(req.headers['user-agent']); +agent.satisfies('15.x || >=19.5.0 || 25.0.0 - 17.2.3'); // true +agent.satisfies('>16.12.0'); // false +``` +--- + +### Migrations + +For small changes between version please review the [changelog][changelog]. + +#### Upgrading from 1.10 to 2.0.0 + +- `useragent.fromAgent` has been removed. +- `agent.toJSON` now returns an Object, use `JSON.stringify(agent)` for the old + behaviour. +- `agent.os` is now an `OperatingSystem` instance with version numbers. If you + still a string only representation do `agent.os.toString()`. +- `semver` has been removed from the dependencies, so if you are using the + `require('useragent/features')` you need to add it to your own dependencies + +#### Upgrading from 0.1.2 to 1.0.0 + +- `useragent.browser(ua)` has been renamed to `useragent.is(ua)`. +- `useragent.parser(ua, jsua)` has been renamed to `useragent.parse(ua, jsua)`. +- `result.pretty()` has been renamed to `result.toAgent()`. +- `result.V1` has been renamed to `result.major`. +- `result.V2` has been renamed to `result.minor`. +- `result.V3` has been renamed to `result.patch`. +- `result.prettyOS()` has been removed. +- `result.match` has been removed. + +--- + +### License + +MIT + +[browserscope]: http://www.browserscope.org/ +[benchmark]: /3rd-Eden/useragent/blob/master/benchmark/run.js +[changelog]: /3rd-Eden/useragent/blob/master/CHANGELOG.md +[npm]: http://npmjs.org diff --git a/node_modules/useragent/bin/testfiles.js b/node_modules/useragent/bin/testfiles.js new file mode 100755 index 0000000..f01a6d7 --- /dev/null +++ b/node_modules/useragent/bin/testfiles.js @@ -0,0 +1,24 @@ +#!/usr/bin/env node + +var request = require('request') + , path = require('path') + , fs = require('fs'); + +var files = { + 'pgts.yaml': 'https://raw.github.com/tobie/ua-parser/master/test_resources/pgts_browser_list.yaml' + , 'testcases.yaml': 'https://raw.github.com/tobie/ua-parser/master/test_resources/test_user_agent_parser.yaml' + , 'firefoxes.yaml': 'https://raw.github.com/tobie/ua-parser/master/test_resources/firefox_user_agent_strings.yaml' +}; + +/** + * Update the fixtures + */ + +Object.keys(files).forEach(function (key) { + request(files[key], function response (err, res, data) { + if (err || res.statusCode !== 200) return console.error('failed to update'); + + console.log('downloaded', files[key]); + fs.writeFileSync(path.join(__dirname, '..', 'tests', 'fixtures', key), data); + }); +}); diff --git a/node_modules/useragent/bin/update.js b/node_modules/useragent/bin/update.js new file mode 100755 index 0000000..28c2501 --- /dev/null +++ b/node_modules/useragent/bin/update.js @@ -0,0 +1,17 @@ +#!/usr/bin/env node + +'use strict'; + +/** + * Update our definition file. + */ +require('../lib/update').update(function updating(err, data) { + if (err) { + console.error('Update unsuccessfull due to reasons'); + console.log(err.message); + console.log(err.stack); + + return; + } + console.log('Successfully fetched and generated new parsers from the internets.'); +}); diff --git a/node_modules/useragent/features/index.js b/node_modules/useragent/features/index.js new file mode 100644 index 0000000..5dab04a --- /dev/null +++ b/node_modules/useragent/features/index.js @@ -0,0 +1,19 @@ +"use strict"; + +/** + * Plugin dependencies + */ +var Agent = require('../').Agent + , semver = require('semver'); + +/** + * Checks if the user agent's version can be satisfied agents the give + * ranged argument. This uses the semver libraries range construction. + * + * @param {String} ranged The range the version has to satisfie + * @returns {Boolean} + * @api public + */ +Agent.prototype.satisfies = function satisfies (range) { + return semver.satisfies(this.major + '.' + this.minor + '.' + this.patch, range); +}; diff --git a/node_modules/useragent/index.js b/node_modules/useragent/index.js new file mode 100644 index 0000000..f239a36 --- /dev/null +++ b/node_modules/useragent/index.js @@ -0,0 +1,598 @@ +'use strict'; + +/** + * This is where all the magic comes from, specially crafted for `useragent`. + */ +var regexps = require('./lib/regexps'); + +/** + * Reduce references by storing the lookups. + */ +// OperatingSystem parsers: +var osparsers = regexps.os + , osparserslength = osparsers.length; + +// UserAgent parsers: +var agentparsers = regexps.browser + , agentparserslength = agentparsers.length; + +// Device parsers: +var deviceparsers = regexps.device + , deviceparserslength = deviceparsers.length; + +/** + * The representation of a parsed user agent. + * + * @constructor + * @param {String} family The name of the browser + * @param {String} major Major version of the browser + * @param {String} minor Minor version of the browser + * @param {String} patch Patch version of the browser + * @param {String} source The actual user agent string + * @api public + */ +function Agent(family, major, minor, patch, source) { + this.family = family || 'Other'; + this.major = major || '0'; + this.minor = minor || '0'; + this.patch = patch || '0'; + this.source = source || ''; +} + +/** + * OnDemand parsing of the Operating System. + * + * @type {OperatingSystem} + * @api public + */ +Object.defineProperty(Agent.prototype, 'os', { + get: function lazyparse() { + var userAgent = this.source + , length = osparserslength + , parsers = osparsers + , i = 0 + , parser + , res; + + for (; i < length; i++) { + if (res = parsers[i][0].exec(userAgent)) { + parser = parsers[i]; + + if (parser[1]) res[1] = parser[1].replace('$1', res[1]); + break; + } + } + + return Object.defineProperty(this, 'os', { + value: !parser || !res + ? new OperatingSystem() + : new OperatingSystem( + res[1] + , parser[2] || res[2] + , parser[3] || res[3] + , parser[4] || res[4] + ) + }).os; + }, + + /** + * Bypass the OnDemand parsing and set an OperatingSystem instance. + * + * @param {OperatingSystem} os + * @api public + */ + set: function set(os) { + if (!(os instanceof OperatingSystem)) return false; + + return Object.defineProperty(this, 'os', { + value: os + }).os; + } +}); + +/** + * OnDemand parsing of the Device type. + * + * @type {Device} + * @api public + */ +Object.defineProperty(Agent.prototype, 'device', { + get: function lazyparse() { + var userAgent = this.source + , length = deviceparserslength + , parsers = deviceparsers + , i = 0 + , parser + , res; + + for (; i < length; i++) { + if (res = parsers[i][0].exec(userAgent)) { + parser = parsers[i]; + + if (parser[1]) res[1] = parser[1].replace('$1', res[1]); + break; + } + } + + return Object.defineProperty(this, 'device', { + value: !parser || !res + ? new Device() + : new Device( + res[1] + , parser[2] || res[2] + , parser[3] || res[3] + , parser[4] || res[4] + ) + }).device; + }, + + /** + * Bypass the OnDemand parsing and set an Device instance. + * + * @param {Device} device + * @api public + */ + set: function set(device) { + if (!(device instanceof Device)) return false; + + return Object.defineProperty(this, 'device', { + value: device + }).device; + } +}); +/*** Generates a string output of the parsed user agent. + * + * @returns {String} + * @api public + */ +Agent.prototype.toAgent = function toAgent() { + var output = this.family + , version = this.toVersion(); + + if (version) output += ' '+ version; + return output; +}; + +/** + * Generates a string output of the parser user agent and operating system. + * + * @returns {String} "UserAgent 0.0.0 / OS" + * @api public + */ +Agent.prototype.toString = function toString() { + var agent = this.toAgent() + , os = this.os !== 'Other' ? this.os : false; + + return agent + (os ? ' / ' + os : ''); +}; + +/** + * Outputs a compiled veersion number of the user agent. + * + * @returns {String} + * @api public + */ +Agent.prototype.toVersion = function toVersion() { + var version = ''; + + if (this.major) { + version += this.major; + + if (this.minor) { + version += '.' + this.minor; + + // Special case here, the patch can also be Alpha, Beta etc so we need + // to check if it's a string or not. + if (this.patch) { + version += (isNaN(+this.patch) ? ' ' : '.') + this.patch; + } + } + } + + return version; +}; + +/** + * Outputs a JSON string of the Agent. + * + * @returns {String} + * @api public + */ +Agent.prototype.toJSON = function toJSON() { + return { + family: this.family + , major: this.major + , minor: this.minor + , patch: this.patch + , device: this.device + , os: this.os + }; +}; + +/** + * The representation of a parsed Operating System. + * + * @constructor + * @param {String} family The name of the os + * @param {String} major Major version of the os + * @param {String} minor Minor version of the os + * @param {String} patch Patch version of the os + * @api public + */ +function OperatingSystem(family, major, minor, patch) { + this.family = family || 'Other'; + this.major = major || ''; + this.minor = minor || ''; + this.patch = patch || ''; +} + +/** + * Generates a stringified version of the Operating System. + * + * @returns {String} "Operating System 0.0.0" + * @api public + */ +OperatingSystem.prototype.toString = function toString() { + var output = this.family + , version = this.toVersion(); + + if (version) output += ' '+ version; + return output; +}; + +/** + * Generates the version of the Operating System. + * + * @returns {String} + * @api public + */ +OperatingSystem.prototype.toVersion = function toVersion() { + var version = ''; + + if (this.major) { + version += this.major; + + if (this.minor) { + version += '.' + this.minor; + + // Special case here, the patch can also be Alpha, Beta etc so we need + // to check if it's a string or not. + if (this.patch) { + version += (isNaN(+this.patch) ? ' ' : '.') + this.patch; + } + } + } + + return version; +}; + +/** + * Outputs a JSON string of the OS, values are defaulted to undefined so they + * are not outputed in the stringify. + * + * @returns {String} + * @api public + */ +OperatingSystem.prototype.toJSON = function toJSON(){ + return { + family: this.family + , major: this.major || undefined + , minor: this.minor || undefined + , patch: this.patch || undefined + }; +}; + +/** + * The representation of a parsed Device. + * + * @constructor + * @param {String} family The name of the os + * @api public + */ +function Device(family, major, minor, patch) { + this.family = family || 'Other'; + this.major = major || ''; + this.minor = minor || ''; + this.patch = patch || ''; +} + +/** + * Generates a stringified version of the Device. + * + * @returns {String} "Device 0.0.0" + * @api public + */ +Device.prototype.toString = function toString() { + var output = this.family + , version = this.toVersion(); + + if (version) output += ' '+ version; + return output; +}; + +/** + * Generates the version of the Device. + * + * @returns {String} + * @api public + */ +Device.prototype.toVersion = function toVersion() { + var version = ''; + + if (this.major) { + version += this.major; + + if (this.minor) { + version += '.' + this.minor; + + // Special case here, the patch can also be Alpha, Beta etc so we need + // to check if it's a string or not. + if (this.patch) { + version += (isNaN(+this.patch) ? ' ' : '.') + this.patch; + } + } + } + + return version; +}; + +/** + * Get string representation. + * + * @returns {String} + * @api public + */ +Device.prototype.toString = function toString() { + var output = this.family + , version = this.toVersion(); + + if (version) output += ' '+ version; + return output; +}; + +/** + * Outputs a JSON string of the Device, values are defaulted to undefined so they + * are not outputed in the stringify. + * + * @returns {String} + * @api public + */ +Device.prototype.toJSON = function toJSON() { + return { + family: this.family + , major: this.major || undefined + , minor: this.minor || undefined + , patch: this.patch || undefined + }; +}; + +/** + * Small nifty thick that allows us to download a fresh set regexs from t3h + * Int3rNetz when we want to. We will be using the compiled version by default + * but users can opt-in for updates. + * + * @param {Boolean} refresh Refresh the dataset from the remote + * @api public + */ +module.exports = function updater() { + try { + require('./lib/update').update(function updating(err, results) { + if (err) { + console.log('[useragent] Failed to update the parsed due to an error:'); + console.log('[useragent] '+ (err.message ? err.message : err)); + return; + } + + regexps = results; + + // OperatingSystem parsers: + osparsers = regexps.os; + osparserslength = osparsers.length; + + // UserAgent parsers: + agentparsers = regexps.browser; + agentparserslength = agentparsers.length; + + // Device parsers: + deviceparsers = regexps.device; + deviceparserslength = deviceparsers.length; + }); + } catch (e) { + console.error('[useragent] If you want to use automatic updating, please add:'); + console.error('[useragent] - request (npm install request --save)'); + console.error('[useragent] - yamlparser (npm install yamlparser --save)'); + console.error('[useragent] To your own package.json'); + } +}; + +// Override the exports with our newly set module.exports +exports = module.exports; + +/** + * Nao that we have setup all the different classes and configured it we can + * actually start assembling and exposing everything. + */ +exports.Device = Device; +exports.OperatingSystem = OperatingSystem; +exports.Agent = Agent; + +/** + * Parses the user agent string with the generated parsers from the + * ua-parser project on google code. + * + * @param {String} userAgent The user agent string + * @param {String} jsAgent Optional UA from js to detect chrome frame + * @returns {Agent} + * @api public + */ +exports.parse = function parse(userAgent, jsAgent) { + if (!userAgent) return new Agent(); + + var length = agentparserslength + , parsers = agentparsers + , i = 0 + , parser + , res; + + for (; i < length; i++) { + if (res = parsers[i][0].exec(userAgent)) { + parser = parsers[i]; + + if (parser[1]) res[1] = parser[1].replace('$1', res[1]); + if (!jsAgent) return new Agent( + res[1] + , parser[2] || res[2] + , parser[3] || res[3] + , parser[4] || res[4] + , userAgent + ); + + break; + } + } + + // Return early if we didn't find an match, but might still be able to parse + // the os and device, so make sure we supply it with the source + if (!parser || !res) return new Agent('', '', '', '', userAgent); + + // Detect Chrome Frame, but make sure it's enabled! So we need to check for + // the Chrome/ so we know that it's actually using Chrome under the hood. + if (jsAgent && ~jsAgent.indexOf('Chrome/') && ~userAgent.indexOf('chromeframe')) { + res[1] = 'Chrome Frame (IE '+ res[1] +'.'+ res[2] +')'; + + // Run the JavaScripted userAgent string through the parser again so we can + // update the version numbers; + parser = parse(jsAgent); + parser[2] = parser.major; + parser[3] = parser.minor; + parser[4] = parser.patch; + } + + return new Agent( + res[1] + , parser[2] || res[2] + , parser[3] || res[3] + , parser[4] || res[4] + , userAgent + ); +}; + +/** + * If you are doing a lot of lookups you might want to cache the results of the + * parsed user agent string instead, in memory. + * + * @TODO We probably want to create 2 dictionary's here 1 for the Agent + * instances and one for the userAgent instance mapping so we can re-use simular + * Agent instance and lower our memory consumption. + * + * @param {String} userAgent The user agent string + * @param {String} jsAgent Optional UA from js to detect chrome frame + * @api public + */ +var LRU = require('lru-cache')(5000); +exports.lookup = function lookup(userAgent, jsAgent) { + var key = (userAgent || '')+(jsAgent || '') + , cached = LRU.get(key); + + if (cached) return cached; + LRU.set(key, (cached = exports.parse(userAgent, jsAgent))); + + return cached; +}; + +/** + * Does a more inaccurate but more common check for useragents identification. + * The version detection is from the jQuery.com library and is licensed under + * MIT. + * + * @param {String} useragent The user agent + * @returns {Object} matches + * @api public + */ +exports.is = function is(useragent) { + var ua = (useragent || '').toLowerCase() + , details = { + chrome: false + , firefox: false + , ie: false + , mobile_safari: false + , mozilla: false + , opera: false + , safari: false + , webkit: false + , version: (ua.match(exports.is.versionRE) || [0, "0"])[1] + }; + + if (~ua.indexOf('webkit')) { + details.webkit = true; + + if (~ua.indexOf('chrome')) { + details.chrome = true; + } else if (~ua.indexOf('safari')) { + details.safari = true; + + if (~ua.indexOf('mobile') && ~ua.indexOf('apple')) { + details.mobile_safari = true; + } + } + } else if (~ua.indexOf('opera')) { + details.opera = true; + } else if (~ua.indexOf('mozilla') && !~ua.indexOf('compatible')) { + details.mozilla = true; + + if (~ua.indexOf('firefox')) details.firefox = true; + } else if (~ua.indexOf('msie')) { + details.ie = true; + } + + return details; +}; + +/** + * Parses out the version numbers. + * + * @type {RegExp} + * @api private + */ +exports.is.versionRE = /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/; + +/** + * Transform a JSON object back to a valid userAgent string + * + * @param {Object} details + * @returns {Agent} + */ +exports.fromJSON = function fromJSON(details) { + if (typeof details === 'string') details = JSON.parse(details); + + var agent = new Agent(details.family, details.major, details.minor, details.patch) + , os = details.os; + + // The device family was added in v2.0 + if ('device' in details) { + agent.device = new Device(details.device.family); + } else { + agent.device = new Device(); + } + + if ('os' in details && os) { + // In v1.1.0 we only parsed out the Operating System name, not the full + // version which we added in v2.0. To provide backwards compatible we should + // we should set the details.os as family + if (typeof os === 'string') { + agent.os = new OperatingSystem(os); + } else { + agent.os = new OperatingSystem(os.family, os.major, os.minor, os.patch); + } + } + + return agent; +}; + +/** + * Library version. + * + * @type {String} + * @api public + */ +exports.version = require('./package.json').version; diff --git a/node_modules/useragent/lib/regexps.js b/node_modules/useragent/lib/regexps.js new file mode 100644 index 0000000..fb271d4 --- /dev/null +++ b/node_modules/useragent/lib/regexps.js @@ -0,0 +1,2270 @@ +var parser; + +exports.browser = Object.create(null); + +parser = Object.create(null); +parser[0] = new RegExp("(SeaMonkey|Camino)/(\\d+)\\.(\\d+)\\.?([ab]?\\d+[a-z]*)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[0] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Pale[Mm]oon)/(\\d+)\\.(\\d+)\\.?(\\d+)?"); +parser[1] = "Pale Moon (Firefox Variant)"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[1] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Fennec)/(\\d+)\\.(\\d+)\\.?([ab]?\\d+[a-z]*)"); +parser[1] = "Firefox Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[2] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Fennec)/(\\d+)\\.(\\d+)(pre)"); +parser[1] = "Firefox Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[3] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Fennec)/(\\d+)\\.(\\d+)"); +parser[1] = "Firefox Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[4] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Mobile.*(Firefox)/(\\d+)\\.(\\d+)"); +parser[1] = "Firefox Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[5] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Namoroka|Shiretoko|Minefield)/(\\d+)\\.(\\d+)\\.(\\d+(?:pre)?)"); +parser[1] = "Firefox ($1)"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[6] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)/(\\d+)\\.(\\d+)(a\\d+[a-z]*)"); +parser[1] = "Firefox Alpha"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[7] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)/(\\d+)\\.(\\d+)(b\\d+[a-z]*)"); +parser[1] = "Firefox Beta"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[8] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)-(?:\\d+\\.\\d+)?/(\\d+)\\.(\\d+)(a\\d+[a-z]*)"); +parser[1] = "Firefox Alpha"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[9] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)-(?:\\d+\\.\\d+)?/(\\d+)\\.(\\d+)(b\\d+[a-z]*)"); +parser[1] = "Firefox Beta"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[10] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Namoroka|Shiretoko|Minefield)/(\\d+)\\.(\\d+)([ab]\\d+[a-z]*)?"); +parser[1] = "Firefox ($1)"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[11] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox).*Tablet browser (\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "MicroB"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[12] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(MozillaDeveloperPreview)/(\\d+)\\.(\\d+)([ab]\\d+[a-z]*)?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[13] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Flock)/(\\d+)\\.(\\d+)(b\\d+?)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[14] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(RockMelt)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[15] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Navigator)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Netscape"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[16] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Navigator)/(\\d+)\\.(\\d+)([ab]\\d+)"); +parser[1] = "Netscape"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[17] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Netscape6)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Netscape"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[18] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(MyIBrow)/(\\d+)\\.(\\d+)"); +parser[1] = "My Internet Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[19] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Opera Tablet).*Version/(\\d+)\\.(\\d+)(?:\\.(\\d+))?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[20] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Opera)/.+Opera Mobi.+Version/(\\d+)\\.(\\d+)"); +parser[1] = "Opera Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[21] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Opera Mobi"); +parser[1] = "Opera Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[22] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Opera Mini)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[23] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Opera Mini)/att/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[24] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Opera)/9.80.*Version/(\\d+)\\.(\\d+)(?:\\.(\\d+))?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[25] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(?:Mobile Safari).*(OPR)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Opera Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[26] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(?:Chrome).*(OPR)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Opera"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[27] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(hpw|web)OS/(\\d+)\\.(\\d+)(?:\\.(\\d+))?"); +parser[1] = "webOS Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[28] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(luakit)"); +parser[1] = "LuaKit"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[29] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Snowshoe)/(\\d+)\\.(\\d+).(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[30] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Lightning)/(\\d+)\\.(\\d+)([ab]?\\d+[a-z]*)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[31] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)/(\\d+)\\.(\\d+)\\.(\\d+(?:pre)?) \\(Swiftfox\\)"); +parser[1] = "Swiftfox"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[32] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)/(\\d+)\\.(\\d+)([ab]\\d+[a-z]*)? \\(Swiftfox\\)"); +parser[1] = "Swiftfox"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[33] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(rekonq)/(\\d+)\\.(\\d+)\\.?(\\d+)? Safari"); +parser[1] = "Rekonq"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[34] = parser; +parser = Object.create(null); +parser[0] = new RegExp("rekonq"); +parser[1] = "Rekonq"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[35] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(conkeror|Conkeror)/(\\d+)\\.(\\d+)\\.?(\\d+)?"); +parser[1] = "Conkeror"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[36] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(konqueror)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Konqueror"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[37] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(WeTab)-Browser"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[38] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Comodo_Dragon)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Comodo Dragon"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[39] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(YottaaMonitor|BrowserMob|HttpMonitor|YandexBot|Slurp|BingPreview|PagePeeker|ThumbShotsBot|WebThumb|URL2PNG|ZooShot|GomezA|Catchpoint bot|Willow Internet Crawler|Google SketchUp|Read%20Later)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[40] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Symphony) (\\d+).(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[41] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Minimo)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[42] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(CrMo)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Chrome Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[43] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(CriOS)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Chrome Mobile iOS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[44] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Chrome)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+) Mobile"); +parser[1] = "Chrome Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[45] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(chromeframe)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Chrome Frame"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[46] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(UCBrowser)[ /](\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "UC Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[47] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(UC Browser)[ /](\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[48] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(UC Browser|UCBrowser|UCWEB)(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "UC Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[49] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(SLP Browser)/(\\d+)\\.(\\d+)"); +parser[1] = "Tizen Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[50] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(SE 2\\.X) MetaSr (\\d+)\\.(\\d+)"); +parser[1] = "Sogou Explorer"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[51] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(baidubrowser)[/\\s](\\d+)"); +parser[1] = "Baidu Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[52] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(FlyFlow)/(\\d+)\\.(\\d+)"); +parser[1] = "Baidu Explorer"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[53] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Pingdom.com_bot_version_)(\\d+)\\.(\\d+)"); +parser[1] = "PingdomBot"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[54] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(facebookexternalhit)/(\\d+)\\.(\\d+)"); +parser[1] = "FacebookBot"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[55] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Twitterbot)/(\\d+)\\.(\\d+)"); +parser[1] = "TwitterBot"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[56] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Rackspace Monitoring)/(\\d+)\\.(\\d+)"); +parser[1] = "RackspaceBot"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[57] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PyAMF)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[58] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(YaBrowser)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Yandex Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[59] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Chrome)/(\\d+)\\.(\\d+)\\.(\\d+).* MRCHROME"); +parser[1] = "Mail.ru Chromium Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[60] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(AOL) (\\d+)\\.(\\d+); AOLBuild (\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[61] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(AdobeAIR|FireWeb|Jasmine|ANTGalio|Midori|Fresco|Lobo|PaleMoon|Maxthon|Lynx|OmniWeb|Dillo|Camino|Demeter|Fluid|Fennec|Epiphany|Shiira|Sunrise|Flock|Netscape|Lunascape|WebPilot|Vodafone|NetFront|Netfront|Konqueror|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|Opera Mini|iCab|NetNewsWire|ThunderBrowse|Iris|UP\\.Browser|Bunjalloo|Google Earth|Raven for Mac|Openwave)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[62] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Chromium|Chrome)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[63] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Bolt|Jasmine|IceCat|Skyfire|Midori|Maxthon|Lynx|Arora|IBrowse|Dillo|Camino|Shiira|Fennec|Phoenix|Chrome|Flock|Netscape|Lunascape|Epiphany|WebPilot|Opera Mini|Opera|Vodafone|NetFront|Netfront|Konqueror|Googlebot|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|iCab|NetNewsWire|Space Bison|Stainless|Orca|Dolfin|BOLT|Minimo|Tizen Browser|Polaris|Abrowser|Planetweb|ICE Browser)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[64] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Chromium|Chrome)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[65] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iRider|Crazy Browser|SkipStone|iCab|Lunascape|Sleipnir|Maemo Browser) (\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[66] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iCab|Lunascape|Opera|Android|Jasmine|Polaris) (\\d+)\\.(\\d+)\\.?(\\d+)?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[67] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Kindle)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[68] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Donut"); +parser[1] = 0; +parser[2] = "1"; +parser[3] = "2"; +parser[4] = 0; +exports.browser[69] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Eclair"); +parser[1] = 0; +parser[2] = "2"; +parser[3] = "1"; +parser[4] = 0; +exports.browser[70] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Froyo"); +parser[1] = 0; +parser[2] = "2"; +parser[3] = "2"; +parser[4] = 0; +exports.browser[71] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Gingerbread"); +parser[1] = 0; +parser[2] = "2"; +parser[3] = "3"; +parser[4] = 0; +exports.browser[72] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Honeycomb"); +parser[1] = 0; +parser[2] = "3"; +parser[3] = 0; +parser[4] = 0; +exports.browser[73] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(IEMobile)[ /](\\d+)\\.(\\d+)"); +parser[1] = "IE Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[74] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(MSIE) (\\d+)\\.(\\d+).*XBLWP7"); +parser[1] = "IE Large Screen"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[75] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[76] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Firefox)/(\\d+)\\.(\\d+)(pre|[ab]\\d+[a-z]*)?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[77] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Obigo)InternetBrowser"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[78] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Obigo)\\-Browser"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[79] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Obigo|OBIGO)[^\\d]*(\\d+)(?:.(\\d+))?"); +parser[1] = "Obigo"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[80] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(MAXTHON|Maxthon) (\\d+)\\.(\\d+)"); +parser[1] = "Maxthon"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[81] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Maxthon|MyIE2|Uzbl|Shiira)"); +parser[1] = 0; +parser[2] = "0"; +parser[3] = 0; +parser[4] = 0; +exports.browser[82] = parser; +parser = Object.create(null); +parser[0] = new RegExp("PLAYSTATION 3.+WebKit"); +parser[1] = "NetFront NX"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[83] = parser; +parser = Object.create(null); +parser[0] = new RegExp("PLAYSTATION 3"); +parser[1] = "NetFront"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[84] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PlayStation Portable)"); +parser[1] = "NetFront"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[85] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PlayStation Vita)"); +parser[1] = "NetFront NX"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[86] = parser; +parser = Object.create(null); +parser[0] = new RegExp("AppleWebKit.+ (NX)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "NetFront NX"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[87] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Nintendo 3DS)"); +parser[1] = "NetFront NX"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[88] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(BrowseX) \\((\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[89] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(NCSA_Mosaic)/(\\d+)\\.(\\d+)"); +parser[1] = "NCSA Mosaic"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[90] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(POLARIS)/(\\d+)\\.(\\d+)"); +parser[1] = "Polaris"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[91] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Embider)/(\\d+)\\.(\\d+)"); +parser[1] = "Polaris"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[92] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(BonEcho)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Bon Echo"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[93] = parser; +parser = Object.create(null); +parser[0] = new RegExp("M?QQBrowser"); +parser[1] = "QQ Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[94] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPod).+Version/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[95] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPod).*Version/(\\d+)\\.(\\d+)"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[96] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPhone).*Version/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[97] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPhone).*Version/(\\d+)\\.(\\d+)"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[98] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPad).*Version/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[99] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPad).*Version/(\\d+)\\.(\\d+)"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[100] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPod|iPhone|iPad);.*CPU.*OS (\\d+)(?:_\\d+)?_(\\d+).*Mobile"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[101] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPod|iPhone|iPad)"); +parser[1] = "Mobile Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[102] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(AvantGo) (\\d+).(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[103] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(OneBrowser)/(\\d+).(\\d+)"); +parser[1] = "ONE Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[104] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Avant)"); +parser[1] = 0; +parser[2] = "1"; +parser[3] = 0; +parser[4] = 0; +exports.browser[105] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(QtCarBrowser)"); +parser[1] = 0; +parser[2] = "1"; +parser[3] = 0; +parser[4] = 0; +exports.browser[106] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iBrowser/Mini)(\\d+).(\\d+)"); +parser[1] = "iBrowser Mini"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[107] = parser; +parser = Object.create(null); +parser[0] = new RegExp("^(Nokia)"); +parser[1] = "Nokia Services (WAP) Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[108] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(NokiaBrowser)/(\\d+)\\.(\\d+).(\\d+)\\.(\\d+)"); +parser[1] = "Nokia Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[109] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(NokiaBrowser)/(\\d+)\\.(\\d+).(\\d+)"); +parser[1] = "Nokia Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[110] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(NokiaBrowser)/(\\d+)\\.(\\d+)"); +parser[1] = "Nokia Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[111] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(BrowserNG)/(\\d+)\\.(\\d+).(\\d+)"); +parser[1] = "Nokia Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[112] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Series60)/5\\.0"); +parser[1] = "Nokia Browser"; +parser[2] = "7"; +parser[3] = "0"; +parser[4] = 0; +exports.browser[113] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Series60)/(\\d+)\\.(\\d+)"); +parser[1] = "Nokia OSS Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[114] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(S40OviBrowser)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Ovi Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[115] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Nokia)[EN]?(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[116] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(BB10);"); +parser[1] = "BlackBerry WebKit"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[117] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PlayBook).+RIM Tablet OS (\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "BlackBerry WebKit"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[118] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Black[bB]erry).+Version/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "BlackBerry WebKit"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[119] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Black[bB]erry)\\s?(\\d+)"); +parser[1] = "BlackBerry"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[120] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(OmniWeb)/v(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[121] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Blazer)/(\\d+)\\.(\\d+)"); +parser[1] = "Palm Blazer"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[122] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Pre)/(\\d+)\\.(\\d+)"); +parser[1] = "Palm Pre"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[123] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(ELinks)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[124] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(ELinks) \\((\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[125] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Links) \\((\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[126] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(QtWeb) Internet Browser/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[127] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Silk)/(\\d+)\\.(\\d+)(?:\\.([0-9\\-]+))?"); +parser[1] = "Amazon Silk"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[128] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PhantomJS)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[129] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(AppleWebKit)/(\\d+)\\.?(\\d+)?\\+ .* Safari"); +parser[1] = "WebKit Nightly"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[130] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Version)/(\\d+)\\.(\\d+)(?:\\.(\\d+))?.*Safari/"); +parser[1] = "Safari"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[131] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Safari)/\\d+"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[132] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(OLPC)/Update(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[133] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(OLPC)/Update()\\.(\\d+)"); +parser[1] = 0; +parser[2] = "0"; +parser[3] = 0; +parser[4] = 0; +exports.browser[134] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(SEMC\\-Browser)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[135] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Teleca)"); +parser[1] = "Teleca Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[136] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Phantom)/V(\\d+)\\.(\\d+)"); +parser[1] = "Phantom Browser"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[137] = parser; +parser = Object.create(null); +parser[0] = new RegExp("([MS]?IE) (\\d+)\\.(\\d+)"); +parser[1] = "IE"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[138] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Trident(.*)rv.(\\d+)\\.(\\d+)"); +parser[1] = "IE"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[139] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(python-requests)/(\\d+)\\.(\\d+)"); +parser[1] = "Python Requests"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[140] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Thunderbird)/(\\d+)\\.(\\d+)\\.?(\\d+)?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[141] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Wget)/(\\d+)\\.(\\d+)\\.?([ab]?\\d+[a-z]*)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[142] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(curl)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "cURL"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.browser[143] = parser; + +exports.browser.length = 144; + +exports.device = Object.create(null); + +parser = Object.create(null); +parser[0] = new RegExp("HTC ([A-Z][a-z0-9]+) Build"); +parser[1] = "HTC $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[0] = parser; +parser = Object.create(null); +parser[0] = new RegExp("HTC ([A-Z][a-z0-9 ]+) \\d+\\.\\d+\\.\\d+\\.\\d+"); +parser[1] = "HTC $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[1] = parser; +parser = Object.create(null); +parser[0] = new RegExp("HTC_Touch_([A-Za-z0-9]+)"); +parser[1] = "HTC Touch ($1)"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[2] = parser; +parser = Object.create(null); +parser[0] = new RegExp("USCCHTC(\\d+)"); +parser[1] = "HTC $1 (US Cellular)"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[3] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Sprint APA(9292)"); +parser[1] = "HTC $1 (Sprint)"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[4] = parser; +parser = Object.create(null); +parser[0] = new RegExp("HTC ([A-Za-z0-9]+ [A-Z])"); +parser[1] = "HTC $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[5] = parser; +parser = Object.create(null); +parser[0] = new RegExp("HTC[-_/\\s]([A-Za-z0-9]+)"); +parser[1] = "HTC $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[6] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(ADR[A-Za-z0-9]+)"); +parser[1] = "HTC $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[7] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(HTC)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[8] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(QtCarBrowser)"); +parser[1] = "Tesla Model S"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[9] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(SamsungSGHi560)"); +parser[1] = "Samsung SGHi560"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[10] = parser; +parser = Object.create(null); +parser[0] = new RegExp("SonyEricsson([A-Za-z0-9]+)/"); +parser[1] = "Ericsson $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[11] = parser; +parser = Object.create(null); +parser[0] = new RegExp("PLAYSTATION 3"); +parser[1] = "PlayStation 3"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[12] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PlayStation Portable)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[13] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PlayStation Vita)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[14] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(KFOT Build)"); +parser[1] = "Kindle Fire"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[15] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(KFTT Build)"); +parser[1] = "Kindle Fire HD"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[16] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(KFJWI Build)"); +parser[1] = "Kindle Fire HD 8.9\" WiFi"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[17] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(KFJWA Build)"); +parser[1] = "Kindle Fire HD 8.9\" 4G"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[18] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Kindle Fire)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[19] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Kindle)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[20] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Silk)/(\\d+)\\.(\\d+)(?:\\.([0-9\\-]+))?"); +parser[1] = "Kindle Fire"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[21] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Android[\\- ][\\d]+\\.[\\d]+; [A-Za-z]{2}\\-[A-Za-z]{2}; WOWMobile (.+) Build"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[22] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Android[\\- ][\\d]+\\.[\\d]+\\-update1; [A-Za-z]{2}\\-[A-Za-z]{2}; (.+) Build"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[23] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Android[\\- ][\\d]+\\.[\\d]+\\.[\\d]+; [A-Za-z]{2}\\-[A-Za-z]{2}; (.+) Build"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[24] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Android[\\- ][\\d]+\\.[\\d]+\\.[\\d]+;[A-Za-z]{2}\\-[A-Za-z]{2};(.+) Build"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[25] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Android[\\- ][\\d]+\\.[\\d]+; [A-Za-z]{2}\\-[A-Za-z]{2}; (.+) Build"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[26] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Android[\\- ][\\d]+\\.[\\d]+\\.[\\d]+; (.+) Build"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[27] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Android[\\- ][\\d]+\\.[\\d]+; (.+) Build"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[28] = parser; +parser = Object.create(null); +parser[0] = new RegExp("NokiaN([0-9]+)"); +parser[1] = "Nokia N$1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[29] = parser; +parser = Object.create(null); +parser[0] = new RegExp("NOKIA([A-Za-z0-9\\v-]+)"); +parser[1] = "Nokia $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[30] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Nokia([A-Za-z0-9\\v-]+)"); +parser[1] = "Nokia $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[31] = parser; +parser = Object.create(null); +parser[0] = new RegExp("NOKIA ([A-Za-z0-9\\-]+)"); +parser[1] = "Nokia $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[32] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Nokia ([A-Za-z0-9\\-]+)"); +parser[1] = "Nokia $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[33] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Lumia ([A-Za-z0-9\\-]+)"); +parser[1] = "Lumia $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[34] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Symbian"); +parser[1] = "Nokia"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[35] = parser; +parser = Object.create(null); +parser[0] = new RegExp("BB10; ([A-Za-z0-9\\- ]+)\\)"); +parser[1] = "BlackBerry $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[36] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(PlayBook).+RIM Tablet OS"); +parser[1] = "BlackBerry Playbook"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[37] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Black[Bb]erry ([0-9]+);"); +parser[1] = "BlackBerry $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[38] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Black[Bb]erry([0-9]+)"); +parser[1] = "BlackBerry $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[39] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Black[Bb]erry;"); +parser[1] = "BlackBerry"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[40] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Pre)/(\\d+)\\.(\\d+)"); +parser[1] = "Palm Pre"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[41] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Pixi)/(\\d+)\\.(\\d+)"); +parser[1] = "Palm Pixi"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[42] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Touch[Pp]ad)/(\\d+)\\.(\\d+)"); +parser[1] = "HP TouchPad"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[43] = parser; +parser = Object.create(null); +parser[0] = new RegExp("HPiPAQ([A-Za-z0-9]+)/(\\d+).(\\d+)"); +parser[1] = "HP iPAQ $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[44] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Palm([A-Za-z0-9]+)"); +parser[1] = "Palm $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[45] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Treo([A-Za-z0-9]+)"); +parser[1] = "Palm Treo $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[46] = parser; +parser = Object.create(null); +parser[0] = new RegExp("webOS.*(P160UNA)/(\\d+).(\\d+)"); +parser[1] = "HP Veer"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[47] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(AppleTV)"); +parser[1] = "AppleTV"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[48] = parser; +parser = Object.create(null); +parser[0] = new RegExp("AdsBot-Google-Mobile"); +parser[1] = "Spider"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[49] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Googlebot-Mobile/(\\d+).(\\d+)"); +parser[1] = "Spider"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[50] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPad) Simulator;"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[51] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPad);"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[52] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPod) touch;"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[53] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPod);"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[54] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPhone) Simulator;"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[55] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPhone);"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[56] = parser; +parser = Object.create(null); +parser[0] = new RegExp("acer_([A-Za-z0-9]+)_"); +parser[1] = "Acer $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[57] = parser; +parser = Object.create(null); +parser[0] = new RegExp("acer_([A-Za-z0-9]+)_"); +parser[1] = "Acer $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[58] = parser; +parser = Object.create(null); +parser[0] = new RegExp("ALCATEL-([A-Za-z0-9]+)"); +parser[1] = "Alcatel $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[59] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Alcatel-([A-Za-z0-9]+)"); +parser[1] = "Alcatel $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[60] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Amoi\\-([A-Za-z0-9]+)"); +parser[1] = "Amoi $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[61] = parser; +parser = Object.create(null); +parser[0] = new RegExp("AMOI\\-([A-Za-z0-9]+)"); +parser[1] = "Amoi $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[62] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Asus\\-([A-Za-z0-9]+)"); +parser[1] = "Asus $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[63] = parser; +parser = Object.create(null); +parser[0] = new RegExp("ASUS\\-([A-Za-z0-9]+)"); +parser[1] = "Asus $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[64] = parser; +parser = Object.create(null); +parser[0] = new RegExp("BIRD\\-([A-Za-z0-9]+)"); +parser[1] = "Bird $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[65] = parser; +parser = Object.create(null); +parser[0] = new RegExp("BIRD\\.([A-Za-z0-9]+)"); +parser[1] = "Bird $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[66] = parser; +parser = Object.create(null); +parser[0] = new RegExp("BIRD ([A-Za-z0-9]+)"); +parser[1] = "Bird $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[67] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Dell ([A-Za-z0-9]+)"); +parser[1] = "Dell $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[68] = parser; +parser = Object.create(null); +parser[0] = new RegExp("DoCoMo/2\\.0 ([A-Za-z0-9]+)"); +parser[1] = "DoCoMo $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[69] = parser; +parser = Object.create(null); +parser[0] = new RegExp("([A-Za-z0-9]+)_W\\;FOMA"); +parser[1] = "DoCoMo $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[70] = parser; +parser = Object.create(null); +parser[0] = new RegExp("([A-Za-z0-9]+)\\;FOMA"); +parser[1] = "DoCoMo $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[71] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Huawei([A-Za-z0-9]+)"); +parser[1] = "Huawei $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[72] = parser; +parser = Object.create(null); +parser[0] = new RegExp("HUAWEI-([A-Za-z0-9]+)"); +parser[1] = "Huawei $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[73] = parser; +parser = Object.create(null); +parser[0] = new RegExp("vodafone([A-Za-z0-9]+)"); +parser[1] = "Huawei Vodafone $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[74] = parser; +parser = Object.create(null); +parser[0] = new RegExp("i\\-mate ([A-Za-z0-9]+)"); +parser[1] = "i-mate $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[75] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Kyocera\\-([A-Za-z0-9]+)"); +parser[1] = "Kyocera $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[76] = parser; +parser = Object.create(null); +parser[0] = new RegExp("KWC\\-([A-Za-z0-9]+)"); +parser[1] = "Kyocera $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[77] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Lenovo\\-([A-Za-z0-9]+)"); +parser[1] = "Lenovo $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[78] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Lenovo_([A-Za-z0-9]+)"); +parser[1] = "Lenovo $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[79] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LG/([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[80] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LG-LG([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[81] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LGE-LG([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[82] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LGE VX([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[83] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LG ([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[84] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LGE LG\\-AX([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[85] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LG\\-([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[86] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LGE\\-([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[87] = parser; +parser = Object.create(null); +parser[0] = new RegExp("LG([A-Za-z0-9]+)"); +parser[1] = "LG $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[88] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(KIN)\\.One (\\d+)\\.(\\d+)"); +parser[1] = "Microsoft $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[89] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(KIN)\\.Two (\\d+)\\.(\\d+)"); +parser[1] = "Microsoft $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[90] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Motorola)\\-([A-Za-z0-9]+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[91] = parser; +parser = Object.create(null); +parser[0] = new RegExp("MOTO\\-([A-Za-z0-9]+)"); +parser[1] = "Motorola $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[92] = parser; +parser = Object.create(null); +parser[0] = new RegExp("MOT\\-([A-Za-z0-9]+)"); +parser[1] = "Motorola $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[93] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Nintendo WiiU)"); +parser[1] = "Nintendo Wii U"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[94] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Nintendo (DS|3DS|DSi|Wii);"); +parser[1] = "Nintendo $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[95] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Pantech([A-Za-z0-9]+)"); +parser[1] = "Pantech $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[96] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Philips([A-Za-z0-9]+)"); +parser[1] = "Philips $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[97] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Philips ([A-Za-z0-9]+)"); +parser[1] = "Philips $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[98] = parser; +parser = Object.create(null); +parser[0] = new RegExp("SAMSUNG-([A-Za-z0-9\\-]+)"); +parser[1] = "Samsung $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[99] = parser; +parser = Object.create(null); +parser[0] = new RegExp("SAMSUNG\\; ([A-Za-z0-9\\-]+)"); +parser[1] = "Samsung $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[100] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Dreamcast"); +parser[1] = "Sega Dreamcast"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[101] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Softbank/1\\.0/([A-Za-z0-9]+)"); +parser[1] = "Softbank $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[102] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Softbank/2\\.0/([A-Za-z0-9]+)"); +parser[1] = "Softbank $1"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[103] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(WebTV)/(\\d+).(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[104] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(hiptop|avantgo|plucker|xiino|blazer|elaine|up.browser|up.link|mmp|smartphone|midp|wap|vodafone|o2|pocket|mobile|pda)"); +parser[1] = "Generic Smartphone"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[105] = parser; +parser = Object.create(null); +parser[0] = new RegExp("^(1207|3gso|4thp|501i|502i|503i|504i|505i|506i|6310|6590|770s|802s|a wa|acer|acs\\-|airn|alav|asus|attw|au\\-m|aur |aus |abac|acoo|aiko|alco|alca|amoi|anex|anny|anyw|aptu|arch|argo|bell|bird|bw\\-n|bw\\-u|beck|benq|bilb|blac|c55/|cdm\\-|chtm|capi|comp|cond|craw|dall|dbte|dc\\-s|dica|ds\\-d|ds12|dait|devi|dmob|doco|dopo|el49|erk0|esl8|ez40|ez60|ez70|ezos|ezze|elai|emul|eric|ezwa|fake|fly\\-|fly_|g\\-mo|g1 u|g560|gf\\-5|grun|gene|go.w|good|grad|hcit|hd\\-m|hd\\-p|hd\\-t|hei\\-|hp i|hpip|hs\\-c|htc |htc\\-|htca|htcg)"); +parser[1] = "Generic Feature Phone"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[106] = parser; +parser = Object.create(null); +parser[0] = new RegExp("^(htcp|htcs|htct|htc_|haie|hita|huaw|hutc|i\\-20|i\\-go|i\\-ma|i230|iac|iac\\-|iac/|ig01|im1k|inno|iris|jata|java|kddi|kgt|kgt/|kpt |kwc\\-|klon|lexi|lg g|lg\\-a|lg\\-b|lg\\-c|lg\\-d|lg\\-f|lg\\-g|lg\\-k|lg\\-l|lg\\-m|lg\\-o|lg\\-p|lg\\-s|lg\\-t|lg\\-u|lg\\-w|lg/k|lg/l|lg/u|lg50|lg54|lge\\-|lge/|lynx|leno|m1\\-w|m3ga|m50/|maui|mc01|mc21|mcca|medi|meri|mio8|mioa|mo01|mo02|mode|modo|mot |mot\\-|mt50|mtp1|mtv |mate|maxo|merc|mits|mobi|motv|mozz|n100|n101|n102|n202|n203|n300|n302|n500|n502|n505|n700|n701|n710|nec\\-|nem\\-|newg|neon)"); +parser[1] = "Generic Feature Phone"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[107] = parser; +parser = Object.create(null); +parser[0] = new RegExp("^(netf|noki|nzph|o2 x|o2\\-x|opwv|owg1|opti|oran|ot\\-s|p800|pand|pg\\-1|pg\\-2|pg\\-3|pg\\-6|pg\\-8|pg\\-c|pg13|phil|pn\\-2|pt\\-g|palm|pana|pire|pock|pose|psio|qa\\-a|qc\\-2|qc\\-3|qc\\-5|qc\\-7|qc07|qc12|qc21|qc32|qc60|qci\\-|qwap|qtek|r380|r600|raks|rim9|rove|s55/|sage|sams|sc01|sch\\-|scp\\-|sdk/|se47|sec\\-|sec0|sec1|semc|sgh\\-|shar|sie\\-|sk\\-0|sl45|slid|smb3|smt5|sp01|sph\\-|spv |spv\\-|sy01|samm|sany|sava|scoo|send|siem|smar|smit|soft|sony|t\\-mo|t218|t250|t600|t610|t618|tcl\\-|tdg\\-|telm|tim\\-|ts70|tsm\\-|tsm3|tsm5|tx\\-9|tagt)"); +parser[1] = "Generic Feature Phone"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[108] = parser; +parser = Object.create(null); +parser[0] = new RegExp("^(talk|teli|topl|tosh|up.b|upg1|utst|v400|v750|veri|vk\\-v|vk40|vk50|vk52|vk53|vm40|vx98|virg|vite|voda|vulc|w3c |w3c\\-|wapj|wapp|wapu|wapm|wig |wapi|wapr|wapv|wapy|wapa|waps|wapt|winc|winw|wonu|x700|xda2|xdag|yas\\-|your|zte\\-|zeto|aste|audi|avan|blaz|brew|brvw|bumb|ccwa|cell|cldc|cmd\\-|dang|eml2|fetc|hipt|http|ibro|idea|ikom|ipaq|jbro|jemu|jigs|keji|kyoc|kyok|libw|m\\-cr|midp|mmef|moto|mwbp|mywa|newt|nok6|o2im|pant|pdxg|play|pluc|port|prox|rozo|sama|seri|smal|symb|treo|upsi|vx52|vx53|vx60|vx61|vx70|vx80|vx81|vx83|vx85|wap\\-|webc|whit|wmlb|xda\\-|xda_)"); +parser[1] = "Generic Feature Phone"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[109] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(bot|borg|google(^tv)|yahoo|slurp|msnbot|msrbot|openbot|archiver|netresearch|lycos|scooter|altavista|teoma|gigabot|baiduspider|blitzbot|oegp|charlotte|furlbot|http%20client|polybot|htdig|ichiro|mogimogi|larbin|pompos|scrubby|searchsight|seekbot|semanticdiscovery|silk|snappy|speedy|spider|voila|vortex|voyager|zao|zeal|fast\\-webcrawler|converacrawler|dataparksearch|findlinks|crawler)"); +parser[1] = "Spider"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.device[110] = parser; + +exports.device.length = 111; + +exports.os = Object.create(null); + +parser = Object.create(null); +parser[0] = new RegExp("(Android) (\\d+)\\.(\\d+)(?:[.\\-]([a-z0-9]+))?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[0] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android)\\-(\\d+)\\.(\\d+)(?:[.\\-]([a-z0-9]+))?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[1] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Donut"); +parser[1] = 0; +parser[2] = "1"; +parser[3] = "2"; +parser[4] = 0; +exports.os[2] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Eclair"); +parser[1] = 0; +parser[2] = "2"; +parser[3] = "1"; +parser[4] = 0; +exports.os[3] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Froyo"); +parser[1] = 0; +parser[2] = "2"; +parser[3] = "2"; +parser[4] = 0; +exports.os[4] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Gingerbread"); +parser[1] = 0; +parser[2] = "2"; +parser[3] = "3"; +parser[4] = 0; +exports.os[5] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Android) Honeycomb"); +parser[1] = 0; +parser[2] = "3"; +parser[3] = 0; +parser[4] = 0; +exports.os[6] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Silk-Accelerated=[a-z]{4,5})"); +parser[1] = "Android"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[7] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows (?:NT 5\\.2|NT 5\\.1))"); +parser[1] = "Windows XP"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[8] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(XBLWP7)"); +parser[1] = "Windows Phone"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[9] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows NT 6\\.1)"); +parser[1] = "Windows 7"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[10] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows NT 6\\.0)"); +parser[1] = "Windows Vista"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[11] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Win 9x 4\\.90)"); +parser[1] = "Windows Me"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[12] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows 98|Windows XP|Windows ME|Windows 95|Windows CE|Windows 7|Windows NT 4\\.0|Windows Vista|Windows 2000|Windows 3.1)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[13] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows NT 6\\.2; ARM;)"); +parser[1] = "Windows RT"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[14] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows NT 6\\.2)"); +parser[1] = "Windows 8"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[15] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows NT 5\\.0)"); +parser[1] = "Windows 2000"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[16] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows Phone) (\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[17] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows Phone) OS (\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[18] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows ?Mobile)"); +parser[1] = "Windows Mobile"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[19] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(WinNT4.0)"); +parser[1] = "Windows NT 4.0"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[20] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Win98)"); +parser[1] = "Windows 98"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[21] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Tizen)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[22] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Mac OS X) (\\d+)[_.](\\d+)(?:[_.](\\d+))?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[23] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Mac_PowerPC"); +parser[1] = "Mac OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[24] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(?:PPC|Intel) (Mac OS X)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[25] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(CPU OS|iPhone OS) (\\d+)_(\\d+)(?:_(\\d+))?"); +parser[1] = "iOS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[26] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPhone|iPad|iPod); Opera"); +parser[1] = "iOS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[27] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(iPhone|iPad|iPod).*Mac OS X.*Version/(\\d+)\\.(\\d+)"); +parser[1] = "iOS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[28] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(AppleTV)/(\\d+)\\.(\\d+)"); +parser[1] = "ATV OS X"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[29] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(CrOS) [a-z0-9_]+ (\\d+)\\.(\\d+)(?:\\.(\\d+))?"); +parser[1] = "Chrome OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[30] = parser; +parser = Object.create(null); +parser[0] = new RegExp("([Dd]ebian)"); +parser[1] = "Debian"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[31] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Linux Mint)(?:/(\\d+))?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[32] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Mandriva)(?: Linux)?/(?:[\\d.-]+m[a-z]{2}(\\d+).(\\d))?"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[33] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Symbian[Oo][Ss])/(\\d+)\\.(\\d+)"); +parser[1] = "Symbian OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[34] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Symbian/3).+NokiaBrowser/7\\.3"); +parser[1] = "Symbian^3 Anna"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[35] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Symbian/3).+NokiaBrowser/7\\.4"); +parser[1] = "Symbian^3 Belle"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[36] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Symbian/3)"); +parser[1] = "Symbian^3"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[37] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Series 60|SymbOS|S60)"); +parser[1] = "Symbian OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[38] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(MeeGo)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[39] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Symbian [Oo][Ss]"); +parser[1] = "Symbian OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[40] = parser; +parser = Object.create(null); +parser[0] = new RegExp("Series40;"); +parser[1] = "Nokia Series 40"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[41] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(BB10);.+Version/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "BlackBerry OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[42] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Black[Bb]erry)[0-9a-z]+/(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.(\\d+))?"); +parser[1] = "BlackBerry OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[43] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Black[Bb]erry).+Version/(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.(\\d+))?"); +parser[1] = "BlackBerry OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[44] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(RIM Tablet OS) (\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "BlackBerry Tablet OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[45] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Play[Bb]ook)"); +parser[1] = "BlackBerry Tablet OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[46] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Black[Bb]erry)"); +parser[1] = "BlackBerry OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[47] = parser; +parser = Object.create(null); +parser[0] = new RegExp("\\(Mobile;.+Firefox/\\d+\\.\\d+"); +parser[1] = "Firefox OS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[48] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(BREW)[ /](\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[49] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(BREW);"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[50] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Brew MP|BMP)[ /](\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = "Brew MP"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[51] = parser; +parser = Object.create(null); +parser[0] = new RegExp("BMP;"); +parser[1] = "Brew MP"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[52] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(GoogleTV) (\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[53] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(GoogleTV)/[\\da-z]+"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[54] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(WebTV)/(\\d+).(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[55] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(hpw|web)OS/(\\d+)\\.(\\d+)(?:\\.(\\d+))?"); +parser[1] = "webOS"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[56] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(VRE);"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[57] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Fedora|Red Hat|PCLinuxOS)/(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[58] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Red Hat|Puppy|PCLinuxOS)/(\\d+)\\.(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[59] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Ubuntu|Kindle|Bada|Lubuntu|BackTrack|Red Hat|Slackware)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[60] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Windows|OpenBSD|FreeBSD|NetBSD|Android|WeTab)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[61] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Ubuntu|Kubuntu|Arch Linux|CentOS|Slackware|Gentoo|openSUSE|SUSE|Red Hat|Fedora|PCLinuxOS|Gentoo|Mageia)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[62] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Linux)/(\\d+)\\.(\\d+)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[63] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Linux|BSD)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[64] = parser; +parser = Object.create(null); +parser[0] = new RegExp("SunOS"); +parser[1] = "Solaris"; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[65] = parser; +parser = Object.create(null); +parser[0] = new RegExp("(Red Hat)"); +parser[1] = 0; +parser[2] = 0; +parser[3] = 0; +parser[4] = 0; +exports.os[66] = parser; + +exports.os.length = 67; \ No newline at end of file diff --git a/node_modules/useragent/lib/update.js b/node_modules/useragent/lib/update.js new file mode 100644 index 0000000..eb05092 --- /dev/null +++ b/node_modules/useragent/lib/update.js @@ -0,0 +1,202 @@ +'use strict'; + +/** + * Build in Native modules. + */ +var path = require('path') + , fs = require('fs') + , vm = require('vm'); + +/** + * Third party modules. + */ +var request = require('request') + , yaml = require('yamlparser'); + +exports.update = function update(callback) { + // Fetch the remote resource as that is frequently updated + request(exports.remote, function downloading(err, res, remote) { + if (err) return callback(err); + if (res.statusCode !== 200) return callback(new Error('Invalid statusCode returned')); + + // Also get some local additions that are missing from the source + fs.readFile(exports.local, 'utf8', function reading(err, local) { + if (err) return callback(err); + + // Parse the contents + exports.parse([ remote, local ], function parsing(err, results, source) { + callback(err, results); + + if (source && !err) { + fs.writeFile(exports.output, source, function idk(err) { + if (err) { + console.error('Failed to save the generated file due to reasons', err); + } + }); + } + }); + }); + }); +}; + +exports.parse = function parse(sources, callback) { + var results = {}; + + var data = sources.reduce(function parser(memo, data) { + // Try to repair some of the odd structures that are in the yaml files + // before parsing it so we generate a uniform structure: + + // Normalize the Operating system versions: + data = data.replace(/os_v([1-3])_replacement/gim, function replace(match, version) { + return 'v'+ version +'_replacement'; + }); + + // Make sure that we are able to parse the yaml string + try { data = yaml.eval(data); } + catch (e) { + callback(e); + callback = null; + return memo; + } + + // merge the data with the memo; + Object.keys(data).forEach(function (key) { + var results = data[key]; + memo[key] = memo[key] || []; + + for (var i = 0, l = results.length; i < l; i++) { + memo[key].push(results[i]); + } + }); + + return memo; + }, {}); + + [ + { + resource: 'user_agent_parsers' + , replacement: 'family_replacement' + , name: 'browser' + } + , { + resource: 'device_parsers' + , replacement: 'device_replacement' + , name: 'device' + } + , { + resource: 'os_parsers' + , replacement: 'os_replacement' + , name: 'os' + } + ].forEach(function parsing(details) { + results[details.resource] = results[details.resource] || []; + + var resources = data[details.resource] + , name = details.resource.replace('_parsers', '') + , resource + , parser; + + for (var i = 0, l = resources.length; i < l; i++) { + resource = resources[i]; + + // We need to JSON stringify the data to properly add slashes escape other + // kinds of crap in the RegularExpression. If we don't do thing we get + // some illegal token warnings. + parser = 'parser = Object.create(null);\n'; + parser += 'parser[0] = new RegExp('+ JSON.stringify(resource.regex) + ');\n'; + + // Check if we have replacement for the parsed family name + if (resource[details.replacement]) { + parser += 'parser[1] = "'+ resource[details.replacement].replace('"', '\\"') +'";'; + } else { + parser += 'parser[1] = 0;'; + } + + parser += '\n'; + + if (resource.v1_replacement) { + parser += 'parser[2] = "'+ resource.v1_replacement.replace('"', '\\"') +'";'; + } else { + parser += 'parser[2] = 0;'; + } + + parser += '\n'; + + if (resource.v2_replacement) { + parser += 'parser[3] = "'+ resource.v2_replacement.replace('"', '\\"') +'";'; + } else { + parser += 'parser[3] = 0;'; + } + + parser += '\n'; + + if (resource.v3_replacement) { + parser += 'parser[4] = "'+ resource.v3_replacement.replace('"', '\\"') +'";'; + } else { + parser += 'parser[4] = 0;'; + } + + parser += '\n'; + parser += 'exports.'+ details.name +'['+ i +'] = parser;'; + results[details.resource].push(parser); + } + }); + + // Generate a correct format + exports.generate(results, callback); +}; + +exports.generate = function generate(results, callback) { + var regexps = [ + 'var parser;' + , 'exports.browser = Object.create(null);' + , results.user_agent_parsers.join('\n') + , 'exports.browser.length = '+ results.user_agent_parsers.length +';' + + , 'exports.device = Object.create(null);' + , results.device_parsers.join('\n') + , 'exports.device.length = '+ results.device_parsers.length +';' + + , 'exports.os = Object.create(null);' + , results.os_parsers.join('\n') + , 'exports.os.length = '+ results.os_parsers.length +';' + ].join('\n\n'); + + // Now that we have generated the structure for the RegExps export file we + // need to validate that we created a JavaScript compatible file, if we would + // write the file without checking it's content we could be breaking the + // module. + var sandbox = { + exports: {} // Emulate a module context, so everything is attached here + }; + + // Crossing our fingers that it worked + try { vm.runInNewContext(regexps, sandbox, 'validating.vm'); } + catch (e) { return callback(e, null, regexps); } + + callback(undefined, sandbox.exports, regexps); +}; + +/** + * The location of the ua-parser regexes yaml file. + * + * @type {String} + * @api private + */ +exports.remote = 'https://raw.github.com/tobie/ua-parser/master/regexes.yaml'; + +/** + * The location of our local regexes yaml file. + * + * @type {String} + * @api private + */ +exports.local = path.resolve(__dirname, '..', 'static', 'user_agent.after.yaml'); + +/** + * The the output location for the generated regexps file + * + * @type {String} + * @api private + */ +exports.output = path.resolve(__dirname, '..', 'lib', 'regexps.js'); diff --git a/node_modules/useragent/node_modules/lru-cache/.npmignore b/node_modules/useragent/node_modules/lru-cache/.npmignore new file mode 100644 index 0000000..07e6e47 --- /dev/null +++ b/node_modules/useragent/node_modules/lru-cache/.npmignore @@ -0,0 +1 @@ +/node_modules diff --git a/node_modules/useragent/node_modules/lru-cache/AUTHORS b/node_modules/useragent/node_modules/lru-cache/AUTHORS new file mode 100644 index 0000000..016d7fb --- /dev/null +++ b/node_modules/useragent/node_modules/lru-cache/AUTHORS @@ -0,0 +1,8 @@ +# Authors, sorted by whether or not they are me +Isaac Z. Schlueter +Carlos Brito Lage +Marko Mikulicic +Trent Mick +Kevin O'Hara +Marco Rogers +Jesse Dailey diff --git a/node_modules/useragent/node_modules/lru-cache/LICENSE b/node_modules/useragent/node_modules/lru-cache/LICENSE new file mode 100644 index 0000000..05a4010 --- /dev/null +++ b/node_modules/useragent/node_modules/lru-cache/LICENSE @@ -0,0 +1,23 @@ +Copyright 2009, 2010, 2011 Isaac Z. Schlueter. +All rights reserved. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/useragent/node_modules/lru-cache/README.md b/node_modules/useragent/node_modules/lru-cache/README.md new file mode 100644 index 0000000..9aeb316 --- /dev/null +++ b/node_modules/useragent/node_modules/lru-cache/README.md @@ -0,0 +1,88 @@ +# lru cache + +A cache object that deletes the least-recently-used items. + +## Usage: + +```javascript +var LRU = require("lru-cache") + , options = { max: 500 + , length: function (n) { return n * 2 } + , dispose: function (key, n) { n.close() } + , maxAge: 1000 * 60 * 60 } + , cache = LRU(options) + , otherCache = LRU(50) // sets just the max size + +cache.set("key", "value") +cache.get("key") // "value" + +cache.reset() // empty the cache +``` + +If you put more stuff in it, then items will fall out. + +If you try to put an oversized thing in it, then it'll fall out right +away. + +## Options + +* `max` The maximum size of the cache, checked by applying the length + function to all values in the cache. Not setting this is kind of + silly, since that's the whole purpose of this lib, but it defaults + to `Infinity`. +* `maxAge` Maximum age in ms. Items are not pro-actively pruned out + as they age, but if you try to get an item that is too old, it'll + drop it and return undefined instead of giving it to you. +* `length` Function that is used to calculate the length of stored + items. If you're storing strings or buffers, then you probably want + to do something like `function(n){return n.length}`. The default is + `function(n){return 1}`, which is fine if you want to store `n` + like-sized things. +* `dispose` Function that is called on items when they are dropped + from the cache. This can be handy if you want to close file + descriptors or do other cleanup tasks when items are no longer + accessible. Called with `key, value`. It's called *before* + actually removing the item from the internal cache, so if you want + to immediately put it back in, you'll have to do that in a + `nextTick` or `setTimeout` callback or it won't do anything. +* `stale` By default, if you set a `maxAge`, it'll only actually pull + stale items out of the cache when you `get(key)`. (That is, it's + not pre-emptively doing a `setTimeout` or anything.) If you set + `stale:true`, it'll return the stale value before deleting it. If + you don't set this, then it'll return `undefined` when you try to + get a stale entry, as if it had already been deleted. + +## API + +* `set(key, value)` +* `get(key) => value` + + Both of these will update the "recently used"-ness of the key. + They do what you think. + +* `del(key)` + + Deletes a key out of the cache. + +* `reset()` + + Clear the cache entirely, throwing away all values. + +* `has(key)` + + Check if a key is in the cache, without updating the recent-ness + or deleting it for being stale. + +* `forEach(function(value,key,cache), [thisp])` + + Just like `Array.prototype.forEach`. Iterates over all the keys + in the cache, in order of recent-ness. (Ie, more recently used + items are iterated over first.) + +* `keys()` + + Return an array of the keys in the cache. + +* `values()` + + Return an array of the values in the cache. diff --git a/node_modules/useragent/node_modules/lru-cache/lib/lru-cache.js b/node_modules/useragent/node_modules/lru-cache/lib/lru-cache.js new file mode 100644 index 0000000..4ae51ac --- /dev/null +++ b/node_modules/useragent/node_modules/lru-cache/lib/lru-cache.js @@ -0,0 +1,242 @@ +;(function () { // closure for web browsers + +if (typeof module === 'object' && module.exports) { + module.exports = LRUCache +} else { + // just set the global for non-node platforms. + this.LRUCache = LRUCache +} + +function hOP (obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key) +} + +function naiveLength () { return 1 } + +function LRUCache (options) { + if (!(this instanceof LRUCache)) { + return new LRUCache(options) + } + + var max + if (typeof options === 'number') { + max = options + options = { max: max } + } + + if (!options) options = {} + + max = options.max + + var lengthCalculator = options.length || naiveLength + + if (typeof lengthCalculator !== "function") { + lengthCalculator = naiveLength + } + + if (!max || !(typeof max === "number") || max <= 0 ) { + // a little bit silly. maybe this should throw? + max = Infinity + } + + var allowStale = options.stale || false + + var maxAge = options.maxAge || null + + var dispose = options.dispose + + var cache = Object.create(null) // hash of items by key + , lruList = Object.create(null) // list of items in order of use recency + , mru = 0 // most recently used + , lru = 0 // least recently used + , length = 0 // number of items in the list + , itemCount = 0 + + + // resize the cache when the max changes. + Object.defineProperty(this, "max", + { set : function (mL) { + if (!mL || !(typeof mL === "number") || mL <= 0 ) mL = Infinity + max = mL + // if it gets above double max, trim right away. + // otherwise, do it whenever it's convenient. + if (length > max) trim() + } + , get : function () { return max } + , enumerable : true + }) + + // resize the cache when the lengthCalculator changes. + Object.defineProperty(this, "lengthCalculator", + { set : function (lC) { + if (typeof lC !== "function") { + lengthCalculator = naiveLength + length = itemCount + for (var key in cache) { + cache[key].length = 1 + } + } else { + lengthCalculator = lC + length = 0 + for (var key in cache) { + cache[key].length = lengthCalculator(cache[key].value) + length += cache[key].length + } + } + + if (length > max) trim() + } + , get : function () { return lengthCalculator } + , enumerable : true + }) + + Object.defineProperty(this, "length", + { get : function () { return length } + , enumerable : true + }) + + + Object.defineProperty(this, "itemCount", + { get : function () { return itemCount } + , enumerable : true + }) + + this.forEach = function (fn, thisp) { + thisp = thisp || this + var i = 0; + for (var k = mru - 1; k >= 0 && i < itemCount; k--) if (lruList[k]) { + i++ + var hit = lruList[k] + fn.call(thisp, hit.value, hit.key, this) + } + } + + this.keys = function () { + var keys = new Array(itemCount) + var i = 0 + for (var k = mru - 1; k >= 0 && i < itemCount; k--) if (lruList[k]) { + var hit = lruList[k] + keys[i++] = hit.key + } + return keys + } + + this.values = function () { + var values = new Array(itemCount) + var i = 0 + for (var k = mru - 1; k >= 0 && i < itemCount; k--) if (lruList[k]) { + var hit = lruList[k] + values[i++] = hit.value + } + return values + } + + this.reset = function () { + if (dispose) { + for (var k in cache) { + dispose(k, cache[k].value) + } + } + cache = {} + lruList = {} + lru = 0 + mru = 0 + length = 0 + itemCount = 0 + } + + // Provided for debugging/dev purposes only. No promises whatsoever that + // this API stays stable. + this.dump = function () { + return cache + } + + this.dumpLru = function () { + return lruList + } + + this.set = function (key, value) { + if (hOP(cache, key)) { + // dispose of the old one before overwriting + if (dispose) dispose(key, cache[key].value) + if (maxAge) cache[key].now = Date.now() + cache[key].value = value + this.get(key) + return true + } + + var len = lengthCalculator(value) + var age = maxAge ? Date.now() : 0 + var hit = new Entry(key, value, mru++, len, age) + + // oversized objects fall out of cache automatically. + if (hit.length > max) { + if (dispose) dispose(key, value) + return false + } + + length += hit.length + lruList[hit.lu] = cache[key] = hit + itemCount ++ + + if (length > max) trim() + return true + } + + this.has = function (key) { + if (!hOP(cache, key)) return false + var hit = cache[key] + if (maxAge && (Date.now() - hit.now > maxAge)) { + return false + } + return true + } + + this.get = function (key) { + if (!hOP(cache, key)) return + var hit = cache[key] + if (maxAge && (Date.now() - hit.now > maxAge)) { + this.del(key) + return allowStale ? hit.value : undefined + } + shiftLU(hit) + hit.lu = mru ++ + lruList[hit.lu] = hit + return hit.value + } + + this.del = function (key) { + del(cache[key]) + } + + function trim () { + while (lru < mru && length > max) + del(lruList[lru]) + } + + function shiftLU(hit) { + delete lruList[ hit.lu ] + while (lru < mru && !lruList[lru]) lru ++ + } + + function del(hit) { + if (hit) { + if (dispose) dispose(hit.key, hit.value) + length -= hit.length + itemCount -- + delete cache[ hit.key ] + shiftLU(hit) + } + } +} + +// classy, since V8 prefers predictable objects. +function Entry (key, value, mru, len, age) { + this.key = key + this.value = value + this.lu = mru + this.length = len + this.now = age +} + +})() diff --git a/node_modules/useragent/node_modules/lru-cache/package.json b/node_modules/useragent/node_modules/lru-cache/package.json new file mode 100644 index 0000000..7a1a333 --- /dev/null +++ b/node_modules/useragent/node_modules/lru-cache/package.json @@ -0,0 +1,66 @@ +{ + "name": "lru-cache", + "description": "A cache object that deletes the least-recently-used items.", + "version": "2.2.4", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + "scripts": { + "test": "tap test --gc" + }, + "main": "lib/lru-cache.js", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/node-lru-cache.git" + }, + "devDependencies": { + "tap": "", + "weak": "" + }, + "license": { + "type": "MIT", + "url": "http://github.com/isaacs/node-lru-cache/raw/master/LICENSE" + }, + "contributors": [ + { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + { + "name": "Carlos Brito Lage", + "email": "carlos@carloslage.net" + }, + { + "name": "Marko Mikulicic", + "email": "marko.mikulicic@isti.cnr.it" + }, + { + "name": "Trent Mick", + "email": "trentm@gmail.com" + }, + { + "name": "Kevin O'Hara", + "email": "kevinohara80@gmail.com" + }, + { + "name": "Marco Rogers", + "email": "marco.rogers@gmail.com" + }, + { + "name": "Jesse Dailey", + "email": "jesse.dailey@gmail.com" + } + ], + "readme": "# lru cache\n\nA cache object that deletes the least-recently-used items.\n\n## Usage:\n\n```javascript\nvar LRU = require(\"lru-cache\")\n , options = { max: 500\n , length: function (n) { return n * 2 }\n , dispose: function (key, n) { n.close() }\n , maxAge: 1000 * 60 * 60 }\n , cache = LRU(options)\n , otherCache = LRU(50) // sets just the max size\n\ncache.set(\"key\", \"value\")\ncache.get(\"key\") // \"value\"\n\ncache.reset() // empty the cache\n```\n\nIf you put more stuff in it, then items will fall out.\n\nIf you try to put an oversized thing in it, then it'll fall out right\naway.\n\n## Options\n\n* `max` The maximum size of the cache, checked by applying the length\n function to all values in the cache. Not setting this is kind of\n silly, since that's the whole purpose of this lib, but it defaults\n to `Infinity`.\n* `maxAge` Maximum age in ms. Items are not pro-actively pruned out\n as they age, but if you try to get an item that is too old, it'll\n drop it and return undefined instead of giving it to you.\n* `length` Function that is used to calculate the length of stored\n items. If you're storing strings or buffers, then you probably want\n to do something like `function(n){return n.length}`. The default is\n `function(n){return 1}`, which is fine if you want to store `n`\n like-sized things.\n* `dispose` Function that is called on items when they are dropped\n from the cache. This can be handy if you want to close file\n descriptors or do other cleanup tasks when items are no longer\n accessible. Called with `key, value`. It's called *before*\n actually removing the item from the internal cache, so if you want\n to immediately put it back in, you'll have to do that in a\n `nextTick` or `setTimeout` callback or it won't do anything.\n* `stale` By default, if you set a `maxAge`, it'll only actually pull\n stale items out of the cache when you `get(key)`. (That is, it's\n not pre-emptively doing a `setTimeout` or anything.) If you set\n `stale:true`, it'll return the stale value before deleting it. If\n you don't set this, then it'll return `undefined` when you try to\n get a stale entry, as if it had already been deleted.\n\n## API\n\n* `set(key, value)`\n* `get(key) => value`\n\n Both of these will update the \"recently used\"-ness of the key.\n They do what you think.\n\n* `del(key)`\n\n Deletes a key out of the cache.\n\n* `reset()`\n\n Clear the cache entirely, throwing away all values.\n\n* `has(key)`\n\n Check if a key is in the cache, without updating the recent-ness\n or deleting it for being stale.\n\n* `forEach(function(value,key,cache), [thisp])`\n\n Just like `Array.prototype.forEach`. Iterates over all the keys\n in the cache, in order of recent-ness. (Ie, more recently used\n items are iterated over first.)\n\n* `keys()`\n\n Return an array of the keys in the cache.\n\n* `values()`\n\n Return an array of the values in the cache.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/node-lru-cache/issues" + }, + "_id": "lru-cache@2.2.4", + "dist": { + "shasum": "db15c625de5423a101fa69751bd460ad8d51250f" + }, + "_from": "lru-cache@2.2.x", + "_resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz" +} diff --git a/node_modules/useragent/node_modules/lru-cache/s.js b/node_modules/useragent/node_modules/lru-cache/s.js new file mode 100644 index 0000000..c2a9e54 --- /dev/null +++ b/node_modules/useragent/node_modules/lru-cache/s.js @@ -0,0 +1,25 @@ +var LRU = require('lru-cache'); + +var max = +process.argv[2] || 10240; +var more = 1024; + +var cache = LRU({ + max: max, maxAge: 86400e3 +}); + +// fill cache +for (var i = 0; i < max; ++i) { + cache.set(i, {}); +} + +var start = process.hrtime(); + +// adding more items +for ( ; i < max+more; ++i) { + cache.set(i, {}); +} + +var end = process.hrtime(start); +var msecs = end[0] * 1E3 + end[1] / 1E6; + +console.log('adding %d items took %d ms', more, msecs.toPrecision(5)); diff --git a/node_modules/useragent/node_modules/lru-cache/test/basic.js b/node_modules/useragent/node_modules/lru-cache/test/basic.js new file mode 100644 index 0000000..55d5263 --- /dev/null +++ b/node_modules/useragent/node_modules/lru-cache/test/basic.js @@ -0,0 +1,317 @@ +var test = require("tap").test + , LRU = require("../") + +test("basic", function (t) { + var cache = new LRU({max: 10}) + cache.set("key", "value") + t.equal(cache.get("key"), "value") + t.equal(cache.get("nada"), undefined) + t.equal(cache.length, 1) + t.equal(cache.max, 10) + t.end() +}) + +test("least recently set", function (t) { + var cache = new LRU(2) + cache.set("a", "A") + cache.set("b", "B") + cache.set("c", "C") + t.equal(cache.get("c"), "C") + t.equal(cache.get("b"), "B") + t.equal(cache.get("a"), undefined) + t.end() +}) + +test("lru recently gotten", function (t) { + var cache = new LRU(2) + cache.set("a", "A") + cache.set("b", "B") + cache.get("a") + cache.set("c", "C") + t.equal(cache.get("c"), "C") + t.equal(cache.get("b"), undefined) + t.equal(cache.get("a"), "A") + t.end() +}) + +test("del", function (t) { + var cache = new LRU(2) + cache.set("a", "A") + cache.del("a") + t.equal(cache.get("a"), undefined) + t.end() +}) + +test("max", function (t) { + var cache = new LRU(3) + + // test changing the max, verify that the LRU items get dropped. + cache.max = 100 + for (var i = 0; i < 100; i ++) cache.set(i, i) + t.equal(cache.length, 100) + for (var i = 0; i < 100; i ++) { + t.equal(cache.get(i), i) + } + cache.max = 3 + t.equal(cache.length, 3) + for (var i = 0; i < 97; i ++) { + t.equal(cache.get(i), undefined) + } + for (var i = 98; i < 100; i ++) { + t.equal(cache.get(i), i) + } + + // now remove the max restriction, and try again. + cache.max = "hello" + for (var i = 0; i < 100; i ++) cache.set(i, i) + t.equal(cache.length, 100) + for (var i = 0; i < 100; i ++) { + t.equal(cache.get(i), i) + } + // should trigger an immediate resize + cache.max = 3 + t.equal(cache.length, 3) + for (var i = 0; i < 97; i ++) { + t.equal(cache.get(i), undefined) + } + for (var i = 98; i < 100; i ++) { + t.equal(cache.get(i), i) + } + t.end() +}) + +test("reset", function (t) { + var cache = new LRU(10) + cache.set("a", "A") + cache.set("b", "B") + cache.reset() + t.equal(cache.length, 0) + t.equal(cache.max, 10) + t.equal(cache.get("a"), undefined) + t.equal(cache.get("b"), undefined) + t.end() +}) + + +// Note: `.dump()` is a debugging tool only. No guarantees are made +// about the format/layout of the response. +test("dump", function (t) { + var cache = new LRU(10) + var d = cache.dump(); + t.equal(Object.keys(d).length, 0, "nothing in dump for empty cache") + cache.set("a", "A") + var d = cache.dump() // { a: { key: "a", value: "A", lu: 0 } } + t.ok(d.a) + t.equal(d.a.key, "a") + t.equal(d.a.value, "A") + t.equal(d.a.lu, 0) + + cache.set("b", "B") + cache.get("b") + d = cache.dump() + t.ok(d.b) + t.equal(d.b.key, "b") + t.equal(d.b.value, "B") + t.equal(d.b.lu, 2) + + t.end() +}) + + +test("basic with weighed length", function (t) { + var cache = new LRU({ + max: 100, + length: function (item) { return item.size } + }) + cache.set("key", {val: "value", size: 50}) + t.equal(cache.get("key").val, "value") + t.equal(cache.get("nada"), undefined) + t.equal(cache.lengthCalculator(cache.get("key")), 50) + t.equal(cache.length, 50) + t.equal(cache.max, 100) + t.end() +}) + + +test("weighed length item too large", function (t) { + var cache = new LRU({ + max: 10, + length: function (item) { return item.size } + }) + t.equal(cache.max, 10) + + // should fall out immediately + cache.set("key", {val: "value", size: 50}) + + t.equal(cache.length, 0) + t.equal(cache.get("key"), undefined) + t.end() +}) + +test("least recently set with weighed length", function (t) { + var cache = new LRU({ + max:8, + length: function (item) { return item.length } + }) + cache.set("a", "A") + cache.set("b", "BB") + cache.set("c", "CCC") + cache.set("d", "DDDD") + t.equal(cache.get("d"), "DDDD") + t.equal(cache.get("c"), "CCC") + t.equal(cache.get("b"), undefined) + t.equal(cache.get("a"), undefined) + t.end() +}) + +test("lru recently gotten with weighed length", function (t) { + var cache = new LRU({ + max: 8, + length: function (item) { return item.length } + }) + cache.set("a", "A") + cache.set("b", "BB") + cache.set("c", "CCC") + cache.get("a") + cache.get("b") + cache.set("d", "DDDD") + t.equal(cache.get("c"), undefined) + t.equal(cache.get("d"), "DDDD") + t.equal(cache.get("b"), "BB") + t.equal(cache.get("a"), "A") + t.end() +}) + +test("set returns proper booleans", function(t) { + var cache = new LRU({ + max: 5, + length: function (item) { return item.length } + }) + + t.equal(cache.set("a", "A"), true) + + // should return false for max exceeded + t.equal(cache.set("b", "donuts"), false) + + t.equal(cache.set("b", "B"), true) + t.equal(cache.set("c", "CCCC"), true) + t.end() +}) + +test("drop the old items", function(t) { + var cache = new LRU({ + max: 5, + maxAge: 50 + }) + + cache.set("a", "A") + + setTimeout(function () { + cache.set("b", "b") + t.equal(cache.get("a"), "A") + }, 25) + + setTimeout(function () { + cache.set("c", "C") + // timed out + t.notOk(cache.get("a")) + }, 60) + + setTimeout(function () { + t.notOk(cache.get("b")) + t.equal(cache.get("c"), "C") + }, 90) + + setTimeout(function () { + t.notOk(cache.get("c")) + t.end() + }, 155) +}) + +test("disposal function", function(t) { + var disposed = false + var cache = new LRU({ + max: 1, + dispose: function (k, n) { + disposed = n + } + }) + + cache.set(1, 1) + cache.set(2, 2) + t.equal(disposed, 1) + cache.set(3, 3) + t.equal(disposed, 2) + cache.reset() + t.equal(disposed, 3) + t.end() +}) + +test("disposal function on too big of item", function(t) { + var disposed = false + var cache = new LRU({ + max: 1, + length: function (k) { + return k.length + }, + dispose: function (k, n) { + disposed = n + } + }) + var obj = [ 1, 2 ] + + t.equal(disposed, false) + cache.set("obj", obj) + t.equal(disposed, obj) + t.end() +}) + +test("has()", function(t) { + var cache = new LRU({ + max: 1, + maxAge: 10 + }) + + cache.set('foo', 'bar') + t.equal(cache.has('foo'), true) + cache.set('blu', 'baz') + t.equal(cache.has('foo'), false) + t.equal(cache.has('blu'), true) + setTimeout(function() { + t.equal(cache.has('blu'), false) + t.end() + }, 15) +}) + +test("stale", function(t) { + var cache = new LRU({ + maxAge: 10, + stale: true + }) + + cache.set('foo', 'bar') + t.equal(cache.get('foo'), 'bar') + t.equal(cache.has('foo'), true) + setTimeout(function() { + t.equal(cache.has('foo'), false) + t.equal(cache.get('foo'), 'bar') + t.equal(cache.get('foo'), undefined) + t.end() + }, 15) +}) + +test("lru update via set", function(t) { + var cache = LRU({ max: 2 }); + + cache.set('foo', 1); + cache.set('bar', 2); + cache.del('bar'); + cache.set('baz', 3); + cache.set('qux', 4); + + t.equal(cache.get('foo'), undefined) + t.equal(cache.get('bar'), undefined) + t.equal(cache.get('baz'), 3) + t.equal(cache.get('qux'), 4) + t.end() +}) diff --git a/node_modules/useragent/node_modules/lru-cache/test/foreach.js b/node_modules/useragent/node_modules/lru-cache/test/foreach.js new file mode 100644 index 0000000..eefb80d --- /dev/null +++ b/node_modules/useragent/node_modules/lru-cache/test/foreach.js @@ -0,0 +1,52 @@ +var test = require('tap').test +var LRU = require('../') + +test('forEach', function (t) { + var l = new LRU(5) + for (var i = 0; i < 10; i ++) { + l.set(i.toString(), i.toString(2)) + } + + var i = 9 + l.forEach(function (val, key, cache) { + t.equal(cache, l) + t.equal(key, i.toString()) + t.equal(val, i.toString(2)) + i -= 1 + }) + + // get in order of most recently used + l.get(6) + l.get(8) + + var order = [ 8, 6, 9, 7, 5 ] + var i = 0 + + l.forEach(function (val, key, cache) { + var j = order[i ++] + t.equal(cache, l) + t.equal(key, j.toString()) + t.equal(val, j.toString(2)) + }) + + t.end() +}) + +test('keys() and values()', function (t) { + var l = new LRU(5) + for (var i = 0; i < 10; i ++) { + l.set(i.toString(), i.toString(2)) + } + + t.similar(l.keys(), ['9', '8', '7', '6', '5']) + t.similar(l.values(), ['1001', '1000', '111', '110', '101']) + + // get in order of most recently used + l.get(6) + l.get(8) + + t.similar(l.keys(), ['8', '6', '9', '7', '5']) + t.similar(l.values(), ['1000', '110', '1001', '111', '101']) + + t.end() +}) diff --git a/node_modules/useragent/node_modules/lru-cache/test/memory-leak.js b/node_modules/useragent/node_modules/lru-cache/test/memory-leak.js new file mode 100644 index 0000000..7af45b0 --- /dev/null +++ b/node_modules/useragent/node_modules/lru-cache/test/memory-leak.js @@ -0,0 +1,50 @@ +#!/usr/bin/env node --expose_gc + +var weak = require('weak'); +var test = require('tap').test +var LRU = require('../') +var l = new LRU({ max: 10 }) +var refs = 0 +function X() { + refs ++ + weak(this, deref) +} + +function deref() { + refs -- +} + +test('no leaks', function (t) { + // fill up the cache + for (var i = 0; i < 100; i++) { + l.set(i, new X); + // throw some gets in there, too. + if (i % 2 === 0) + l.get(i / 2) + } + + gc() + + var start = process.memoryUsage() + + // capture the memory + var startRefs = refs + + // do it again, but more + for (var i = 0; i < 10000; i++) { + l.set(i, new X); + // throw some gets in there, too. + if (i % 2 === 0) + l.get(i / 2) + } + + gc() + + var end = process.memoryUsage() + t.equal(refs, startRefs, 'no leaky refs') + + console.error('start: %j\n' + + 'end: %j', start, end); + t.pass(); + t.end(); +}) diff --git a/node_modules/useragent/package.json b/node_modules/useragent/package.json new file mode 100644 index 0000000..3f08f75 --- /dev/null +++ b/node_modules/useragent/package.json @@ -0,0 +1,72 @@ +{ + "name": "useragent", + "version": "2.0.7", + "description": "Fastest, most accurate & effecient user agent string parser, uses Browserscope's research for parsing", + "author": { + "name": "Arnout Kazemier" + }, + "main": "./index.js", + "keywords": [ + "agent", + "browser", + "browserscope", + "os", + "parse", + "parser", + "ua", + "ua-parse", + "ua-parser", + "user agent", + "user", + "user-agent", + "useragent", + "version" + ], + "maintainers": [ + { + "name": "Arnout Kazemier", + "email": "info@3rd-Eden.com", + "url": "http://www.3rd-Eden.com" + } + ], + "license": { + "type": "MIT", + "url": "https://github.com/3rd-Eden/useragent/blob/master/LICENSE" + }, + "repository": { + "type": "git", + "url": "http://github.com/3rd-Eden/useragent.git" + }, + "devDependencies": { + "should": "*", + "mocha": "*", + "long-stack-traces": "0.1.x", + "yamlparser": "0.0.x", + "request": "2.9.x", + "semver": "1.0.x", + "pre-commit": "0.0.x" + }, + "pre-commit": [ + "test", + "update" + ], + "scripts": { + "test": "mocha $(find test -name '*.test.js')", + "qa": "mocha --ui exports $(find test -name '*.qa.js')", + "update": "node ./bin/update.js" + }, + "dependencies": { + "lru-cache": "2.2.x" + }, + "readme": "# useragent - high performance user agent parser for Node.js\n\nUseragent originated as port of [browserscope.org][browserscope]'s user agent\nparser project also known as ua-parser. Useragent allows you to parse user agent\nstring with high accuracy by using hand tuned dedicated regular expressions for\nbrowser matching. This database is needed to ensure that every browser is\ncorrectly parsed as every browser vendor implements it's own user agent schema.\nThis is why regular user agent parsers have major issues because they will\nmost likely parse out the wrong browser name or confuse the render engine version\nwith the actual version of the browser.\n\n---\n\n### Build status [![BuildStatus](https://secure.travis-ci.org/3rd-Eden/useragent.png?branch=master)](http://travis-ci.org/3rd-Eden/useragent)\n\n---\n\n### High performance\n\nThe module has been developed with a benchmark driven approach. It has a\npre-compiled library that contains all the Regular Expressions and uses deferred\nor on demand parsing for Operating System and device information. All this\nengineering effort has been worth it as [this benchmark shows][benchmark]:\n\n```\nStarting the benchmark, parsing 62 useragent strings per run\n\nExecuted benchmark against node module: \"useragent\"\nCount (61), Cycles (5), Elapsed (5.559), Hz (1141.3739447904327)\n\nExecuted benchmark against node module: \"useragent_parser\"\nCount (29), Cycles (3), Elapsed (5.448), Hz (545.6817291171243)\n\nExecuted benchmark against node module: \"useragent-parser\"\nCount (16), Cycles (4), Elapsed (5.48), Hz (304.5373431830105)\n\nExecuted benchmark against node module: \"ua-parser\"\nCount (54), Cycles (3), Elapsed (5.512), Hz (1018.7561434659247)\n\nModule: \"useragent\" is the user agent fastest parser.\n```\n\n---\n\n### Installation\n\nInstallation is done using the Node Package Manager (NPM). If you don't have\nNPM installed on your system you can download it from\n[npmjs.org][npm]\n\n```\nnpm install useragent --save\n```\n\nThe `--save` flag tells NPM to automatically add it to your `package.json` file.\n\n---\n\n### API\n\n\nInclude the `useragent` parser in you node.js application:\n\n```js\nvar useragent = require('useragent');\n```\n\nThe `useragent` library allows you do use the automatically installed RegExp\nlibrary or you can fetch it live from the remote servers. So if you are\nparanoid and always want your RegExp library to be up to date to match with\nagent the widest range of `useragent` strings you can do:\n\n```js\nvar useragent = require('useragent');\nuseragent(true);\n```\n\nThis will async load the database from the server and compile it to a proper\nJavaScript supported format. If it fails to compile or load it from the remote\nlocation it will just fall back silently to the shipped version. If you want to\nuse this feature you need to add `yamlparser` and `request` to your package.json\n\n```\nnpm install yamlparser --save\nnpm install request --save\n```\n\n#### useragent.parse(useragent string[, js useragent]);\n\nThis is the actual user agent parser, this is where all the magic is happening.\nThe function accepts 2 arguments, both should be a `string`. The first argument\nshould the user agent string that is known on the server from the\n`req.headers.useragent` header. The other argument is optional and should be\nthe user agent string that you see in the browser, this can be send from the\nbrowser using a xhr request or something like this. This allows you detect if\nthe user is browsing the web using the `Chrome Frame` extension.\n\nThe parser returns a Agent instance, this allows you to output user agent\ninformation in different predefined formats. See the Agent section for more\ninformation.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\n\n// example for parsing both the useragent header and a optional js useragent\nvar agent2 = useragent.parse(req.headers['user-agent'], req.query.jsuseragent);\n```\n\nThe parse method returns a `Agent` instance which contains all details about the\nuser agent. See the Agent section of the API documentation for the available\nmethods.\n\n#### useragent.lookup(useragent string[, js useragent]);\n\nThis provides the same functionality as above, but it caches the user agent\nstring and it's parsed result in memory to provide faster lookups in the\nfuture. This can be handy if you expect to parse a lot of user agent strings.\n\nIt uses the same arguments as the `useragent.parse` method and returns exactly\nthe same result, but it's just cached.\n\n```js\nvar agent = useragent.lookup(req.headers['user-agent']);\n```\n\nAnd this is a serious performance improvement as shown in this benchmark:\n\n```\nExecuted benchmark against method: \"useragent.parse\"\nCount (49), Cycles (3), Elapsed (5.534), Hz (947.6844321931629)\n\nExecuted benchmark against method: \"useragent.lookup\"\nCount (11758), Cycles (3), Elapsed (5.395), Hz (229352.03831239208)\n```\n\n#### useragent.fromJSON(obj);\n\nTransforms the JSON representation of a `Agent` instance back in to a working\n`Agent` instance\n\n```js\nvar agent = useragent.parse(req.headers['user-agent'])\n , another = useragent.fromJSON(JSON.stringify(agent));\n\nconsole.log(agent == another);\n```\n\n#### useragent.is(useragent string).browsername;\n\nThis api provides you with a quick and dirty browser lookup. The underlying\ncode is usually found on client side scripts so it's not the same quality as\nour `useragent.parse` method but it might be needed for legacy reasons.\n\n`useragent.is` returns a object with potential matched browser names\n\n```js\nuseragent.is(req.headers['user-agent']).firefox // true\nuseragent.is(req.headers['user-agent']).safari // false\nvar ua = useragent.is(req.headers['user-agent'])\n\n// the object\n{\n version: '3'\n webkit: false\n opera: false\n ie: false\n chrome: false\n safari: false\n mobile_safari: false\n firefox: true\n}\n```\n\n---\n\n### Agents, OperatingSystem and Device instances\n\nMost of the methods mentioned above return a Agent instance. The Agent exposes\nthe parsed out information from the user agent strings. This allows us to\nextend the agent with more methods that do not necessarily need to be in the\ncore agent instance, allowing us to expose a plugin interface for third party\ndevelopers and at the same time create a uniform interface for all versioning.\n\nThe Agent has the following property\n\n- `family` The browser family, or browser name, it defaults to Other.\n- `major` The major version number of the family, it defaults to 0.\n- `minor` The minor version number of the family, it defaults to 0.\n- `patch` The patch version number of the family, it defaults to 0.\n\nIn addition to the properties mentioned above, it also has 2 special properties,\nwhich are:\n\n- `os` OperatingSystem instance\n- `device` Device instance\n\nWhen you access those 2 properties the agent will do on demand parsing of the\nOperating System or/and Device information.\n\nThe OperatingSystem has the same properties as the Agent, for the Device we\ndon't have any versioning information available, so only the `family` property is\nset there. If we cannot find the family, they will default to `Other`.\n\nThe following methods are available:\n\n#### Agent.toAgent();\n\nReturns the family and version number concatinated in a nice human readable\nstring.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.toAgent(); // 'Chrome 15.0.874'\n```\n\n#### Agent.toString();\n\nReturns the results of the `Agent.toAgent()` but also adds the parsed operating\nsystem to the string in a human readable format.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.toString(); // 'Chrome 15.0.874 / Mac OS X 10.8.1'\n\n// as it's a to string method you can also concat it with another string\n'your useragent is ' + agent;\n// 'your useragent is Chrome 15.0.874 / Mac OS X 10.8.1'\n```\n#### Agent.toVersion();\n\nReturns the version of the browser in a human readable string.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.toVersion(); // '15.0.874'\n```\n\n#### Agent.toJSON();\n\nGenerates a JSON representation of the Agent. By using the `toJSON` method we\nautomatically allow it to be stringified when supplying as to the\n`JSON.stringify` method.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.toJSON(); // returns an object\n\nJSON.stringify(agent);\n```\n\n#### OperatingSystem.toString();\n\nGenerates a stringified version of operating system;\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.os.toString(); // 'Mac OSX 10.8.1'\n```\n\n#### OperatingSystem.toVersion();\n\nGenerates a stringified version of operating system's version;\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.os.toVersion(); // '10.8.1'\n```\n\n#### OperatingSystem.toJSON();\n\nGenerates a JSON representation of the OperatingSystem. By using the `toJSON`\nmethod we automatically allow it to be stringified when supplying as to the\n`JSON.stringify` method.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.os.toJSON(); // returns an object\n\nJSON.stringify(agent.os);\n```\n\n#### Device.toString();\n\nGenerates a stringified version of device;\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.device.toString(); // 'Asus A100'\n```\n\n#### Device.toVersion();\n\nGenerates a stringified version of device's version;\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.device.toVersion(); // '' , no version found but could also be '0.0.0'\n```\n\n#### Device.toJSON();\n\nGenerates a JSON representation of the Device. By using the `toJSON` method we\nautomatically allow it to be stringified when supplying as to the\n`JSON.stringify` method.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.device.toJSON(); // returns an object\n\nJSON.stringify(agent.device);\n```\n\n### Adding more features to the useragent\n\nAs I wanted to keep the core of the user agent parser as clean and fast as\npossible I decided to move some of the initially planned features to a new\n`plugin` file.\n\nThese extensions to the Agent prototype can be loaded by requiring the\n`useragent/features` file:\n\n```js\nvar useragent = require('useragent');\nrequire('useragent/features');\n```\n\nThe initial release introduces 1 new method, satisfies, which allows you to see\nif the version number of the browser satisfies a certain range. It uses the\nsemver library to do all the range calculations but here is a small summary of\nthe supported range styles:\n\n* `>1.2.3` Greater than a specific version.\n* `<1.2.3` Less than.\n* `1.2.3 - 2.3.4` := `>=1.2.3 <=2.3.4`.\n* `~1.2.3` := `>=1.2.3 <1.3.0`.\n* `~1.2` := `>=1.2.0 <2.0.0`.\n* `~1` := `>=1.0.0 <2.0.0`.\n* `1.2.x` := `>=1.2.0 <1.3.0`.\n* `1.x` := `>=1.0.0 <2.0.0`.\n\nAs it requires the `semver` module to function you need to install it\nseperately:\n\n```\nnpm install semver --save\n```\n\n#### Agent.satisfies('range style here');\n\nCheck if the agent matches the supplied range.\n\n```js\nvar agent = useragent.parse(req.headers['user-agent']);\nagent.satisfies('15.x || >=19.5.0 || 25.0.0 - 17.2.3'); // true\nagent.satisfies('>16.12.0'); // false\n```\n---\n\n### Migrations\n\nFor small changes between version please review the [changelog][changelog].\n\n#### Upgrading from 1.10 to 2.0.0\n\n- `useragent.fromAgent` has been removed.\n- `agent.toJSON` now returns an Object, use `JSON.stringify(agent)` for the old\n behaviour.\n- `agent.os` is now an `OperatingSystem` instance with version numbers. If you\n still a string only representation do `agent.os.toString()`.\n- `semver` has been removed from the dependencies, so if you are using the\n `require('useragent/features')` you need to add it to your own dependencies\n\n#### Upgrading from 0.1.2 to 1.0.0\n\n- `useragent.browser(ua)` has been renamed to `useragent.is(ua)`.\n- `useragent.parser(ua, jsua)` has been renamed to `useragent.parse(ua, jsua)`.\n- `result.pretty()` has been renamed to `result.toAgent()`.\n- `result.V1` has been renamed to `result.major`.\n- `result.V2` has been renamed to `result.minor`.\n- `result.V3` has been renamed to `result.patch`.\n- `result.prettyOS()` has been removed.\n- `result.match` has been removed.\n\n---\n\n### License\n\nMIT\n\n[browserscope]: http://www.browserscope.org/\n[benchmark]: /3rd-Eden/useragent/blob/master/benchmark/run.js\n[changelog]: /3rd-Eden/useragent/blob/master/CHANGELOG.md\n[npm]: http://npmjs.org\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/3rd-Eden/useragent/issues" + }, + "_id": "useragent@2.0.7", + "dist": { + "shasum": "5d2055b6e96721d53c4821fedd8c032e0b467687" + }, + "_from": "useragent@2.0.x", + "_resolved": "https://registry.npmjs.org/useragent/-/useragent-2.0.7.tgz" +} diff --git a/node_modules/useragent/static/user_agent.after.yaml b/node_modules/useragent/static/user_agent.after.yaml new file mode 100644 index 0000000..66b0b0b --- /dev/null +++ b/node_modules/useragent/static/user_agent.after.yaml @@ -0,0 +1,14 @@ +user_agent_parsers: + # browsers + - regex: '(Thunderbird)/(\d+)\.(\d+)\.?(\d+)?' + + # command line tools + - regex: '(Wget)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)' + + - regex: '(curl)/(\d+)\.(\d+)\.(\d+)' + family_replacement: 'cURL' + +os_parsers: + - regex: '(Red Hat)' + +device_parsers: diff --git a/node_modules/useragent/test/features.test.js b/node_modules/useragent/test/features.test.js new file mode 100644 index 0000000..a6c3ee3 --- /dev/null +++ b/node_modules/useragent/test/features.test.js @@ -0,0 +1,16 @@ +describe('useragent/features', function () { + 'use strict'; + + var useragent = require('../') + , features = require('../features') + , ua = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.24 Safari/535.2"; + + describe('#satisfies', function () { + it('should satisfy that range selector', function () { + var agent = useragent.parse(ua); + + agent.satisfies('15.x || >=19.5.0 || 25.0.0 - 17.2.3').should.be_true; + agent.satisfies('>16.12.0').should.be_false; + }); + }); +}); diff --git a/node_modules/useragent/test/fixtures/firefoxes.yaml b/node_modules/useragent/test/fixtures/firefoxes.yaml new file mode 100644 index 0000000..8c0d50b --- /dev/null +++ b/node_modules/useragent/test/fixtures/firefoxes.yaml @@ -0,0 +1,1386 @@ +# http://people.mozilla.com/~dwitte/ua.txt +# +# The following are some example User Agent strings for various versions of +# Firefox and other Gecko-based browsers. Many of these have been modified by +# extensions, external applications, distributions, and users. The version number +# for Firefox 5.0 (and the corresponding Gecko version) is tentative. See +# https://developer.mozilla.org/En/Gecko_User_Agent_String_Reference for more +# details. Credit to http://useragentstring.com/ for providing some of these +# strings. + +test_cases: + # Firefox 4.0 (prerelease) + - user_agent_string: Mozilla/5.0 (Windows NT 6.0; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b6pre) Gecko/20100903 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; rv:2.0b6pre) Gecko/20100903 Firefox/4.0b6pre Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + + # Firefox 4.0.1 + - user_agent_string: Mozilla/5.0 (Windows NT 5.2; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (WindowsCE 6.0; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.5; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 + family: 'Firefox' + major: '4' + minor: '0' + patch: '1' + + # Firefox 4.0 (prerelease) + - user_agent_string: Mozilla/5.0 (Windows NT 6.0; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0b6pre) Gecko/20100903 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; rv:2.0b6pre) Gecko/20100903 Firefox/4.0b6pre Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: b6pre + + # Firefox 5.0 (version number tentative -- not yet released) + - user_agent_string: Mozilla/5.0 (Windows NT 5.2; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (WindowsCE 6.0; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.5; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux x86_64; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.1.1) Gecko/ Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + + # Firefox 3.6 + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.8) Gecko/20100804 Gentoo Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.8) Gecko/20100723 SUSE/3.6.8-0.1.1 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.2.8) Gecko/20100722 Ubuntu/10.04 (lucid) Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.2.8) Gecko/20100723 Ubuntu/10.04 (lucid) Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; fi-FI; rv:1.9.2.8) Gecko/20100723 Ubuntu/10.04 (lucid) Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.8) Gecko/20100727 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.9.2.8) Gecko/20100725 Gentoo Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; FreeBSD i386; de-CH; rv:1.9.2.8) Gecko/20100729 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; pt-BR; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; he; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0C) + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.2.3) Gecko/20121221 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.8) Gecko/20100722 BTRS86393 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0C) + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-TW; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0E) + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; ro; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en; rv:1.9.2.8) Gecko/20100805 Firefox/3.6.8 + family: 'Firefox' + major: '3' + minor: '6' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.7) Gecko/20100723 Fedora/3.6.7-1.fc13 Firefox/3.6.7 + family: 'Firefox' + major: '3' + minor: '6' + patch: '7' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.7) Gecko/20100726 CentOS/3.6-3.el5.centos Firefox/3.6.7 + family: 'Firefox' + major: '3' + minor: '6' + patch: '7' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; hu; rv:1.9.2.7) Gecko/20100713 Firefox/3.6.7 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '7' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.9.2.7) Gecko/20100713 Firefox/3.6.7 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '7' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6 GTB7.0 + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6 + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; pt-PT; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; zh-CN; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; nl; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6 ( .NET CLR 3.5.30729; .NET4.0E) + family: 'Firefox' + major: '3' + minor: '6' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.4) Gecko/20100614 Ubuntu/10.04 (lucid) Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.4) Gecko/20100625 Gentoo Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; ja; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; cs; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; zh-CN; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; fr; rv:1.9.2.4) Gecko/20100523 Firefox/3.6.4 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.4) Gecko/20100527 Firefox/3.6.4 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.4) Gecko/20100527 Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.4) Gecko/20100523 Firefox/3.6.4 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.2.4) Gecko/20100523 Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 GTB7.0 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.4) Gecko/20100513 Firefox/3.6.4 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.4) Gecko/20100503 Firefox/3.6.4 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; nb-NO; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; ko; rv:1.9.2.4) Gecko/20100523 Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; cs; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4 GTB7.0 + family: 'Firefox' + major: '3' + minor: '6' + patch: '4' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.2.3) Gecko/20100403 Fedora/3.6.3-4.fc13 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.3) Gecko/20100403 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.2.3) Gecko/20100401 SUSE/3.6.3-1.1 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; ko-KR; rv:1.9.2.3) Gecko/20100423 Ubuntu/10.04 (lucid) Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.3) Gecko/20100404 Ubuntu/10.04 (lucid) Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.2.3) Gecko/20100423 Ubuntu/10.04 (lucid) Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; es-ES; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.0 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-GB; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; nl; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; fr; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; hu; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.1 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB7.0 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; cs; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; ca; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; sv-SE; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; nl; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.9.2.3) Gecko/20100403 Firefox/3.6.3 + family: 'Firefox' + major: '3' + minor: '6' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.7; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 + family: 'Firefox' + major: '3' + minor: '6' + patch: '2' + + # Firefox 3.5 + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.1.9) Gecko/20100402 Ubuntu/9.10 (karmic) Firefox/3.5.9 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; it; rv:1.9.1.9) Gecko/20100330 Fedora/3.5.9-2.fc12 Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.1.9) Gecko/20100317 SUSE/3.5.9-0.1.1 Firefox/3.5.9 GTB7.0 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; es-CL; rv:1.9.1.9) Gecko/20100402 Ubuntu/9.10 (karmic) Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; cs-CZ; rv:1.9.1.9) Gecko/20100317 SUSE/3.5.9-0.1.1 Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.9.1.9) Gecko/20100401 Ubuntu/9.10 (karmic) Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.9.1.9) Gecko/20100330 Fedora/3.5.9-1.fc12 Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.1.9) Gecko/20100317 SUSE/3.5.9-0.1 Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.9) Gecko/20100401 Ubuntu/9.10 (karmic) Firefox/3.5.9 GTB7.1 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.9) Gecko/20100315 Ubuntu/9.10 (karmic) Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.4) Gecko/20091028 Ubuntu/9.10 (karmic) Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; tr; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 GTB7.1 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; hu; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; et; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; nl; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; es-ES; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 GTB5 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 GTB7.0 (.NET CLR 3.0.30618) + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; ca; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9 GTB7.0 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '9' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; ru; rv:1.9.1.8) Gecko/20100216 Fedora/3.5.8-1.fc12 Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.1.8) Gecko/20100216 Fedora/3.5.8-1.fc11 Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.8) Gecko/20100318 Gentoo Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.8) Gecko/20100216 Fedora/3.5.8-1.fc12 Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.9.1.8) Gecko/20100216 Fedora/3.5.8-1.fc12 Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.9.1.8) Gecko/20100214 Ubuntu/9.10 (karmic) Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.8) Gecko/20100214 Ubuntu/9.10 (karmic) Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; FreeBSD i386; ja-JP; rv:1.9.1.8) Gecko/20100305 Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; sl; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 (.NET CLR 3.5.30729) FirePHP/0.4 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 GTB6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8 GTB7.0 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '8' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2) Gecko/20100305 Gentoo Firefox/3.5.7 + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; cs-CZ; rv:1.9.1.7) Gecko/20100106 Ubuntu/9.10 (karmic) Firefox/3.5.7 + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.1.7) Gecko/20091222 SUSE/3.5.7-1.1.1 Firefox/3.5.7 + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 (.NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; fr; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 (.NET CLR 3.0.04506.648) + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; fa; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.7) Gecko/20091221 MRA 5.5 (build 02842) Firefox/3.5.7 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '7' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.6) Gecko/20100117 Gentoo Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.6) Gecko/20091216 Fedora/3.5.6-1.fc11 Firefox/3.5.6 GTB6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.1.6) Gecko/20091201 SUSE/3.5.6-1.1.1 Firefox/3.5.6 GTB6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.6) Gecko/20100118 Gentoo Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 GTB6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 GTB7.0 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.6) Gecko/20091201 SUSE/3.5.6-1.1.1 Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.9.1.6) Gecko/20100107 Fedora/3.5.6-1.fc12 Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; ca; rv:1.9.1.6) Gecko/20091215 Ubuntu/9.10 (karmic) Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 ( .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; id; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.6) Gecko/20091201 MRA 5.4 (build 02647) Firefox/3.5.6 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; nl; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 MRA 5.5 (build 02842) Firefox/3.5.6 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 MRA 5.5 (build 02842) Firefox/3.5.6 + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 GTB6 (.NET CLR 3.5.30729) FBSMTWB + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729) FBSMTWB + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729) + family: 'Firefox' + major: '3' + minor: '5' + patch: '6' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; sv-SE; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 + family: 'Firefox' + major: '3' + minor: '5' + patch: '3' + + # Firefox on the next Gecko major release (preliminary) + - user_agent_string: Mozilla/5.0 (Windows NT 5.2; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (WindowsCE 6.0; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.5; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.0.1) Gecko Firefox/5.0.1 + family: 'Firefox' + major: '5' + minor: '0' + patch: '1' + +# # Fennec 2.0.1 (not yet released) +# - user_agent_string: Mozilla/5.0 (Android; Linux armv7l; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Fennec/2.0.1 +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: '1' +# - user_agent_string: Mozilla/5.0 (Maemo; Linux armv7l; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Fennec/2.0.1 +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: '1' +# - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Fennec/2.0.1 +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: '1' +# - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Fennec/2.0.1 +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: '1' +# - user_agent_string: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Fennec/2.0.1 +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: '1' +# +# # Fennec 2.0 (prerelease) +# - user_agent_string: Mozilla/5.0 (Android; Linux armv7l; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre Fennec/2.0b1pre +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: 'a1pre' +# - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.0b6pre) Gecko/20100907 Firefox/4.0b6pre Fennec/2.0b1pre +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: 'a1pre' +# - user_agent_string: Mozilla/5.0 (Windows NT 5.1; rv:2.0b6pre) Gecko/20100902 Firefox/4.0b6pre Fennec/2.0b1pre +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: 'a1pre' +# - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.0b4pre) Gecko/20100818 Firefox/4.0b4pre Fennec/2.0a1pre +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: 'a1pre' +# - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.0b4pre) Gecko/20100812 Firefox/4.0b4pre Fennec/2.0a1pre +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: 'a1pre' +# - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.0b3pre) Gecko/20100730 Firefox/4.0b3pre Fennec/2.0a1pre +# family: 'Fennec' +# major: '2' +# minor: '0' +# patch: 'a1pre' + + # Camino 2.2 (not yet released) + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.4; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Camino/2.2.1 + family: 'Camino' + major: '2' + minor: '2' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.5; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Camino/2.2.1 + family: 'Camino' + major: '2' + minor: '2' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Camino/2.2.1 + family: 'Camino' + major: '2' + minor: '2' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; PPC Mac OS X 10.4; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Camino/2.2.1 + family: 'Camino' + major: '2' + minor: '2' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; PPC Mac OS X 10.5; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Camino/2.2.1 + family: 'Camino' + major: '2' + minor: '2' + patch: '1' + + # Camino 2.0 + - user_agent_string: Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en; rv:1.9.0.19) Gecko/2010051911 Camino/2.0.3 (like Firefox/3.0.19) + family: 'Camino' + major: '2' + minor: '0' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; nl; rv:1.9.0.19) Gecko/2010051911 Camino/2.0.3 (MultiLang) (like Firefox/3.0.19) + family: 'Camino' + major: '2' + minor: '0' + patch: '3' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en; rv:1.9.0.18) Gecko/2010021619 Camino/2.0.2 (like Firefox/3.0.18) + family: 'Camino' + major: '2' + minor: '0' + patch: '2' + + # Camino 1.6 + - user_agent_string: Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; it; rv:1.8.1.21) Gecko/20090327 Camino/1.6.7 (MultiLang) (like Firefox/2.0.0.21pre) + family: 'Camino' + major: '1' + minor: '6' + patch: '7' + - user_agent_string: Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.8.1.21) Gecko/20090327 Camino/1.6.7 (like Firefox/2.0.0.21pre) + family: 'Camino' + major: '1' + minor: '6' + patch: '7' + + # Camino 1.5 + - user_agent_string: Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.8.1.12) Gecko/20080206 Camino/1.5.5 + family: 'Camino' + major: '1' + minor: '5' + patch: '5' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X Mach-O; en; rv:1.8.1.12) Gecko/20080206 Camino/1.5.5 + family: 'Camino' + major: '1' + minor: '5' + patch: '5' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.11) Gecko/20071128 Camino/1.5.4 + family: 'Camino' + major: '1' + minor: '5' + patch: '4' + - user_agent_string: Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.8.1.6) Gecko/20070809 Camino/1.5.1 + family: 'Camino' + major: '1' + minor: '5' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.6) Gecko/20070809 Camino/1.5.1 + family: 'Camino' + major: '1' + minor: '5' + patch: '1' +# +# # Thunderbird 3.1 +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; sv-SE; rv:1.9.2.8) Gecko/20100802 Thunderbird/3.1.2 ThunderBrowse/3.3.2 +# family: 'Thunderbird' +# major: '3' +# minor: '1' +# patch: '2' +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.2.8) Gecko/20100802 Thunderbird/3.1.2 +# family: 'Thunderbird' +# major: '3' +# minor: '1' +# patch: '2' +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.7) Gecko/20100713 Lightning/1.0b2 Thunderbird/3.1.1 ThunderBrowse/3.3.1 +# family: 'Thunderbird' +# major: '3' +# minor: '1' +# patch: '1' +# +# # Thunderbird 3.0 +# - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.10) Gecko/20100621 Fedora/3.0.5-1.fc13 Lightning/1.0b2pre Thunderbird/3.0.5 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '5' +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.1.10) Gecko/20100512 Lightning/1.0b1 Thunderbird/3.0.5 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '5' +# - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.9) Gecko/20100423 Thunderbird/3.0.4 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '4' +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.1.9) Gecko/20100317 Lightning/1.0b1 Thunderbird/3.0.4 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '4' +# - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.9) Gecko/20100317 Thunderbird/3.0.4 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '4' +# - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; pl; rv:1.9.1.9) Gecko/20100317 Thunderbird/3.0.4 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '4' +# - user_agent_string: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.9) Gecko/20100317 Thunderbird/3.0.4 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '4' +# - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.8) Gecko/20100408 Thunderbird/3.0.3 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '3' +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.9.1.7) Gecko/20100111 Thunderbird/3.0.1 ThunderBrowse/3.2.8.1 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '1' +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-CA; rv:1.9.1.7) Gecko/20100111 Thunderbird/3.0.1 ThunderBrowse/3.2.8.1 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '1' +# - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.9.1.7) Gecko/20100111 Thunderbird/3.0.1 ThunderBrowse/3.2.8.1 +# family: 'Thunderbird' +# major: '3' +# minor: '0' +# patch: '1' + + # SeaMonkey 2.1.1 (not yet released) + - user_agent_string: Mozilla/5.0 (Windows NT 5.2; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (WindowsCE 6.0; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.5; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + - user_agent_string: Mozilla/5.0 (X11; Linux armv7l; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 SeaMonkey/2.1.1 + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: '1' + + # SeaMonkey 2.1 (prerelease) + - user_agent_string: Mozilla/5.0 (Windows; Windows NT 5.2; rv:2.0b3pre) Gecko/20100803 SeaMonkey/2.1a3pre + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: 'a3pre' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.3a4pre) Gecko/20100404 SeaMonkey/2.1a1pre + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: 'a1pre' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.3a3pre) Gecko/20100312 SeaMonkey/2.1a1pre + family: 'SeaMonkey' + major: '2' + minor: '1' + patch: 'a1pre' + + # SeaMonkey 2.0 + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.11) Gecko/20100721 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.11) Gecko/20100714 SUSE/2.0.6-2.1 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux ia64; de; rv:1.9.1.11) Gecko/20100820 Lightning/1.0b2pre SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.11) Gecko/20100722 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 9.0; en-US; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.11) Gecko/20100722 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.1.11) Gecko/20100701 SeaMonkey/2.0.6 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.1.11pre) Gecko/20100630 SeaMonkey/2.0.6pre + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6pre' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; en-CA; rv:1.9.1.11pre) Gecko/20100629 SeaMonkey/2.0.6pre + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6pre' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.11pre) Gecko/20100515 SeaMonkey/2.0.6pre + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6pre' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.11pre) Gecko/20100508 SeaMonkey/2.0.6pre + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '6pre' + - user_agent_string: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.10) Gecko/20100504 Lightning/1.0b1 Mnenhy/0.8.2 SeaMonkey/2.0.5 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '5' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.1.10) Gecko/20100504 Lightning/1.0b1 SeaMonkey/2.0.5 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '5' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.10) Gecko/20100504 Lightning/1.0b1 SeaMonkey/2.0.5 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '5' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; fr; rv:1.9.1.9) Gecko/20100428 Lightning/1.0b1 SeaMonkey/2.0.4 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '4' + - user_agent_string: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.9) Gecko/20100317 SUSE/2.0.4-3.2 Lightning/1.0b1 SeaMonkey/2.0.4 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.9) Gecko/20100317 Lightning/1.0b1 SeaMonkey/2.0.4 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '4' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1.8) Gecko/20100205 SeaMonkey/2.0.3 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '3' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.7) Gecko/20100104 SeaMonkey/2.0.2 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '2' + - user_agent_string: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20100104 SeaMonkey/2.0.2 + family: 'SeaMonkey' + major: '2' + minor: '0' + patch: '2' diff --git a/node_modules/useragent/test/fixtures/pgts.yaml b/node_modules/useragent/test/fixtures/pgts.yaml new file mode 100644 index 0000000..2210b82 --- /dev/null +++ b/node_modules/useragent/test/fixtures/pgts.yaml @@ -0,0 +1,62356 @@ +test_cases: + - user_agent_string: "abot/0.1 (abot; http://www.abot.com; abot@abot.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Ace Explorer" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ACS-NF/3.0 NEC-c616/001.00" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ACS-NF/3.0 NEC-e616/001.01 (www.proxomitron.de)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ActiveBookmark 1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; AI)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AIM" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AIM/30 (Mozilla 1.24b; Windows; I; 32-bit)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "aipbot/1.0 (aipbot; http://www.aipbot.com; aipbot@aipbot.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Alizee iPod 2005 (Beta; Mac OS X)" + family: "Mobile Safari" + major: + minor: + patch: + - user_agent_string: "alpha 06" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.5 (compatible; alpha/06; AmigaOS 1337)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ALPHA/06_(Win98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "amaya/8.3 libwww/5.4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AmigaOS AmigaVoyager" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Arexx (AmigaVoyager/2.95; AmigaOS/MC680x0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Voyager; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.6 (compatible; AmigaVoyager; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AmigaVoyager/2.95 (compatible; MC680x0; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01 (compatible; AmigaVoyager/2.95; AmigaOS/MC680x0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AmigaVoyager/3.3.122 (AmigaOS/PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AmigaVoyager/3.4.4 (MorphOS/PPC native)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Amiga Voyager" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; AnsearchBot/1.0; +http://www.ansearch.com.au/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; ANTFresco 1.20; RISC OS 3.11)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.04 (compatible; ANTFresco/2.13; RISC OS 4.02)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.04 (compatible; NCBrowser/2.35 (1.45.2.1); ANTFresco/2.17; RISC OS-NC 5.13 Laz1UK1802)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; ANTFresco 2.20; RISC OS 3.11)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AOLserver-Tcl/3.5.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AOL 8.0 (compatible; AOL 8.0; DOS; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AOL/8.0 (Lindows 2003)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "aolbrowser/1.1 InterCon-Web-Library/1.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ArachnetAgent 2.3/4.78 (TuringOS; Turing Machine; 0.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Arexx ( ; ; AmigaOS 3.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Arexx (AmigaVoyager/2.95; AmigaOS/MC680x0; Mod-X by Pe)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Arexx (compatible; AmigaVoyager/2.95; AmigaOS" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Arexx (compatible; AmigaVoyager/2.95; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ARexx (compatible; ARexx; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Arexx (compatible; MSIE 6.0; AmigaOS5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Arexx (compatible; MSIE 6.0; AmigaOS5.0) IBrowse 4.0" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; ARexx; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; ARexx; AmigaOS; Avant Browser [avantbrowser.com]; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; arexx)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "ArtfaceBot (compatible; MSIE 6.0; Mozilla/4.0; Windows NT 5.1;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; Ask Jeeves/Teoma; +http://sp.ask.com/docs/about/tech_crawling.html)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Astra/1.0 (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Astra/2.0 (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Atari/2600b (compatible; 2port; Wood Grain)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Atari/2600 (GalaxianOS; U; en-US) cartridge/$29.95" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Auto-Proxy Downloader" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Advanced Browser (http://www.avantbrowser.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Avant Browser (http://www.avantbrowser.com)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Avant Browser [avantbrowser.com])" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com])" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]; .NET CLR 1.0.3705)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com])" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; .NET CLR 1.0.3705)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Avant Browser/1.2.789rel1 (http://www.avantbrowser.com)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Avantgo 5.5" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; AvantGo 5.2; FreeBSD)" + family: "AvantGo" + major: '5' + minor: '2' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; AvantGo 6.0; FreeBSD)" + family: "AvantGo" + major: '6' + minor: '0' + patch: + - user_agent_string: "Amiga" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AmigaOS" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Amiga OS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Aweb/2.3 (AmigaOS 3.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Amiga-AWeb/3.4APL" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; AWEB 3.4 SE; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Amiga-AWeb/3.4.167SE" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Amiga-AWeb/3.5.05 beta" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; BecomeBot/2.2.1; MSIE 6.0 compatible; +http://www.become.com/webmasters.html)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "BlackBerry7730/3.7.1 UP.Link/5.1.2.5" + family: "Blackberry" + major: '7730' + minor: + patch: + - user_agent_string: "UPG1 UP/4.0 (compatible; Blazer 1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Bobby/3.3 RPT-HTTPClient/0.3-3E" + family: "Other" + major: + minor: + patch: + - user_agent_string: "boitho.com-dc/0.70 ( http://www.boitho.com/dcbot.html )" + family: "Other" + major: + minor: + patch: + - user_agent_string: "boitho.com-dc/0.71 ( http://www.boitho.com/dcbot.html )" + family: "Other" + major: + minor: + patch: + - user_agent_string: "$BotName/$BotVersion [en] (UNIX; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Brain/1.0 [de] (Human RAW 1.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Browsers Part 4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Buscaplus Robi/1.0 (http://www.buscaplus.com/robi/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "BuyGet/1.0 Agent-Admin/webmaster@kfda.go.kr" + family: "Other" + major: + minor: + patch: + - user_agent_string: "CacheBot/0.445 (compatible, http://www.cachebot.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "CDM-8900" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Cerberian Drtrs Version-3.2-Build-1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.0; Update a; AK; Windows 95) via proxy gateway CERN-HTTPD/3.0 libwww/2.17" + family: "IE" + major: '3' + minor: '0' + patch: + - user_agent_string: "cfetch/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "CFNetwork/1.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonP900/R101 Profile/MIDP-2.0 Configuration/CLDC-1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonP900/R102 Profile/MIDP-2.0 Configuration/CLDC-1.0 Rev/MR4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonP910i/R3A SEMC-Browser/Symbian/3.0 Profile/MIDP-2.0 Configuration/CLDC-1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT610/R101 Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT610/R201 Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT610/R201 Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Link/5.1.2.1 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT610/R401 Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT610/R401 Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Link/5.1.1.3 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonZ600/R401 Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonK700i/R2AA SEMC-Browser/4.0.2 Profile/MIDP-2.0 Configuration/CLDC-1.1 (Google WAP Proxy/1.0)" + family: "SEMC-Browser" + major: '4' + minor: '0' + patch: + - user_agent_string: "SonyEricssonK700i/R2AE SEMC-Browser/4.0.3 Profile/MIDP-2.0 Configuration/CLDC-1.1 UP.Link/6.2.3.15.0 (Google WAP Proxy/1.0)" + family: "SEMC-Browser" + major: '4' + minor: '0' + patch: + - user_agent_string: "Clushbot/3.31-BinaryFury (+http://www.clush.com/bot.html)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 1.0; Commodore64)" + family: "IE" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 2.0; Commodore64)" + family: "IE" + major: '2' + minor: '0' + patch: + - user_agent_string: "Contiki/1.0 (Commodore 64; http://dunkels.com/adam/contiki/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ConveraMultiMediaCrawler/0.1 (+http://www.authoritativeweb.com/crawl)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "CosmixCrawler/0.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "crawler (ISSpider-3.0; http://www.yoururlgoeshere.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Crawler0.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.0 (compatible; Crazy Browser 1.0.1; FreeBSD 3.2-RELEASE i386)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Crazy Browser 1.0.5; .NET CLR 1.0.3705)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FREE; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MyIE2; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; APCMAG; NetCaptor 6.5.0B7; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; 3305; Versatel.de ISDN 0404; Crazy Browser 1.0.5; onlineTV; www.cdesign.de)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; Crazy Browser 1.0.5; Tyco Electronics 01/2003)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {4CBEAFB3-10C9-497A-B016-7FEBFBD707E9}; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; brip1; RainBird 1.01/HT; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Crazy Browser 1.0.5; FDM)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Crazy Browser 1.0.5; .NET CLR 1.0.3705)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Crazy Browser 1.0.5; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Crazy Browser 1.0.5; iRider 2.20.0018)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusNetDSL6; Crazy Browser 1.0.5; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Crazy Browser 1.0.5; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A5020528-0A08-4436-8CD1-D02C46132E5A}; SV1; Crazy Browser 1.0.5; CustomExchangeBrowser; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=vBB1c.00; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5; Alexa Toolbar)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5; .NET CLR 1.0.3705)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5; (R1 1.1); .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5; (R1 1.5))" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 1.0.5; SV1; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; FunWebProducts; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GoogleBot; Crazy Browser 1.0.5; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; SV1; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Katiesoft 7; Crazy Browser 1.0.5; .NET CLR 1.0.3705)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Crazy Browser 1.0.5; Alexa Toolbar)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Socantel; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 1.0.5; .NET CLR 1.0.3705)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 1.0.5; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 1.0.5; .NET CLR 1.1.4322; FDM)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 1.0.5; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iebar; Crazy Browser 1.0.5)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Texas Instruments; MyIE2; Crazy Browser 1.0.5; .NET CLR 1.0.3705)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.ASPSimply.com; Crazy Browser 1.0.5; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Crazy Browser 1.0.5; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "Crazy Browser" + major: '1' + minor: '0' + patch: '5' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Crazy Browser 2.0.0 Beta 1)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; YPC 3.0.1; yie6; Crazy Browser 2.0.0 Beta 1)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 2.0.0 Beta 1)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crazy Browser 2.0.0 Beta 1; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 2.0.0 Beta 1)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 2.0.0 Beta 1; .NET CLR 1.0.3705)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 2.0.0 Beta 1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 2.0.0 Beta 1; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts-MyTotalSearch; Maxthon; Crazy Browser 2.0.0 Beta 1)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; Deepnet Explorer 1.3.2; Crazy Browser 2.0.0 Beta 1; .NET CLR 1.1.4322)" + family: "Crazy Browser" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "curl/7.10.2 (powerpc-apple-darwin7.0) libcurl/7.10.2 OpenSSL/0.9.7b zlib/1.1.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.10.6 (i386-redhat-linux-gnu) libcurl/7.10.6 OpenSSL/0.9.7a ipv6 zlib/1.1.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.10.6 (i386-redhat-linux-gnu) libcurl/7.10.6 OpenSSL/0.9.7a ipv6 zlib/1.2.0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.11.2 (i686-pc-linux-gnu) libcurl/7.10.2 OpenSSL/0.9.6i ipv6 zlib/1.1.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.12.0 (i686-pc-linux-gnu) libcurl/7.12.0 OpenSSL/0.9.7e ipv6 zlib/1.2.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.7.2 (powerpc-apple-darwin6.0) libcurl 7.7.2 (OpenSSL 0.9.6b)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.7.3 (i686-pc-linux-gnu) libcurl 7.7.3 (OpenSSL 0.9.6)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.7.3 (win32) libcurl 7.7.3 (OpenSSL 0.9.6)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.9.3 (powerpc-ibm-aix4.3.3.0) libcurl 7.9.3 (OpenSSL 0.9.6m)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.9.5 (i386-redhat-linux-gnu) libcurl 7.9.5 (OpenSSL 0.9.6b) (ipv6 enabled)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "curl/7.9.8 (i386-redhat-linux-gnu) libcurl 7.9.8 (OpenSSL 0.9.7a) (ipv6 enabled)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "DA 5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "DA 5.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "daemon (AmigaOS; alpha/06; AmigaOS mod-x)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "DataFountains/DMOZ Downloader" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; DB Browse 4.3; DB OS 6.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "deepak-USC/ISI" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Deepnet Explorer" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Deepnet Explorer 1.0.1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Dillo/0.6.4" + family: "Dillo" + major: '0' + minor: '6' + patch: '4' + - user_agent_string: "Dillo/0.7.3" + family: "Dillo" + major: '0' + minor: '7' + patch: '3' + - user_agent_string: "Dillo/0.8.0" + family: "Dillo" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Dillo/0.8.0-pre" + family: "Dillo" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Dillo/0.8.1" + family: "Dillo" + major: '0' + minor: '8' + patch: '1' + - user_agent_string: "Dillo/0.8.2" + family: "Dillo" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Dillo/0.8.2-pre" + family: "Dillo" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Dillo/0.8.3" + family: "Dillo" + major: '0' + minor: '8' + patch: '3' + - user_agent_string: "Dillo/0.8.3-rc2" + family: "Dillo" + major: '0' + minor: '8' + patch: '3' + - user_agent_string: "Dillo/0.8.4" + family: "Dillo" + major: '0' + minor: '8' + patch: '4' + - user_agent_string: "Dillo/0.8.5-pre" + family: "Dillo" + major: '0' + minor: '8' + patch: '5' + - user_agent_string: "Dillo/27951.4" + family: "Dillo" + major: '27951' + minor: '4' + patch: + - user_agent_string: "dloader(NaverRobot)/1.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; DLW 2.0; Win32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "DoCoMo/1.0/D503iS/c10" + family: "Other" + major: + minor: + patch: + - user_agent_string: "DoCoMo/1.0/P502i/c10 (Google CHTML Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "DoCoMo/2.0 F900i(c100;TB;W22H12),gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "DoCoMo/2.0 N900i(c100;TB;W24H12)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Doris/1.10 [en] (Symbian)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Doris/1.17 [en] (Symbian)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Download.exe(1.1) (+http://www.sql-und-xml.de/freeware-tools/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Download Master" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Download Ninja 7.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "EasyDL/3.04 http://keywen.com/Encyclopedia/Bot" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks (0.10rc1; Linux 2.6.9-gentoo-r10 i686; 80x25)" + family: "Links" + major: '0' + minor: '10' + patch: + - user_agent_string: "ELinks (0.4.2; cygwin; 700)" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.4.2; Linux; )" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.4pre18; Linux 2.2.22 i686; 80x25)" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.4pre5; Linux 2.2.20-compact i586; 80x30)" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.4pre5; Linux 2.2.20 i586; 138x44)" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.4pre5; Linux 2.4.23 i686; 114x27)" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.4pre5; Linux 2.4.24 i686; 132x34)" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.4pre5; Linux 2.6.0 i686; 176x66)" + family: "Links" + major: '0' + minor: '4' + patch: + - user_agent_string: "ELinks (0.9.3)" + family: "Links" + major: '0' + minor: '9' + patch: + - user_agent_string: "ELinks (0.9.CVS; Linux 2.6.5 i686; 169x55)" + family: "Links" + major: '0' + minor: '9' + patch: + - user_agent_string: "ELinks/0.9.CVS (textmode; Linux 2.4.18-1-386 i686; 80x25-3)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.1 (textmode; FreeBSD 4.10-PRERELEASE i386; 132x43)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.1 (textmode; FreeBSD 4.10-STABLE i386; 132x43)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.1 (textmode; Linux 2.4.26 i686; 128x48)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.1 (textmode; Linux 2.6.3-7mdksmp i686; 80x25)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.1 (textmode; Linux 2.6.6 i686; 128x54)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.1 (textmode; Linux; 80x24)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.1 (textmode; Linux; 80x25)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.2rc2 (textmode; Linux 2.4.26-lck1 i486; 80x25)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.2rc4 (textmode; Linux 2.4.20-8 i686; 105x46)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.2rc7 (textmode; Linux 2.4.29-1 i686; 190x75)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.2 (textmode; Linux; 157x52)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.3 (textmode; Linux 2.6.10 i686; 80x25)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.3 (textmode; Linux 2.6.7-20050106 i686; 80x34)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.3 (textmode; Linux 2.6.8-1-386 i686; 160x64)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.3 (textmode; Linux 2.6.8.1 i686; 118x82)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ELinks/0.9.3 (textmode; Linux 2.6.8-mdp04 i686; 80x25)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Enigma Browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "EricssonT68/R101 (;; ;; ;; Smartphone; SDA/1.0 Profile/MIDP-2.0 Configuration/CLDC-1.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Explorer /5.02 (Windows 95; U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Explorer /5.02 (Windows 95; U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; FastWeb; Windows NT 5.1; OMEGA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "FavOrg" + family: "Other" + major: + minor: + patch: + - user_agent_string: "FDM 1.x" + family: "Other" + major: + minor: + patch: + - user_agent_string: "FindAnISP.com_ISP_Finder_v99a" + family: "Other" + major: + minor: + patch: + - user_agent_string: "findlinks/0.901e (+http://wortschatz.uni-leipzig.de/findlinks/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Firefox/1.0 (Windows; U; Win98; en-US; Localization; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Firefox/1.0.1 (Windows NT 5.1; U; pl-PL)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "FireFox (X11; Linux i686; pl-PL); slackware; FireFox;" + family: "Other" + major: + minor: + patch: + - user_agent_string: "FlashGet" + family: "Other" + major: + minor: + patch: + - user_agent_string: "FOOZWAK (zeep; 47.3; CheeseMatic 9.1; T312461; iOpus-I-M; BucketChunk 4.1; Shronk; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "FreshDownload/4.40" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Funky Little Browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Galeon (IE4 compatible; Galeon; Windows XP)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Galeon (PPC; U; Windows NT 5.1; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Galeon; Windows NT 5.1;)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (IE4 compatible; Galeon; Windows NT 5.1;)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (IE4 compatible; Galeon; Windows XP)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 Galeon 1.2.5 (X11; Linux i686; U;) Gecko/0-pie MSIE 6.0" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-IE; rv:1.6) Gecko Galeon" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 Galeon/1.0.2 (X11; Linux i686; U)" + family: "Galeon" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 Galeon/1.0.3 (X11; Linux i686; U)" + family: "Galeon" + major: '1' + minor: '0' + patch: '3' + - user_agent_string: "Mozilla/5.0 Galeon/1.0.3 (X11; Linux i686; U;) Gecko/20020214" + family: "Galeon" + major: '1' + minor: '0' + patch: '3' + - user_agent_string: "Mozilla/5.0 Galeon/1.0.3 (X11; Linux i686; U;) Gecko/20020325" + family: "Galeon" + major: '1' + minor: '0' + patch: '3' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.0 (X11; Linux i686; U)" + family: "Galeon" + major: '1' + minor: '2' + patch: '0' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.0 (X11; Linux i686; U;) Gecko/20020408" + family: "Galeon" + major: '1' + minor: '2' + patch: '0' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.11 (X11; Linux i686; U;) Gecko/0" + family: "Galeon" + major: '1' + minor: '2' + patch: '11' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.11 (X11; Linux i686; U;) Gecko/20030417" + family: "Galeon" + major: '1' + minor: '2' + patch: '11' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.11 (X11; Linux i686; U;) Gecko/20030703" + family: "Galeon" + major: '1' + minor: '2' + patch: '11' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.11 (X11; Linux i686; U;) Gecko/20030708" + family: "Galeon" + major: '1' + minor: '2' + patch: '11' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.11 (X11; Linux i686; U;) Gecko/20030716" + family: "Galeon" + major: '1' + minor: '2' + patch: '11' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.11 (X11; Linux i686; U;) Gecko/20030822" + family: "Galeon" + major: '1' + minor: '2' + patch: '11' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.13 (X11; Linux i686; U;) Gecko/20040308" + family: "Galeon" + major: '1' + minor: '2' + patch: '13' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.13 (X11; Linux i686; U;) Gecko/20041004" + family: "Galeon" + major: '1' + minor: '2' + patch: '13' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.5 (X11; Linux i586; U;) Gecko/20020605" + family: "Galeon" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.5 (X11; Linux i686; U)" + family: "Galeon" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.5 (X11; Linux i686; U;) Gecko/0" + family: "Galeon" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.5 (X11; Linux i686; U;) Gecko/20020605" + family: "Galeon" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.5 (X11; Linux i686; U;) Gecko/20020623 Debian/1.2.5-0.woody.1" + family: "Galeon" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.5 (X11; Linux i686; U;) Gecko/20020809" + family: "Galeon" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.6 (X11; Linux i686; U;) Gecko/20020827" + family: "Galeon" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.6 (X11; Linux i686; U;) Gecko/20020830" + family: "Galeon" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.6 (X11; Linux i686; U;) Gecko/20021105" + family: "Galeon" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.7 (X11; Linux i686; U;) Gecko/20021203" + family: "Galeon" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.7 (X11; Linux i686; U;) Gecko/20021226 Debian/1.2.7-6" + family: "Galeon" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.7 (X11; Linux i686; U;) Gecko/20030131" + family: "Galeon" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.7 (X11; Linux i686; U;) Gecko/20030401" + family: "Galeon" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.7 (X11; Linux i686; U;) Gecko/20030622" + family: "Galeon" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.7 (X11; Linux ppc; U;) Gecko/20030130" + family: "Galeon" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.8 (X11; Linux i686; U;) Gecko/20030317" + family: "Galeon" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 Galeon/1.2.8 (X11; Linux i686; U;) Gecko/20030328" + family: "Galeon" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031114 Galeon/1.3.10" + family: "Galeon" + major: '1' + minor: '3' + patch: '10' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Galeon/1.3.10 (Debian package 1.3.10-3)" + family: "Galeon" + major: '1' + minor: '3' + patch: '10' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Galeon/1.3.11a (Debian package 1.3.11a-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '11' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Galeon/1.3.11a (Debian package 1.3.11a-2)" + family: "Galeon" + major: '1' + minor: '3' + patch: '11' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040814 Galeon/1.3.11a" + family: "Galeon" + major: '1' + minor: '3' + patch: '11' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.6) Gecko/20040115 Galeon/1.3.12" + family: "Galeon" + major: '1' + minor: '3' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20031015 Galeon/1.3.12" + family: "Galeon" + major: '1' + minor: '3' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040115 Galeon/1.3.12" + family: "Galeon" + major: '1' + minor: '3' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040308 Galeon/1.3.12" + family: "Galeon" + major: '1' + minor: '3' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040331 Galeon/1.3.12" + family: "Galeon" + major: '1' + minor: '3' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; hu; rv:1.6) Gecko/20040229 Galeon/1.3.12" + family: "Galeon" + major: '1' + minor: '3' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; PL; rv:1.6) Gecko/20040115 Galeon/1.3.12" + family: "Galeon" + major: '1' + minor: '3' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031115 Galeon/1.3.13" + family: "Galeon" + major: '1' + minor: '3' + patch: '13' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040116 Galeon/1.3.13" + family: "Galeon" + major: '1' + minor: '3' + patch: '13' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040122 Galeon/1.3.13 (Debian package 1.3.13-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '13' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040122 Galeon/1.3.13 (Debian package 1.3.13-2)" + family: "Galeon" + major: '1' + minor: '3' + patch: '13' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040130 Galeon/1.3.13" + family: "Galeon" + major: '1' + minor: '3' + patch: '13' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040305 Galeon/1.3.13" + family: "Galeon" + major: '1' + minor: '3' + patch: '13' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040312 Galeon/1.3.13 (Debian package 1.3.13-2)" + family: "Galeon" + major: '1' + minor: '3' + patch: '13' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040402 Galeon/1.3.14" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040426 Galeon/1.3.14" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040501 Galeon/1.3.14" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20040928 Galeon/1.3.14 (Debian package 1.3.14a-0jds4)" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20040107 Galeon/1.3.14" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040122 Galeon/1.3.14 (Debian package 1.3.14a-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040124 Galeon/1.3.14" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040309 Galeon/1.3.14" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040312 Galeon/1.3.14" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040413 Galeon/1.3.14 (Debian package 1.3.14a-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040413 Galeon/1.3.14 (Debian package 1.3.14acvs20040504-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040528 Galeon/1.3.14 (Debian package 1.3.14acvs20040520-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '14' + - user_agent_string: "Mozilla/5.0 (compatible; Galeon/1.3.15; Atari 2600)" + family: "Galeon" + major: '1' + minor: '3' + patch: '15' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040413 Galeon/1.3.15 (Debian package 1.3.15-2)" + family: "Galeon" + major: '1' + minor: '3' + patch: '15' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510 Galeon/1.3.15" + family: "Galeon" + major: '1' + minor: '3' + patch: '15' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040528 Galeon/1.3.15 (Debian package 1.3.15-2)" + family: "Galeon" + major: '1' + minor: '3' + patch: '15' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040618 Galeon/1.3.15" + family: "Galeon" + major: '1' + minor: '3' + patch: '15' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040624 Galeon/1.3.15" + family: "Galeon" + major: '1' + minor: '3' + patch: '15' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040624 Galeon/1.3.15 (Debian package 1.3.15-3)" + family: "Galeon" + major: '1' + minor: '3' + patch: '15' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040710 Galeon/1.3.16" + family: "Galeon" + major: '1' + minor: '3' + patch: '16' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510 Galeon/1.3.16" + family: "Galeon" + major: '1' + minor: '3' + patch: '16' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040726 Galeon/1.3.16 (Debian package 1.3.16-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '16' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040802 Galeon/1.3.16 (Debian package 1.3.16-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '16' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040805 Galeon/1.3.16 (Debian package 1.3.16-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '16' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040810 Galeon/1.3.16 (Debian package 1.3.16-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '16' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040724 Galeon/1.3.16" + family: "Galeon" + major: '1' + minor: '3' + patch: '16' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.2) Gecko/20040824 Galeon/1.3.17" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040805 Galeon/1.3.17 (Debian package 1.3.17-2.0.1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040803 Galeon/1.3.17" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040804 Galeon/1.3.17" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040818 Galeon/1.3.17" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040820 Galeon/1.3.17 (Debian package 1.3.17-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040906 Galeon/1.3.17" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040921 Galeon/1.3.17" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Galeon/1.3.17 (Debian package 1.3.17-2)" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.7.2) Gecko/20040808 Galeon/1.3.17" + family: "Galeon" + major: '1' + minor: '3' + patch: '17' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041130 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041221 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041224 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20041007 Galeon/1.3.18 (Debian package 1.3.18-1.1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041228 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040916 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040922 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040928 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Galeon/1.3.18 (Debian package 1.3.18-1.1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041020 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041223 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Galeon/1.3.18" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Galeon/1.3.18 (Debian package 1.3.18-2)" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.3) Gecko/20041007 Galeon/1.3.18 (Debian package 1.3.18-1.1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '18' + - user_agent_string: "Mozilla/5.0 (This is not Lynx/Please do not arrest user; X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041027 Galeon/1.3.19" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041224 Galeon/1.3.19" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041020 Galeon/1.3.19" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041027 Galeon/1.3.19" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Galeon/1.3.19 (Debian package 1.3.19-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Galeon/1.3.19 (Debian package 1.3.19-3)" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Galeon/1.3.19 (Debian package 1.3.19-4)" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050106 Galeon/1.3.19 (Debian package 1.3.19-1ubuntu1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050216 Galeon/1.3.19" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 Galeon/1.3.19" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041230 Galeon/1.3.19" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050106 Galeon/1.3.19 (Debian package 1.3.19-3)" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041221 Galeon/1.3.19.99" + family: "Galeon" + major: '1' + minor: '3' + patch: '19' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Galeon/1.3.20 (Debian package 1.3.20-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '20' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050106 Galeon/1.3.20 (Debian package 1.3.20-1ubuntu4)" + family: "Galeon" + major: '1' + minor: '3' + patch: '20' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050324 Galeon/1.3.20 (Debian package 1.3.20-1)" + family: "Galeon" + major: '1' + minor: '3' + patch: '20' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586) Gecko/20030311 Galeon/1.3.3" + family: "Galeon" + major: '1' + minor: '3' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20030311 Galeon/1.3.3" + family: "Galeon" + major: '1' + minor: '3' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20030428 Galeon/1.3.3" + family: "Galeon" + major: '1' + minor: '3' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386) Gecko/0 Galeon/1.3.4" + family: "Galeon" + major: '1' + minor: '3' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586) Gecko/20030807 Galeon/1.3.5" + family: "Galeon" + major: '1' + minor: '3' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20030530 Galeon/1.3.5" + family: "Galeon" + major: '1' + minor: '3' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20030807 Galeon/1.3.5" + family: "Galeon" + major: '1' + minor: '3' + patch: '5' + - user_agent_string: "Galeon/1.3.7 (IE4 compatible; Galeon; Windows XP) Galeon/1.3.7 Debian/1.3.7.20030803-1" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Galeon/1.3.7 (IE4 compatible; I; Mac_PowerPC)" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Galeon/1.3.7 (IE4 compatible; I; Windows XP) Galeon/1.3.7 Debian/1.3.7.20030803-1" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386) Gecko/0 Galeon/1.3.7" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20030610 Galeon/1.3.7" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20030630 Galeon/1.3.7" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20040107 Galeon/1.3.7" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20040319 Galeon/1.3.7" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20040323 Galeon/1.3.7" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20040428 Galeon/1.3.7" + family: "Galeon" + major: '1' + minor: '3' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.4) Gecko/20030630 Galeon/1.3.8" + family: "Galeon" + major: '1' + minor: '3' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.4) Gecko/20030630 Galeon/1.3.8" + family: "Galeon" + major: '1' + minor: '3' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030630 Galeon/1.3.8" + family: "Galeon" + major: '1' + minor: '3' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.4) Gecko/20030630 Galeon/1.3.8" + family: "Galeon" + major: '1' + minor: '3' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.4) Gecko/20030630 Galeon/1.3.8" + family: "Galeon" + major: '1' + minor: '3' + patch: '8' + - user_agent_string: "Galeon/1.3.9 Mozilla/1.4 HTML/4.01 XHTML/1.0 CSS/2.1" + family: "Galeon" + major: '1' + minor: '3' + patch: '9' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030915 Galeon/1.3.9" + family: "Galeon" + major: '1' + minor: '3' + patch: '9' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031015 Galeon/1.3.9" + family: "Galeon" + major: '1' + minor: '3' + patch: '9' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.4) Gecko/20030930 Galeon/1.3.9" + family: "Galeon" + major: '1' + minor: '3' + patch: '9' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20030311 Galeon/1.3.3,gzip(gfe) (via translate.google.com)" + family: "Galeon" + major: '1' + minor: '3' + patch: '3' + - user_agent_string: "GetRight/5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "GetRight/5.0.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "GetRight/5.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Go-Ahead-Got-It/1.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "googlebot/2.1 (+http://www.googlebot.com/bot.html" + family: "Other" + major: + minor: + patch: + - user_agent_string: "googlebot/2.1; +http://www.google.com/bot.html" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Googlebot (+http://www.google.com/bot.html)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Googlebot/2.1 (compatible; MSIE; Windows)" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Googlebot/2.1 (+http://www.googlebot.com/bot.html) (compatible; MSIE 6.0; )" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Googlebot/2.1+(+http://www.google.com/bot.html)" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.0 (MobilePhone SCP-5500/US/1.0) NetFront/3.0 MMP/2.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" + family: "NetFront" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (MobilePhone SCP-5500/US/1.0) NetFront/3.0 MMP/2.0 FAKE (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" + family: "NetFront" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.)" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "GoogleBot/2.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Googlebot-Image/1.0 (+http://www.googlebot.com/bot.html" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; grub-client-2.6.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Grubclient-2.2-internal-beta)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Grubclient; windows; SV1; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "grub crawler" + family: "Other" + major: + minor: + patch: + - user_agent_string: "grub crawler(http://www.grub.org)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "gsa-crawler (Enterprise; GID-01742;gsatesting@rediffmail.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Happy-Browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "HLoader" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Homerweb" + family: "Other" + major: + minor: + patch: + - user_agent_string: "HooWWWer/2.1.0 (+http://cosco.hiit.fi/search/hoowwwer/ | mailto:crawler-infohiit.fi)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Hop 0.7 (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Hozilla/9.0 (Macintosh; U; PC Mac OS X; en-us) SnappleWebKit/69 (KHTML, like your mom) Safari/69" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (Win95; I; HTTPClient 1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Hyperlink/2.5e (Commodore 64)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ia_archiver-web.archive.org" + family: "Other" + major: + minor: + patch: + - user_agent_string: "alpha/06 (compatible; IBrowse; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "IBrowse (AmigaOS; alpha/06; AmigaOS mod-x)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "IBrowse(compatible; alpha/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "IBrowse (compatible; alpha/06; AmigaOS/PPC; SV1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "IBrowse/1.12demo (AmigaOS 3.0)" + family: "IBrowse" + major: '1' + minor: '12' + patch: + - user_agent_string: "IBrowse/2.2 (Windows V45)" + family: "IBrowse" + major: '2' + minor: '2' + patch: + - user_agent_string: "IBrowse/2.2 (Windows V50)" + family: "IBrowse" + major: '2' + minor: '2' + patch: + - user_agent_string: "IBrowse/2.3 (AmigaOS 3.0)" + family: "IBrowse" + major: '2' + minor: '3' + patch: + - user_agent_string: "IBrowse/2.3 (AmigaOS 3.1)" + family: "IBrowse" + major: '2' + minor: '3' + patch: + - user_agent_string: "IBrowse/2.3 (AmigaOS 3.9)" + family: "IBrowse" + major: '2' + minor: '3' + patch: + - user_agent_string: "IBrowse/2.3 (AmigaOS 3.9))" + family: "IBrowse" + major: '2' + minor: '3' + patch: + - user_agent_string: "IBrowse/2.3 (AmigaOS 4.0)" + family: "IBrowse" + major: '2' + minor: '3' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; IBrowse 2.3; AmigaOS4.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AmigaOS4.0) IBrowse 2.3" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; IBrowse 3.0; AmigaOS4.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "iCab" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 (compatible; iCab 2.9.1; Macintosh; U; PPC; Mac OS X)" + family: "iCab" + major: '2' + minor: '9' + patch: '1' + - user_agent_string: "iCab/2.9.5 (Macintosh; U; PPC; Mac OS X)" + family: "iCab" + major: '2' + minor: '9' + patch: '5' + - user_agent_string: "Mozilla/4.5 (compatible; iCab 2.9.6; Macintosh; U; PPC)" + family: "iCab" + major: '2' + minor: '9' + patch: '6' + - user_agent_string: "Mozilla/4.5 (compatible; iCab 2.9.7; Macintosh; U; PPC)" + family: "iCab" + major: '2' + minor: '9' + patch: '7' + - user_agent_string: "Mozilla/4.5 (compatible; iCab 2.9.7; Macintosh; U; PPC; Mac OS X)" + family: "iCab" + major: '2' + minor: '9' + patch: '7' + - user_agent_string: "iCab/2.9.8 (Macintosh; U; PPC)" + family: "iCab" + major: '2' + minor: '9' + patch: '8' + - user_agent_string: "iCab/2.9.8 (Macintosh; U; PPC; Mac OS X)" + family: "iCab" + major: '2' + minor: '9' + patch: '8' + - user_agent_string: "Mozilla/4/5 (compatible; iCab 2.9.8; Macintosh; U; 68K" + family: "iCab" + major: '2' + minor: '9' + patch: '8' + - user_agent_string: "Mozilla/4.5 (compatible; iCab 2.9.8; Macintosh; U; PPC)" + family: "iCab" + major: '2' + minor: '9' + patch: '8' + - user_agent_string: "Mozilla/4.5 (compatible; iCab 2.9.8; Macintosh; U; PPC; Mac OS X)" + family: "iCab" + major: '2' + minor: '9' + patch: '8' + - user_agent_string: "Mozilla/5.0 (compatible; iCab 2.9.8; Macintosh; U, PPC; Mac OS X)" + family: "iCab" + major: '2' + minor: '9' + patch: '8' + - user_agent_string: "iCab/3.0 (Macintosh; U; PPC; Mac OS X)" + family: "iCab" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; iCab 3.0; Macintosh; U; PPC; Mac OS X)" + family: "iCab" + major: '3' + minor: '0' + patch: + - user_agent_string: "ICE Browser/5.05 (Java 1.4.1; Windows 2000 5.0 x86)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ICEBrowser 5.31" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ICE Browser/v5_4_3 (Java 1.4.2_01; Windows XP 5.1 x86)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ICE Browser/v5_4_3_1 (Java 1.4.2_01; Windows XP 5.1 x86)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "IEAutoDiscovery" + family: "Other" + major: + minor: + patch: + - user_agent_string: "IE test" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Internet Explorer 5x" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Internet Explorer 5.x" + family: "Other" + major: + minor: + patch: + - user_agent_string: "IQSearch" + family: "Other" + major: + minor: + patch: + - user_agent_string: "itunes" + family: "Other" + major: + minor: + patch: + - user_agent_string: "iTunes/4.2 (Macintosh; U; PPC Mac OS X 10.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "iTunes/4.7 (Macintosh; U; PPC Mac OS X 10.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient/2.0final" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient/2.0.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient/2.0rc1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient/2.0rc2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient/3.0-beta1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient/3.0-rc1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Jakarta Commons-HttpClient/2.0.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java(TM) 2 Runtime Environment, Standard Edition" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java1.1.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java1.3.1_03" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java1.4.0_02" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.1_01" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.1_02" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.1_04" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.1_05" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.2_01" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.2_03" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.2_04" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.2_05" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.4.2_06" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.5.0_01" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Java/1.5.0-beta2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "jBrowser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "JoBo/1.4beta (http://www.matuschek.net/jobo.html)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "JoeDog/1.00 [en] (X11; I; Siege 2.59)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Kittiecentral.com; HTTP)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Kittiecentral.com; HTTPConnect)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Kittiecentral.com; Index-Client)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Klondike/1.50 (WSP Win32) (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "KnowItAll(knowitall@cs.washington.edu)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Konqueror" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror; FreeBSD; http://www.cartedaffaire.net/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Konqueror/1.1.2" + family: "Konqueror" + major: '1' + minor: '1' + patch: '2' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.0.1; X11); Supports MD5-Digest; Supports gzip encoding" + family: "Konqueror" + major: '2' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.1.1; X11)" + family: "Konqueror" + major: '2' + minor: '1' + patch: '1' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.1.2; X11)" + family: "Konqueror" + major: '2' + minor: '1' + patch: '2' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2-11; Linux)" + family: "Konqueror" + major: '2' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2.1)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2.1; Linux)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2.2)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2.2-2; Linux)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2.2; FreeBSD)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2.2; Linux)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/2.2.2; Linux 2.4.14-xfs; X11; i686)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '2' + - user_agent_string: "Konqueror 3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0.0-10; Linux)" + family: "Konqueror" + major: '3' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0.0; FreeBSD)" + family: "Konqueror" + major: '3' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0.0; Linux)" + family: "Konqueror" + major: '3' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0; Darwin)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020101)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020313)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3; FreeBSD)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3; Linux)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3; Linux; X11)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0; i686 Linux; 20021215)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0.0-10; Linux 2.4.18-3smp)" + family: "Konqueror" + major: '3' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0.1 (CVS >= 20020327); Linux) Linspire (Lindows, Inc.)" + family: "Konqueror" + major: '3' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; CYGWIN_NT-5.1)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; de)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; de, DE, de_DE@euro)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; FreeBSD)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20020802)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; i686 Linux; 20021111)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.20-4GB-athlon; X11; i686)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.20-4GB; X11)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.20; X11; i686)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.20-xfs; X11)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.21-20.0.1.ELsmp; X11; i686; , en_US, en, de)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.21-243-athlon)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.22-10mdk; X11; i686; en_GB, en_NZ, en)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.22-10mdk; X11; i686; fr, fr_FR)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.22-1.2115.nptl)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.22-4GB-athlon; X11; i686)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.22-aes; X11; i686)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.22-xfs; X11)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux 2.4.24-xfs; X11)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux; de, DE, de_DE@euro)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux; en_US, en)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux; i686)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux; X11; de, DE, de_DE@euro)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux; X11; en_GB)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux; X11; i686; , en_US, en)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; Linux; X11; i686; uk, uk_UA)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; OpenBSD)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1; SunOS)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1.3; OpenBSD 3.4)" + family: "Konqueror" + major: '3' + minor: '1' + patch: '3' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Darwin) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; , en_GB, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; en_US, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; FreeBSD 4.9-STABLE; X11; i386; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; FreeBSD) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2) KHTML/3.2.3 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.4.22) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.4.23-0; X11; i686) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.4.24-xfs; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.4.25-klg; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.4.26; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.4.27; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.3-15mdksmp; i686) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.3-7mdk) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.3-7mdk; X11; i686; en_US, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.4-52-default; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.4; i686) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.5) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.5; X11; i686; en_US, es, fr, it, en_US.UTF-8, en)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.5; X11; i686; en_US, es, fr, it, en_US.UTF-8, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.5; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.7-rc3-love2; X11; i686) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.7; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.8.1-10mdk) KHTML/3.2.3 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.8.1-12mdksmp) KHTML/3.2.3 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux 2.6.8.1; X11; i686; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; de, de_DE@euro) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; en_GB, en_GB.UTF-8, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; en_GB, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; en_US, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; en_US, zh_TW, en_US.UTF-8, zh_TW.UTF-8, zh) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; i686; en_US, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; i686) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux) KHTML/3.2.3 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; ) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux) (KHTML, like Gecko) WebWasher 3.3" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; X11; , en_US, en) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; X11; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; X11; es, es_ES, es_ES.UTF8) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; X11; i686) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; X11; ) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; Linux; X11; ru, en_US, ru_RU, ru_RU.KOI8-R, KOI8-R) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; NetBSD) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; OpenBSD) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2; x86_64; en_US) KHTML/3.2.3 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2.; Linux 2.4.20-gentoo-r2; X11; i" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2.2; Linux) (KHTML, like Gecko) - www.amorosi4u.de.vu" + family: "Konqueror" + major: '3' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2.3; FreeBSD 4.10-STABLE; X11; i386; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.2.3; OpenBSD 3.6)" + family: "Konqueror" + major: '3' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; FreeBSD 5.3-RELEASE-p2; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; FreeBSD) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.4.21-243-smp4G) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; konqueror/3.3; linux 2.4.21-243-smp4G) (KHTML, like Geko)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.4.24; X11; i686; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.4.27; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.10-1-386; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.10-1-686-smp) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.10-1-686; X11; i686; zh_TW) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.10-1-k7; X11; i686; en_US) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.10-gentoo-r2-ljr; X11; x86_64; en_US) KHTML/3.3.91 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.10; X11; i686; en_US) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.10; X11; i686) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.11.2; X11; i686; cs, en_US) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.7) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.7; X11; i686; fr, it, es, ru, de, en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.8.1-24mdk; X11; i686; sl) KHTML/3.3.92 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.8-1-686; X11; i686; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.8-2-686-smp) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.9-10.1.aur.4; X11; pl) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux 2.6.9; X11) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; de, en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; de) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux) KHTML/3.3.91 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux) KHTML/3.3.92 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; ppc) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; X11; i686; en_US) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; X11; i686; es, en_US) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; X11; i686) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; X11; x86_64; de) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; Linux; x86_64) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; pl, en_US) KHTML/3.3.2 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; pl) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.3; X11; de) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.4; FreeBSD) KHTML/3.4.0 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '4' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.4; Linux 2.6.11-rc4; X11; en_US) KHTML/3.4.0 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '4' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.4; Linux; en_US) KHTML/3.4.0 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '4' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.4; Linux) KHTML/3.4.0 (like Gecko)" + family: "Konqueror" + major: '3' + minor: '4' + patch: + - user_agent_string: "Mozilla/6.0 (compatible; Konqueror/4.2; i686 FreeBSD 6.4; 20060308)" + family: "Konqueror" + major: '4' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020126)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020202)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc1; i686 Linux; 20020224)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020703)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20020911)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc3; i686 Linux; 20021022)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.0-rc4; i686 Linux; 20020719)" + family: "Konqueror" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1-rc3; i686 Linux; 20020510)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1-rc4; i686 Linux; 20020710)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020609)" + family: "Konqueror" + major: '3' + minor: '1' + patch: + - user_agent_string: "Kurzor/1.0 (Kurzor; http://adcenter.hu/docs/en/bot.html; cursor@easymail.hu)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Lament/7.8 (compatible; Netscape 5.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "larbin_2.6.3 (larbin-2.6.3@unspecified.mail)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "larbin_2.6.3 larbin-2.6.3@unspecified.mail" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LB-Crawler/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LG/U8110/v2.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "fetch libfetch/2.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "libwww-perl/5.79" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT306/R101 [Html2Wml/0.4.11 libwww-perl/5.79]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "testJapanequeDelicious/0.1 libwww-perl/5.803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "W3C-checklink/4.1 [4.14] libwww-perl/5.803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; Linkman)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Links" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Links (030709; Linux 2.6.7-bootsplash i686; fb)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LINKS Mozilla/2.0 (compatible; MSIE 10.0)" + family: "IE" + major: '10' + minor: '0' + patch: + - user_agent_string: "Links (0.92; Linux 2.2.14-5.0 i586)" + family: "Links" + major: '0' + minor: '92' + patch: + - user_agent_string: "Links (0.96; Linux 2.4.9-e.38.1RS i686)" + family: "Links" + major: '0' + minor: '96' + patch: + - user_agent_string: "Links (0.96; Unix)" + family: "Links" + major: '0' + minor: '96' + patch: + - user_agent_string: "Links (0.97pre3; Linux 2.4.18-6mdk i586)" + family: "Links" + major: '0' + minor: '97' + patch: + - user_agent_string: "Links (0.98; Darwin 7.6.0 Power Macintosh; 90x50)" + family: "Links" + major: '0' + minor: '98' + patch: + - user_agent_string: "Links/0.98 (fdafsd; Unix; 80x25)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Links (0.98; Linux 2.2.25 i586; 100x37)" + family: "Links" + major: '0' + minor: '98' + patch: + - user_agent_string: "Links (0.98; Linux 2.4.20 i686; 80x34)" + family: "Links" + major: '0' + minor: '98' + patch: + - user_agent_string: "Links (0.98; Linux 2.4.25-20040331b i686; 80x50)" + family: "Links" + major: '0' + minor: '98' + patch: + - user_agent_string: "Links (0.98; Unix)" + family: "Links" + major: '0' + minor: '98' + patch: + - user_agent_string: "Links (0.98; Unix; 100x37)" + family: "Links" + major: '0' + minor: '98' + patch: + - user_agent_string: "Links (0.99; Linux 2.6.8.1-4-386 i686; 198x66)" + family: "Links" + major: '0' + minor: '99' + patch: + - user_agent_string: "Links (0.99pre14; CYGWIN_NT-5.1 1.5.10(0.116/4/2) i686; 111x39)" + family: "Links" + major: '0' + minor: '99' + patch: + - user_agent_string: "Links (0.99pre8; Unix; 80x25)" + family: "Links" + major: '0' + minor: '99' + patch: + - user_agent_string: "Links (1.00pre10; Darwin 5.5 Power Macintosh; 80x24)" + family: "Links" + major: '1' + minor: '00' + patch: + - user_agent_string: "Links (1.00pre12; Linux 2.6.10-grsec i686; 139x54) (Debian pkg 0.99+1.00pre12-1)" + family: "Links" + major: '1' + minor: '00' + patch: + - user_agent_string: "Links (1.00pre12; Linux 2.6.2 i586; 80x24) (Debian pkg 0.99+1.00pre12-1)" + family: "Links" + major: '1' + minor: '00' + patch: + - user_agent_string: "Links (1.00pre3; SunOS 5.9 i86pc; 80x24)" + family: "Links" + major: '1' + minor: '00' + patch: + - user_agent_string: "Links (2.0; FreeBSD 4.7-RELEASE i386; 80x24)" + family: "Links" + major: '2' + minor: '0' + patch: + - user_agent_string: "Links 2.0 (http://gossamer-threads.com/scripts/links/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Links (2.0pre1; Linux 2.4.24-grsec i686; 80x25)" + family: "Links" + major: '2' + minor: '0' + patch: + - user_agent_string: "Links (2.0pre6; Linux 2.2.16 i686; x)" + family: "Links" + major: '2' + minor: '0' + patch: + - user_agent_string: "Links (2.1pre11; FreeBSD 4.9-RELEASE i386; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; FreeBSD 5.2.1-RELEASE i386; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.4.20-20.7asp i686; 80x24)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.4.22-10mdk i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.4.24 i686; 87x32)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.4.25-gentoo-r2 i686; 100x37)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.4.25-gentoo-r2 i686; 160x64)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.4.26-gentoo-r6 i686; 122x43)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.6.5-gentoo i686; 122x40)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.6.6-rc1 i686; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.6.7-gentoo-r14 i686; fb)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre11; Linux 2.6.7-ide4 i586; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre12; Linux 2.2.19-7.0.16smp i686; 128x47)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre13; Linux 2.4.7-10 i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre13; Linux 2.6.3-4mdk i686; 100x37)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; FreeBSD 4.9-RELEASE i386; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; FreeBSD 5.1-RELEASE i386; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; FreeBSD 5.2.1-RELEASE i386; 80x50)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; Linux 2.4.26-bsd21h i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; Linux 2.6.4-52-default i686; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; Linux 2.6.4-54.5-default i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; Linux 2.6.5-7.104-default i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; Linux 2.6.5 i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; OpenBSD 3.4 i386)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre14; OpenBSD 3.6 i386)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; CYGWIN_NT-5.0 1.3.1(0.38/3/2) i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; FreeBSD 4.10-RELEASE i386; 131x85)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; FreeBSD 4.10-RELEASE i386; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; FreeBSD 5.2-CURRENT i386; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; FreeBSD 5.3-RELEASE i386; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; FreeBSD 5.3-RELEASE i386; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; FreeBSD 5.3-RELEASE-p5 i386; 78x28)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; FreeBSD 5.3-STABLE i386; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.2.14-5.0 i586; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.2.16 i586; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.4.18-27.7.x i586; svgalib)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.4.22-1.2115.nptl i686; braille)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.4.26 i586; 128x48)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.4.26 i686; 128x48)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.4.26 i686; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.4.27 i586; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.10-gentoo-r4 i686; 141x52)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.10-gentoo-r4n i686; fb)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.10-gentoo-r5 i686; 100x38)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.10-gentoo-r6 i686; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.6tlahuizcalpacuhtli i486; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.9-gentoo-r1-g4 ppc; 160x53)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.9-gentoo-r1 i686; 128x48)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.9-gentoo-r1 x86_64; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; Linux 2.6.9 i686; 128x48)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; NetBSD 2.99.11 amd64; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre15; OpenBSD 3.6 i386; x)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre16; Linux 2.6.9-buz i686; 128x47)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre17; FreeBSD 5.4-PRERELEASE i386; 80x60)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre17; Linux 2.4.18-rmk7-pxa3-embedix armv5tel; 73x33)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre7; Linux 2.6.9 i686; 80x25)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre9; Linux 2.4.25 i686; fb)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "Links (2.1pre; Linux)" + family: "Links" + major: '2' + minor: '1' + patch: + - user_agent_string: "LinkSweeper/1.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Linspire Internet Suite" + family: "Other" + major: + minor: + patch: + - user_agent_string: "lmspider (lmspider@scansoft.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Lotus-Notes/5.0; Windows-NT)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Lotus-Notes/6.0; Windows-NT)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH/3.02a (http://www.learntohack.nil)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH browser 3.02a" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH Browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH Browser 3.02" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH Browser/3.02a" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH Browser 3.02a (compatible; mozilla ; Windows NT 5.1; SV1; http://www.learntohack.nil; .NET CLR 1.1.4322; http://www.learntohack.nil)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH Browser 3.02a (compatible; MSIE 6.0; Windows NT 5.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "LTH Browser 3.02a (compatible; MSIE 6.0; Windows NT 5.1; SV1; http://www.learntohack.nil; .NET CLR 1.1.4322; http://www.learntohack.nil)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "LTH Browser 3.02a (http://www.learntohack.nil)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH Browser/3.02a (http://www.learntohack.nil)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LTH Browser/3.02 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "lwp-request/2.06" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LWP::Simple/5.50" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LWP::Simple/5.68" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LWP::Simple/5.76" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LWP::Simple/5.79" + family: "Other" + major: + minor: + patch: + - user_agent_string: "LWP::Simple/5.800" + family: "Other" + major: + minor: + patch: + - user_agent_string: "lwp-trivial/1.34" + family: "Other" + major: + minor: + patch: + - user_agent_string: "lwp-trivial/1.38" + family: "Other" + major: + minor: + patch: + - user_agent_string: "lwp-trivial/1.40" + family: "Other" + major: + minor: + patch: + - user_agent_string: "lwp-trivial/1.41" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Lynx (compatible; MSIE 6.0; )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Lynx (SunOS 10)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Lynx/1.025 (CP/Build 16-bit)" + family: "Lynx" + major: '1' + minor: '025' + patch: + - user_agent_string: "Lynx/2.2 libwww/2.14" + family: "Lynx" + major: '2' + minor: '2' + patch: + - user_agent_string: "Lynx/2.6 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '6' + patch: + - user_agent_string: "Lynx/2.7.1ac-0.102+intl+csuite libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '7' + patch: '1' + - user_agent_string: "Lynx/2.7.1 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '7' + patch: '1' + - user_agent_string: "Lynx/2.7.2 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '7' + patch: '2' + - user_agent_string: "Lynx/2.8 (incompatible; NCSA HALOS; HAL9000" + family: "Lynx" + major: '2' + minor: '8' + patch: + - user_agent_string: "Lynx/2.8rel.2 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: + - user_agent_string: "Lynx/2.8.1rel.2 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '1' + - user_agent_string: "Lynx/2.8.2rel.1 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '2' + - user_agent_string: "Lynx/2.8.3dev.18 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.3dev.6 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.3dev.8 libwww-FM/2.14FM" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.3dev.9 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.3rel.1 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.3rel.1 libwww-FM/2.14FM" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.3rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.4" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.3rel.1 libwww-FM/2.14 SSL-MM/1.4 OpenSSL/0.9.6" + family: "Lynx" + major: '2' + minor: '8' + patch: '3' + - user_agent_string: "Lynx/2.8.4rel.1" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 Dillo/0.7.3 pl (X11; Linux)" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/0.8.6" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6a" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6b" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6c" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6e" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6g" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7a" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7b" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7c" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.4rel.1-mirabilos libwww-FM/2.14FM SSL-MM/1.4.1 OpenSSL/0.9.6c" + family: "Lynx" + major: '2' + minor: '8' + patch: '4' + - user_agent_string: "Lynx/2.8.5dev.12 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7a" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.16 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.16 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6b" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.16 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7a" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.2 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6a" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.7 libwww-FM/2.14 SSL-MM/1.4.1" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.7 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6b" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.7 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.7 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7a" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.8 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.6g" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5dev.9 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7-beta3" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5rel.1 libwww-FM/2.14" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/0.8.12" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/1.0.16" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7c" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7d" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.5rel.2 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7d" + family: "Lynx" + major: '2' + minor: '8' + patch: '5' + - user_agent_string: "Lynx/2.8.6dev.11 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7d" + family: "Lynx" + major: '2' + minor: '8' + patch: '6' + - user_agent_string: "Lynx/2.8.6dev.6 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7d" + family: "Lynx" + major: '2' + minor: '8' + patch: '6' + - user_agent_string: "LynX 0.01 beta" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MacNetwork/1.0 (Macintosh)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Metager2 (http://metager2.de/site/webmaster.php)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MicroSux 6.6.6 (fucked up v9.1) 2 bit" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Minstrel-Browse/1.0 (http://www.minstrel.org.uk/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Missigua Locator 1.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MnoGoSearch/3.2.31" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mosaic for Amiga/1.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.0 (compatible; NCSA Mosaic; Atari 800-ST)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mosaic/0.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA_Mosaic/1.0 (X11; FreeBSD 1.2.0 i286) via proxy gateway CERN-HTTPD/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA_Mosaic/2.0 (compatible; MSIE 6.0;Windows XP),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "NCSA_Mosaic/2.0 (Windows 3.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA_Mosaic/2.0 (Windows NT 5.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mosaic/2.1 (Amiga ARexx)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mosaic/2.1 (compatible; MSIE; Amiga ARexx; SV1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA_Mosaic/2.7b5 (X11;Linux 2.0.13 i386) libwww/2.12 modified" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA Mosaic/2.7b5 (X11;Linux 2.6.7 i686) libwww/2.12 modified" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA_Mosaic/2.7b5 (X11;Linux 2.6.7 i686) libwww/2.12 modified" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA Mosaic/2-7-6 (X11;OpenVMS V7.2 VAX)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Mosaic/2.8; Windows NT 5.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA_Mosaic/2.8 (X11; FreeBSD 5.2.1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA Mosaic/3.0.0 (Windows x86)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AIR_Mosaic(16bit)(demo)/v3.09.05.08" + family: "Other" + major: + minor: + patch: + - user_agent_string: "mMosaic/3.6.6 (X11;SunOS 5.8 sun4m)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MOT-V551/08.17.0FR MIB/2.2.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MovableType/3.0D" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozdex/0.06-dev (Mozdex; http://www.mozdex.com/bot.html; spider@mozdex.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "mozilla (compatible; MSIE 3.0; Mac_PowerPC)" + family: "IE" + major: '3' + minor: '0' + patch: + - user_agent_string: "alpha/06" + family: "Other" + major: + minor: + patch: + - user_agent_string: "alpha/06 (AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "alpha/06 (compatible; alpha/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ALPHA/06 (compatible; ALPHA/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ALPHA/06 (compatible; Win98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AmigaOS 3.4 S.E.K-Tron" + family: "Other" + major: + minor: + patch: + - user_agent_string: "AmigaOS 5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/0.001 (uncompatible; TuringOS; Turing Machine; 0.001; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/0.02 [fu] (Dos62; Panzer PzKpfw Mk VI; SK Yep, its official I'm a nazi, or an asshat whichever.)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/0.1 [es] (Windows NT 5.1; U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.000 (AOS; U; en) Gecko/20050301" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.0 (Macintosh; 68K; U; en)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.1N (X11; I; SunOS 5.4 sun4m)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.4.1 (windows; U; NT4.0; en-us) Gecko/25250101" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.6 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040812 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla 1.7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla 1.7.2 (FreeBSD 5.2.1) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla 1.75 on Linux: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/2.01 (Win16; I) via HTTP/1.0 deep.space.star-travel.org/" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/2.0 (compatible ; MSIE 3.02; Windows CE; PPC; 240x320)" + family: "IE" + major: '3' + minor: '02' + patch: + - user_agent_string: "Mozilla/24.4 (X11; I; Linux 2.4 i686; U) [en-ES]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01-C-MACOS8 (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01SGoldC-SGI (X11; I; IRIX 6.3 IP32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01 (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.04Gold (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.04 (Win16; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.04 (Win16; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.04 (X11; I; SunOS 5.5.1 sun4u) via HTTP/1.0 depraved-midget.onlinescanner.com/" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (DreamKey/2.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 [en] (AWV2.20f)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (Liberate DTV 1.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (Planetweb/2.100 JS SSL US; Dreamcast US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (Windows 98;U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (Windows 98; Win 9x 4.90)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (x86 [en] Windows NT 5.1; Sun)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.x (I-Opener 1.1; Netpliance)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (0000000000; 0000 000; 0000000 00 000)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (0000000000; 0000 0000; 00000000000)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.00 [en] (Compatible; RISC OS 4.39; MSIE 5.01; Windows 98; Oregano 1.10)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (6; probably not the latest!; Windows 2005; H010818)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (AmigaOS 3.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (combatible; MSIE 6.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; alpha 06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; alpha/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; ALPHA/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; AmigaOS; Chimera)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; GoogleToolbar 2.0.113-big; Windows XP 5.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; ICS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; IE-Favorites-Check-0.5)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Mozilla 4; Linux; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0b1; X11; I; Linux 2.4.18 i686)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98)Gecko/20020604" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (Compatible; MSIE 5.5; Windows NT 4.0; QXW03002)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (Compatible; MSIE 5.5; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 ( compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AmigaOs)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla /4.0 (compatible; MSIE 6.0; i686 Linux)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; NetBSD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (Compatible; MSIE 6.0; SunOS 5.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (Compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 7.1; Windows NT 7.1; Blueberry Bulid 2473)" + family: "IE" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.0 (Compatible; Windows_NT 5.0; MSIE 6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (exemplo; msiex; amiga)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (fantomBrowser)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 ( http://www.brismee.com/ ; mailto:guy.brismee@advalvas.be ; NSA/666.666.666 ; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 ( http://www.brismee.com/ ; mailto:guy.brismee@laposte.net ; NSA/666.666.666 ; SV1; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (JemmaTheTourist;http://www.activtourist.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 look-alike" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (Macintosh; U; PPC Mac OS X; en)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (MobilePhone SCP-5500/US/1.0) NetFront/3.0 MMP/2.0" + family: "NetFront" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (Mozilla/4.0; 6.0; MSIE 6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (MSIE/6.0; compatible; Win98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (MSIE 6.0; Windows NT 5.1; .NET CLR 1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (PDA; SL-C860/1.0,OpenPDA/Qtopia/1.3.2) NetFront/3.0" + family: "NetFront" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (PDA; Windows CE/1.0.0) NetFront/3.0" + family: "NetFront" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (PDA; Windows CE/1.0.1) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.0 (); ; ; ()" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (SKIZZLE! Distributed Internet Spider v1.0 - www.SKIZZLE.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (SmartPhone; Symbian OS/0.9.1) NetFront/3.0" + family: "NetFront" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (stat 0.12) (statbot@gmail.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (SunOS 5.8)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (Windows NT 4.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (Windows XP 5.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20040803 Debian-1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla 4.75 [en] (X11; I; Linux 2.2.25 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla 4.8 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla 5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (000000000; 0; 000 000 00 0 000000; 00000; 00000000) 00000000000000 0000000000" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (000000000; 0; 000 000 00 0; 00000) 000000000000000 0000000 0000 000000 0000000000" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (000000000; 0; 000 000 00 0; 00) 0000000000000000000 0000000 0000 000000 0000000000000" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (000000000; 0; 000 000 00 0; 00000) 0000000000000000000 0000000 0000 000000 0000000000000" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (000000000; 0; 000 000 00 0 000000; 00000; 00000000) 00000000000000 00000000000 000000000000000000" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (000000000; 0; 000 000 00 0; 00000) 0000000000000000000 0000000 0000 000000 0000000000000,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.001 (Macintosh; N; PPC; ja) Gecko/25250101 MegaCorpBrowser/1.0 (MegaCorp, Inc.)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.001 (windows; U; NT4.0; en-us) Gecko/25250101" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0adfasdf" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (ALL YOUR BASE ARE BELONG TO US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (AmigaOS 3.5, Amiga, 0wnx0r3d by eric) Gecko/20020604" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (AmigaOS; sektron)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Atari; U; Atari 800; en-US) Gecko/20040206 Galaxian/2.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (BeOS; U; BeOS BePC; en-CA; rv:1.5b) Gecko/20050308 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; 0.8) Gecko/20010208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.4) Gecko/20030701" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (CIA Secure OS; U; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Clustered-Search-Bot/1.0; support@clush.com; http://www.clush.com/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Mozilla/4.0; MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Gecko/20050105 Debian/1.7.5-1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; X11; Linux i686; Konqueror/3.2) (KHTML, like Gecko) Gentoo/2004" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (DeadPeopleTasteLikeChicken.biz)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [de] (OS/2; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows NT 5.1; U; en-US;)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows; U; en-US; rv:1.4)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows; U; Win98; en-US; rv.0.9.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows; U; WinNT5.1; en-GB; rv:1.4)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows XP; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (FreeBSD; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.2" + family: "K-Meleon" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Google-Gbrowser/0.0.9a; Windows NT 5.1; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Hector)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 IE" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (incompatible; MSIE 6.9; Secret OS 3.2; FIB;)" + family: "IE" + major: '6' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Java 1.4.1_05; Windows XP 5.1 x86; en) ICEbrowser/v6_0_0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Java 1.4.2_02; Windows XP 5.1 x86; en) ICEbrowser/v6_0_0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Java 1.4.2_05; Windows XP 5.1 x86; en) ICEbrowser/v5_2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (kombpartilb; Verhsun; Plasdfjoi; SV1; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Linux i386; en-US) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-EN; rv:0.9.4)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC;) Gecko DEVONtech" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; Incompatible my ass! What if I don't want your jerky, elitist, ugly-assed CSS crap? Screw you!)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.6 (KHTML, like Gecko) NetNewsWire/2.0b10" + family: "NetNewsWire" + major: '2' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.6 (KHTML, like Gecko) NetNewsWire/2.0b22" + family: "NetNewsWire" + major: '2' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0+(Macintosh;+U;+PPC+Mac+OS+X;+en)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/103u (KHTML, like Gecko) safari/100" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/124 (KHTML, like Gecko)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/124 (KHTML, like Gecko, Safari) Shiira/0.9.1" + family: "Shiira" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko, Safari) Shiira/0.9.2" + family: "Shiira" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko, Safari) Shiira/0.9.2.2" + family: "Shiira" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.4 (KHTML, like Gecko, Safari) Shiira/0.9.2.2" + family: "Shiira" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.6 (KHTML, like Gecko, Safari) Shiira/0.9.3" + family: "Shiira" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit (KHTML, like Gecko) AIQtech" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit (KHTML, like Gecko) DEVONtech" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/124 (KHTML, like Gecko) safari/125.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.2 (KHTML, like Gecko, Safari) Shiira/0.9.2.2" + family: "Shiira" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.22" + family: "OmniWeb" + major: '563' + minor: '22' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.29" + family: "OmniWeb" + major: '563' + minor: '29' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.33" + family: "OmniWeb" + major: '563' + minor: '33' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.34" + family: "OmniWeb" + major: '563' + minor: '34' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v496" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v549" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v558" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v558.43" + family: "OmniWeb" + major: '558' + minor: '43' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v558.46" + family: "OmniWeb" + major: '558' + minor: '46' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v558.48" + family: "OmniWeb" + major: '558' + minor: '48' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20020909 Chimera/0.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20030917 Camino/0.7" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/125.6 (KHTML, like Gecko, Safari) Shiira/0.9.3" + family: "Shiira" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; da-DK; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.2b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; de-DE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.6) Gecko/20050331 Camino/0.8.3" + family: "Camino" + major: '0' + minor: '8' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a2) Gecko/20040714" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a5) Gecko/20041114 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a5) Gecko/20041121 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20041201 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20050103 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20050111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b2) Gecko/20050224 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b2) Gecko/20050317 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b2) Gecko/20050401 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050115 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050127 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050130 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050131 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050203 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050217 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; fr-FR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O) Gecko Camino" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; it-IT; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; zh-tw) AppleWebKit/125.5.6 (KHTML, like Gecko, Safari) Shiira/0.9.3" + family: "Shiira" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (MSIE 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (MSIE 6.0) Gecko/20011018" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla 5.0 (MSIE 6.0 Win 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (NetBSD 1.6.2; U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (NetWare; U; NetWare 6.0.04; en-PL) ICEbrowser/5.4.3 NovellViewPort/3.4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (No data found)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (not MSIE5.5; X11; U; HP-UX 9000/785; en-US; rv:1.1) Gecko/20020828" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 3; en-US; rv:1.6) Gecko/20040117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.7.5) Gecko/20041220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.8a2) Gecko/20040719" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4; da-DK; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (ROIL FF/1.0; Windows NT 5.1 64-bit)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (RSS Reader Panel)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Sage)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (tTh @ Cette) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (U; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Unknown; 32-bit)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (U; PPC; en) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Version: 1251 Type:4565)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Version: 245 Type:180)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Version: 3247 Type:3276)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Version: 4445 Type:1763)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (VMS; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows 3.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U; en-CA) Gecko/20041107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U; rv:1.7.5) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1,de-DE)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win3.1; en-US; rv:1.0.0) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-AT; 0.7) Gecko/20010109" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-AT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:1.7.6) Gecko/20050321 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.0; CMCE) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.2b) Gecko/20021016" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.8.0.1c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041220 K-Meleon/9.0" + family: "K-Meleon" + major: '9' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040707 MSIE/7.66" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8a3) Gecko/20040817" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8b2) Gecko/20050317 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8b2) Gecko/20050329 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8b) Gecko/20050217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:7.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; es-ES; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; hu; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pl-PL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pl-PL; rv:1.7.6) Gecko/20050319" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; PL; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pt-BR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; sv-SE; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; sv-SE; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-AT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.5) Gecko/20041220 K-Meleon/0.9" + family: "K-Meleon" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.8a6) Gecko/20050111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; fr-FR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; PL; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; pt-BR; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; Bush knew, failed to act.)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.5) Gecko/20041108 STFU/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.6) Gecko/20050321 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; el-GR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.5) Gecko/20041110 FireFox/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.6) Gecko/20050321 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; 0.7) Gecko/20010109" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; Like Navigator 6.2) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2b) Gecko/20020923 Phoenix/0.1" + family: "Phoenix" + major: '0' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2b) Gecko/20020929 Phoenix/0.2" + family: "Phoenix" + major: '0' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5b) Gecko/20030823 Mozilla Firebird/0.6.1+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20031016" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040803 Mnenhy/0.6.0.104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.3) Gecko/20040910 Mnenhy/0.6.0.101" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.0.0e" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.1.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.4) Gecko/20041002" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.4) Gecko/20041010 FireFox/0.9b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.4) Gecko/20041010 K-Meleon/0.9b" + family: "K-Meleon" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Plasmahuman/1.0 (Firefox 1.0 Get it. Now.)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.2d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041220 K-Meleon/0.9" + family: "K-Meleon" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050218" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050308 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040621" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a4) Gecko/20040927" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a5) Gecko/20041122,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a5) Gecko/20041122 MultiZilla/1.7.0.0o" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6) Gecko/20050109" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6) Gecko/20050110" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6) Gecko/20050111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6) Gecko/20050111 Mnenhy/0.7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b2) Gecko/20050221" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b2) Gecko/20050314 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b2) Gecko/20050323 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b2) Gecko/20050330 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050120" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050211" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050216" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-AR; rv:1.7.5) Gecko/20041108 Clab_Browser_1.0_www.cristalab.com/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-AR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-AR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.7.6) Gecko/20050303 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fi-FI; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.0.0) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.8a6+) Gecko/20050111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.8b+) Gecko/20050117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7.6) Gecko/20050311 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; nl-NL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; nl-NL; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.7.2) Gecko/20040803 Mnenhy/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; PL; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pt-BR; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pt-BR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.7.4) Gecko/20040926" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; tr-TR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-TW; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ca-AD; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7.6) Gecko/20050318 Firefox/1.0.2 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7.6) Gecko/20050330 Firefox/1.0.2 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; da-DK; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; da-DK; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.5) Gecko/20041108 Firefox/LukasHetzi" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8a3) Gecko/20040817" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041107 Junglelemming/4.3.7.1 (Wesma Pictures)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041122 Muuuh/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.6) Gecko/20050223" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.6) Gecko/20050321 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-CA; rv:1.8b2) Gecko/20050312 Firefox/1.0+ (tinderbox beast)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.0.1) Gecko/20020823" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.0.2) Gecko/20021120" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.6) Gecko/20050316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.6) Gecko/20050321 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2.1) Gecko/20021130,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040709" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040910 Mnenhy/0.6.0.104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.0.0d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040910 Sylera/2.1.20" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firechicken/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firematt/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Hypnotoad/1.0 (Firefox/1.0)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 IE/6.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Junglelemming/1.0 (Wesma Pictures)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Microsoft/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Mozilla/4.0/MSIE 6.0" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Mozilla/5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 MSIE/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107-RB Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.1c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.1j" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.8.0.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041219 Sylera/2.1.21" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041220 K-Meleon/0.9" + family: "K-Meleon" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041222 MOOX (M3)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050308 Firefox/0.9.6" + family: "Firefox" + major: '0' + minor: '9' + patch: '6' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 (All your Firefox/1.0.1 are belong to Firesomething)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223 Firelemur/1.0.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 CompeGPS/1.0.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Hypnotoad/1.0.1 (Firefox/1.0.1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Supergecko/1.0.1 (IE6)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050308 Firefox/1.0.1 (MOOX M1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US, rv:1.7.6) Gecko/20050308 Firefox/1.0.1 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050308 Firefox/1.0.1 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050308 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050312 Firefox/1.0.1 (stipe)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050314 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050315 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050317 Seastarfish/1.0.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050319" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050323" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050324 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 FairFox/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Unknow/x" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a4) Gecko/20040927" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a5) Gecko/20041123 K-Meleon/0.9" + family: "K-Meleon" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a5) Gecko/20041217 Mozilla Sunbird/0.2RC1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20040101" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050107 MultiZilla/1.7.0.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050112" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050226" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050228 Firefox/1.0+ (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050307 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050313 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050315 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050319 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050320 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050321 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050330 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050401" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050128 Mnenhy/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050131 Firefox/1.0+ (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050201" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050202 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050205" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050217 MultiZilla/1.7.0.2d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:) Gecko/20040309" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US;) Unchaos/Crawler" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.7.5) Gecko/20041210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; eu-ES; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; eu-ES; rv:1.7.3) Gecko/20040910,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; eu-ES; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; eu-ES; rv:1.7.6) Gecko/20050225 Firefox/1.0.1,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fi-FI; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041108 Mozilla/4.0/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041108 Mozilla /4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 2000)/1.0" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041109 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.0o" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.8)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; he-IL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; hr-HR; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; hu-HU; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.3.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.6) Gecko/20050311 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ko-KR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nb-NO; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.6) Gecko/20050321 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; PL; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; PL; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; PL; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.0.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.0.2) Gecko/20040823" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 xb0x/0.10.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sl-SI; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; tr-TR; rv:1.7.6) Gecko/20050321 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; uk-UA; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; cs-CZ; rv:1.7.6) Gecko/20050318 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-GB; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20041217 WebWasher 3.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20041220 K-Meleon/0.9" + family: "K-Meleon" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8b2) Gecko/20050307 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; hu-HU; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; pl-PL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; ru-RU; rv:1.7.4) Gecko/20040926" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; ru-RU; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; tr-TR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-AT; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows, U, WinNT4.0, en-US, rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; es-ES; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; es-ES; rv:1.7.6) Gecko/20050303 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; fi-FI; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; Windows 98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; ; Windows NT 5.1; rv:1.7.5) Gecko/20041107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux; en-US) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; DragonFly i386; en-US; rv:1.7.5) Gecko/20041112 Foobar/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; de-DE; rv:1.7.6) Gecko/20050322 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-GB; rv:1.7.5) Gecko/20041228" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20030702" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20030723" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20031008 Epiphany/1.0" + family: "Epiphany" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20031017" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5a) Gecko/20030926 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031203" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031207 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040128" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.2) Gecko/20040829" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.2) Gecko/20041016" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041201 Epiphany/1.4.6" + family: "Epiphany" + major: '1' + minor: '4' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041204 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041219" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041221 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050103" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050108" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050112" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050118" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050124" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050305" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050306" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.6) Gecko/20050302 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.6) Gecko/20050315 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7a) Gecko/20040311" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040701 Epiphany/1.2.8" + family: "Epiphany" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20050314 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8a5) Gecko/20041214" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i686; en-US; rv:1.8a5) Gecko/20041106" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.6) Gecko/20040304" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.6) Gecko/20040816" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.6) Gecko/20040831" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/800; en-US; rv:1.4) Gecko/20030730" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; IRIX64 IP28; en-US; rv:1.7.5) Gecko/R-A-C Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; IRIX64 IP30; en-US; rv:1.7.5) Gecko/R-A-C Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; IRIX64 IP35; en-US; rv:1.7.5) Gecko/20041230" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux 2.4.2-2 i686; en-US; 0.7) Gecko/20010316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux 2.4.2 i686, en) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux 2.6.11.4-gentoo-xD i686; pl-PL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux 2.6.3-FTSOJ i686; en-US; rv:1.6)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux 2.6.4 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux; fr-FR; rv:1.6) Gecko/20040207 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.0.2) Gecko/20030708" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041209 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu4-warty99)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041219 Firefox/1.0 (Debian package 1.0+dfsg.1-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.6) Gecko/20050325 Firefox/1.0.2 (Debian package 1.0.2-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; it-IT; rv:1.4.1) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; da-DK; rv:1.7.5) Gecko/20041221" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686, de)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.4.2) Gecko/20040921" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6; 009f52b638a35a83ea5212109fc44eed;) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040115 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.2) Gecko/20040906" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.3) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20041218" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20041220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20041221" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20041231" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20050125" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.8a5) Gecko/20041121" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.8a5) Gecko/20041122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.8a6) Gecko/20050111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.8b2) Gecko/20050317" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.6)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.2) Gecko/20040906" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.6) Gecko/20050301 Firefox/1.0.1 (Debian package 1.0.1-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.6) Gecko/20050306 Firefox/1.0.1 (Debian package 1.0.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; el-GR; rv:1.7.5) Gecko/20041209 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu4-warty99)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.5) Gecko/20050312 Epiphany/1.4.8" + family: "Epiphany" + major: '1' + minor: '4' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.6) Gecko/20050315 Firefox/1.0 (Ubuntu package 1.0.1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.6) Gecko/20050325 Firefox/1.0.2 (Debian package 1.0.2-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20030401 Debian/1.0.2-2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20030821" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1; aggregator:Rojo; http://rojo.com/) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3.1) Gecko/20030721 wamcom.org" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031218" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040412" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20040805" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20041004" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20041010" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20050104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4b) Gecko/20030522 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030702" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20040206" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5b) Gecko/20030903 Firebird/0.6.1+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031030 MultiZilla/1.5.0.3l" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031125" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031222" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040625" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040914 Epiphany/1.2.5" + family: "Epiphany" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20050202 Linspire/1.6-5.1.0.50.linspire2.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20041029" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040803 MultiZilla/1.6.0.0e" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040806" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040810" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040901" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040917" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040918 Epiphany/1.4.6" + family: "Epiphany" + major: '1' + minor: '4' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040919 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040920" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040921" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040924 Debian/1.7.3-2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040924 Epiphany/1.4.4 (Ubuntu)" + family: "Epiphany" + major: '1' + minor: '4' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040929" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040930" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041001 Epiphany/1.2.9" + family: "Epiphany" + major: '1' + minor: '2' + patch: '9' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Epiphany/1.4.5" + family: "Epiphany" + major: '1' + minor: '4' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Epiphany/1.4.6" + family: "Epiphany" + major: '1' + minor: '4' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041019 MultiZilla/1.7.0.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041023" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041105" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041202 Debian/1.7.3.x.1-39" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20050112" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5;) Gecko/20020604 OLYMPIAKOS SFP" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 firefox/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 IE/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Microsoft/IE6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 MSIE/5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.1" + family: "Firefox" + major: '1' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111 Firefox (MSIE 6.0)/1.0" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111 Mozilla/1.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041118 Mozilla/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041217 Mnenhy/0.6.0.104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041217 Mnenhy/0.7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041217 msie" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.7.0.2d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041219" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041220 MultiZilla/1.7.0.1f" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041222" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041223" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041224" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041226" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041226 Epiphany/1.4.7" + family: "Epiphany" + major: '1' + minor: '4' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041227" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041228 Epiphany/1.4.6" + family: "Epiphany" + major: '1' + minor: '4' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041229" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041229 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041231" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Debian/1.4-6 StumbleUpon/1.87" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Epiphany/1.4.7" + family: "Epiphany" + major: '1' + minor: '4' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Epiphany/1.4.7 (Debian package 1.4.7-3)" + family: "Epiphany" + major: '1' + minor: '4' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 MultiZilla/1.7.0.1j" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050108" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050110 Spica/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050114 Microsoft/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050120" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050128" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050211 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050218" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050219 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050221 msie/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-6ubuntu1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050223 Firefox/1.0 (Debian package 1.0.x.2-15)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050309" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050302 HypnoToad/1.0.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050304 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050306 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050308 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050309 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050311 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050311 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050312 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050314 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050315 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050317 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050318 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050321 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050324 Debian/1.7.6-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050324 Epiphany/1.4.8 (Debian package 1.4.8-2)" + family: "Epiphany" + major: '1' + minor: '4' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050324 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050324 Firefox/1.0 (Ubuntu package 1.0.2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050325 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050325 Firefox/1.0.2 (Debian package 1.0.2-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050328 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050401 Firefox/1.0.2 (Debian package 1.0.2-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040618 Epiphany/1.2.6" + family: "Epiphany" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040903 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040907 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040909 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20041027 NaverBot/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040729" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040817" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a5) Gecko/20041121" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a5) Gecko/20041124" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a6) Gecko/20050107 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a6) Gecko/20050111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b2) Gecko/20050227" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050314" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; SkipStone 0.8.4) Gecko/20020722" + family: "SkipStone" + major: '0' + minor: '8' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.5) Gecko/20031107 Debian/1.5-3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1 StumbleUpon/1.999" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.6) Gecko/20050303 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.6) Gecko/20050306 Firefox/1.0.1 (Debian package 1.0.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.6) Gecko/20050312 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fi-FI; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.4.2) Gecko/20040308" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.3) Gecko/20041020" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.4.3) Gecko/20041004" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20050221 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-6ubuntu1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.6) Gecko/20050306 Firefox/1.0.1 (Debian package 1.0.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.6) Gecko/20050315 Firefox/1.0 (Ubuntu package 1.0.1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686) Gecko/20041107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.7.5) Gecko/20041119 Firefox/1.0 (Debian package 1.0-3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.7.6) Gecko/20050325 Firefox/1.0.2 (Debian package 1.0.2-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.4.3) Gecko/20041004" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.7.3) Gecko/20040922" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7.3) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ko-KR; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.6) Gecko/20040122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.5) Gecko/20050102" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.5) Gecko/20050111 Fedora/1.7.5-3.0.3.kde" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.6) Gecko/20050303 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.6) Gecko/20050306 Firefox/1.0.1 (Debian package 1.0.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.6) Gecko/20050322 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; PL; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; PL; rv:1.5) Gecko/20031020" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; PL; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.7.3) Gecko/20040930" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041001 Superholio/0.10.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041020 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041113 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20050329 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.7.6) Gecko/20050315 Firefox/1.0 (Ubuntu package 1.0.1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; tr-TR; rv:1.7.2) Gecko/20040804 Epiphany/1.2.8" + family: "Epiphany" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i?86; en-US; rv:1.6) Gecko/20040116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.3) Gecko/20041207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20050105 Debian/1.7.5-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20050107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20050221 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-6ubuntu1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.6) Gecko/20050306 Firefox/1.0.1 (Debian package 1.0.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.6) Gecko/20050325 Firefox/1.0.2 (Debian package 1.0.2-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux sparc; en-US; rv:1.5) Gecko/20041129" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; ca-AD; rv:1.7.5) Gecko/20050210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.3) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.3) Gecko/20041020" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050101" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050201" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050310" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.6) Gecko/20050305" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; nl-NL; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.3) Gecko/20050117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.5) Gecko/20041205 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.6) Gecko/20050308 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD macppc; en-US; rv:1.5) Gecko/20040102 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD macppc; en-US; rv:1.7.2) Gecko/20040825 Camino/0.8.1" + family: "Camino" + major: '0' + minor: '8' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.2.1) Gecko/20030228" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040830 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20050110" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20050312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.7.6) Gecko/20050312 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; OpenVMS AlphaServer_ES40; en-US; rv:1.4) Gecko/20041126 FireFox/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OSF1 alpha; en-US; rv:1.4) Gecko/20030903" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.4) Gecko/20040126" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.4) Gecko/20040414" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7.3) Gecko/20040919" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7) Gecko/20041221" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.2) Gecko/20021211" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4) Gecko/20041214" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.3) Gecko/20040914" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.5) Gecko/20050105" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.6) Gecko/20050301 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.6) Gecko/20050313 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040629" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20041221" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; fr-FR; rv:1.7.5) Gecko/2004" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; System/V-POSIX alpha; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; UNICOS/mk 21164a(EV5.6) Cray T3E; en-US; huelk) Gecko/20040413 SynLabs/0.6.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X) Gecko/20021016" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.5 (compatible; alpha/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.666 [en] (X11; U; FreeBSD 4.5-STABLE i386)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.01 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 (BEOS; U ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (6.0; comtemptible)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 [en] (Atari 2600; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 [en] (Win32; Escape 5.03; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 [en] (Win32; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 [en] (X11; Linux 2.4.26 Sparc64) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 [en] (X11; Linux 2.6.10 Sparc 64) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 (Linux; Escape/5.0; acentic client)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.1 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.1 [ja] (X11; I; Linux 2.2.13-33cmc1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.2 [en] (BeOS; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.2 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.00; msie" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.02 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.0 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.1 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.2 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7 [en] (Debian Sarge; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/9.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/9.0 (Atari2600; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/9.2 (Windows; U; Windows 3.11; en-US; rv:4.9.3) Gecko/20050213 Firefox/4.2" + family: "Firefox" + major: '4' + minor: '2' + patch: + - user_agent_string: "Mozilla/9.876 (alpha/06)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (compatible; X11; I; Linux 2.0.32 i586)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla Epinard" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla FireFox (compatible)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (FreeBSD 5.3-CURRENT)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (IE4 Compatible; I; Mac_PowerPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (IE5 Compatible; I; Mac_PowerPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla(IE Compatible)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (larbin2.6.3@unspecified.mail)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla Windows" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (X11; E; Linux )" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (X11; I; Linux 2.0.32 i286)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (X11; I; Linux 2.0.32 i586)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SEKTron alpha/06; AmigaOS" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 [en] (X11; U; Linux 2.6.4; en-US; rv:0.9.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:0.9.2) Gecko/2001" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010628" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.2.1) Gecko/20010901" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.3) Gecko/20010801" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20010914" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20010923" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux sparc64; en-US; rv:0.9.4) Gecko/20011029" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4.2) Gecko/20021112 CS 2000 7.0/7.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.5) Gecko/20011018" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en US; rv:0.9.6+)Gecko/20011122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.6+) Gecko/20011122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:0.9.8) Gecko/20020204" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:0.9.8) Gecko/20020204" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.8) Gecko/20020204" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (U; en-US; rv:0.9.9) Gecko/20020311" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.9) Gecko/20020408" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.9) Gecko/20020412 Debian/0.9.9-6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.9) Gecko/20020501" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.9) Gecko/20020513" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0rc1) Gecko/20020417" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0rc2) Gecko/20020510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0rc3) Gecko/20020523" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0rc2) Gecko/20020510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0rc3) Gecko/20020524" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.0) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.0.0) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.0) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.0) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.0.0) Gecko/20020530" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.0.0) Gecko/20020605" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.0.0) Gecko/20020623 Debian/1.0.0-0.woody.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0+) Gecko/20020518" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20020529" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20020604" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20020607" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20020623 Debian/1.0.0-0.woody.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0; hi, Mom) Gecko/20020604" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.0.0) Gecko/20020529" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.0.0) Gecko/20020622 Debian/1.0.0-0.woody.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.0) Gecko/20020611" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20020730 AOL/7.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20020909" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20021023 Chimera/0.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.0.1) Gecko/20021219 Chimera/0.6+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.0.1) Gecko/20020830" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.0.1) Gecko/20020903" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020809" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020828" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020830" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020903" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20021003" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20021103" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20021105" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.2) Gecko/20021216" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20021120" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20021216" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20021216" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20030708" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20030716" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20031013" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.1a) Gecko/20020611" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.1b) Gecko/20020721" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-AT; rv:1.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.1) Gecko/20021005" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.1) Gecko/20030102" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.1) Gecko/20030104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1a) Gecko/20020610" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1) Gecko/20020826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1) Gecko/20020827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.1) Gecko/20020827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.1) Gecko/20020927" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/1.10 [en] (Compatible; RISC OS 4.37; Oregano 1.10)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Symbian OS/1.1.0)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2a) Gecko/20020910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2b) Gecko/20021016" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2) Gecko/20021126" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.2) Gecko/20021204" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2) Gecko/20021202" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2) Gecko/20021207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OSF1 alpha; en-US; rv:1.2) Gecko/20021205" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-GB; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; nl-NL; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.2.1) Gecko/20030324" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.2.1) Gecko/20021204" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1; aggregator:NewsMonster; http://www.newsmonster.org/) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20021130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20021204" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20021213 Debian/1.2.1-2.bunk" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030124" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030225,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030327" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2.1) Gecko/20030502 Debian/1.2.1-9woody3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.2.1) Gecko/20030225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.2.1) Gecko/20021125" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.2.1) Gecko/20030228" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; ru-RU; rv:1.2.1) Gecko/20030721" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.2.1) Gecko/20030711" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; fr-FR; rv:1.2.1) Gecko/20030711" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 (X11; U; Linux 2.6.13 i686; en-US; rv:1.2.9) Gecko/20050612 MSIE (Debian FAST Browser) v15.23 - All rights reserved - Unix - Error Processing table...
    Line 43
    " + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.3) Gecko/20030616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.3a) Gecko/20021212" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3b) Gecko/20030210" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3; MultiZilla v1.4.0.3J) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3a) Gecko/20021212" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3b; MultiZilla v1.3.1 (a)) Gecko/20030210" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.3b) Gecko/20030323" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.3) Gecko/20030321" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.3) Gecko/20030313" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3a) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3b) Gecko/20030210" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030313" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030314" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030408" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030623" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030708 Debian/1.3-4.lindows43" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.3b) Gecko/20030317" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.3) Gecko/20030317" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.3a) Gecko/20021211" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.3) Gecko/20030314" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.3.1) Gecko/20030721 wamcom.org" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.3.1) Gecko/20030723 wamcom.org" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.3.1) Gecko/20030425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.3.1) Gecko/20030425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.3.1) Gecko/20030425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; el-gr; rv:1.3.1) Gecko/20030425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3.1) Gecko/20030425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3.1) Gecko/20030425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.3.1) Gecko/20030524" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.3.1) Gecko/20030525" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.3.1) Gecko/20040413" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.3.1) Gecko/20040528" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3.1) Gecko/20030425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3.1) Gecko/20030428" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3.1) Gecko/20030517" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.3.1) Gecko/20030428" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030507" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030529" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-us; rv:1.4)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4a) Gecko/20030401" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4b) Gecko/20030507" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030529" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030612" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.4) Gecko/20030624/7.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4a) Gecko/20030401" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20030709" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20030715" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20030730" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20040127" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20040324" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.4) Gecko/20030730" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ca; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; da-DK; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.4) Gecko/20030821" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4a) Gecko/20030401" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4b) Gecko/20030507" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030529" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030617" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030703" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030704" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030714 Debian/1.4-2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030716" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030728" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030730" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030805" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030807" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030818" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030821" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030908 Debian/1.4-4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030915" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030922" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031110" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031112" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031119 Debian/1.4.0.x.1-20" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031211" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20031212" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20040107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20040116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Larbin/2.6.3 (larbin@unspecified.mail)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Larbin/2.6.3 larbin@unspecified.mail" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.4) Gecko/20031111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; gl-ES; rv:1.4) Gecko/20030703" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.4) Gecko/20030630" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.4) Gecko/20030922" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.4) Gecko/20030908" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenVMS AlphaServer_ES40; en-US; rv:1.4) Gecko/20030826 SWB/V1.4 (HP)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.4b) Gecko/20030523" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.4) Gecko/20040214" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.4) Gecko/20040510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4) Gecko/20030701" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4) Gecko/20031128" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4) Gecko/20040414" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-0; en-US; rv:1.4.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4.1) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (MacOSX; U; MacOSX; en-US; rv:1.4.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.4.1) Gecko/20031014" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4.1) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4.1) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4.1; MultiZilla v1.5.0.2j) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4.1) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.4.1) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031008" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031008 Debian/1.4-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031114 MSIE" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20040312 Debian/1.4.1-0jds1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20040406" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.4.1) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.4.1) Gecko/20031114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.4.1) Gecko/20040406" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.4.1) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.4.1) Gecko/20031114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.4.1) Gecko/20031114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.4.1) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.4.1) Gecko/20031114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.4.1) Gecko/20031209" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.4.1) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.4.1) Gecko/20031114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4.1) Gecko/20031125" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.4.2) Gecko/20040220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.4.2) Gecko/20040301" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040301" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040308" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040323" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040326" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040330" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040428" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040921" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.4.2) Gecko/20040308" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.4.2) Gecko/20040308" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.4.2) Gecko/20040220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.4.3) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20040924" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.3) Gecko/20040930" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.4.3) Gecko/20040930" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.5b) Gecko/20030904" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.1" + family: "K-Meleon" + major: '0' + minor: '8' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.2" + family: "K-Meleon" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; es-ES; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; es-ES; rv:1.5) Gecko/20031007, Mozilla/5.0 (Windows; U; Win98; es-ES; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; PL; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.5b) Gecko/20030827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; fr-FR; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5a) Gecko/20030718" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5b) Gecko/20030827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20030916" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20030925" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5 ) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.2" + family: "K-Meleon" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; PL; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.5) Gecko/20031006" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.5b) Gecko/20030827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.5b) Gecko/20030827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5b) Gecko/20030827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20030916" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20030925" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.5) Gecko/20031006" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-AT; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.2" + family: "K-Meleon" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; rv:1.5a; FreeBSD)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5a) Gecko/20030712" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5b) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031028" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20040102" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20040105" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20040110" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20040921" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.5) Gecko/20031027" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.5) Gecko/20031015" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.5) Gecko/20031031" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.5) Gecko/20031107 Debian/1.5-3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5a) Gecko/20030718" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5b) Gecko/20030827" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5b) Gecko/20030831" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20030917" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20030925" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031009" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031016" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031024" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031031" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Debian/1.5-3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Debian/1.5-3 StumbleUpon/1.906" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031111 Debian/1.5-2.backports.org.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031115 Debian/1.5-3.he-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031202" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031211 Debian/1.5-2.0.0.lindows0.0.43.45+0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031224" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031231" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20040225 Debian/1.5-2.0.0.lindows0.0.65.45+0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20040414" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.5) Gecko/20031007 Debian/1.6-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.5) Gecko/20031007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.5a) Gecko/20030723" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.5) Gecko/20031016" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.5) Gecko/20031222" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.5.1) Gecko/20031120" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5.1) Gecko/20031207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.6b) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-AT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040113 Relativity" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040206 MSIE/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6; lwpc5440) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; et-EE; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; hu; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; ja-JP; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pl-PL; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-AT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.6b) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; nl-NL; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; cs-CZ; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.6b) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6a) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6a) Gecko/20031105" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6b) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 MSIE/5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Poweranemone/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Powergoat/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Powerpig/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.6+) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; nb-NO; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; PL; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.6) Gecko/20040407" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-CN; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-TW; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ar; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.6b) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6a) Gecko/20020430" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6a) Gecko/20031030" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6b) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113 |sncwebguy|" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040119 MyIE2" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 GoogleBot/1.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 KPTX3/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Mozilla/5.0 StumbleUpon/1.904" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 msie/6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 MSIE/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Spacedonkey/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Telnet/4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6; RattBrowser) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fi-FI; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.6) Gecko/20040113,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nb-NO; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; PL; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-AT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; fr-FR; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; pt-BR; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; DragonFly i386; en-US; rv:1.6) Gecko/20040518" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6a) Gecko/20031207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6a) Gecko/20040525" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040120" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040308" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040313" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040319" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040324" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040412" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040414" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040512" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; ru-RU; rv:1.6) Gecko/20040406" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.6) Gecko/20040122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040413" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040413 Debian/1.6-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040527" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040530 Debian/1.6-6.backports.org.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.6) Gecko/20040216 Debian/1.6.x.1-10" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-IE; rv:1.6) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-IE; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6a) Gecko/20031029" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6a) Gecko/20031103" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6b) Gecko/20031113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6b) Gecko/20031208" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6b) Gecko/20031210" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Fucking cocksmoker" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040112" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040119" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040122 Debian/1.6-0.backports.org.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040122 Debian/1.6-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040122 Debian Sarge" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040123" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040124" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040127" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040130" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040203" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040204" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 dufus/42" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-us; rv:1.6) Gecko/20040207 firefox/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 InterBank 4.32" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040211" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040215 MSIE/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040216 Debian/1.6.x.1-10" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040218" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040223" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040224" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040229" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040303" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040306" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040307" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040308" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040310" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040312 Debian/1.6-3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040314" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040318" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040321" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040324" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040325" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040326" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040329" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040330" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040401 Debian/1.6-4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040402 Debian/1.6-3.backports.org.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040403" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040411" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040413 Debian/1.6-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040422" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040423" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040425" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040426 Debian/1.4-4 StumbleUpon/1.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040429" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040430" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040505" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040506" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040506 Powerstarfish/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040507" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040518" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040528 Debian/1.6-7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040530 Debian/1.6-6.backports.org.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6 kni-rat-sam 20041007) Gecko/20040510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6; Using IIS? Visit www.glowingplate.com/iis ) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040123 Debian/1.6-1.he-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040413 Debian/1.6-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040528 Debian/1.6-7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-CA; rv:1.6) Gecko/20040207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6b) Gecko/20031210" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6) Gecko/20040122 Debian/1.6-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6) Gecko/20040126" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6) Gecko/20040207 AnyBrowser /1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6) Gecko/20040413 Debian/1.6-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.6) Gecko/20040429" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.6) Gecko/20040510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; nl-NL; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.6) Gecko/20040124" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; PL; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; PL; rv:1.6) Gecko/20040122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.6) Gecko/20040528 Debian/1.6-7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.6) Gecko/20040331" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.6) Gecko/20040413 Debian/1.6-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.6) Gecko/20040115" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.6) Gecko/20040122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.6) Gecko/20040510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux powerpc; en-US; rv:1.6) Gecko/20040207 FireFox/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.6) Gecko/20040414 Debian/1.6-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; eo-EO; rv:1.6) Gecko/20040414 Debian/1.6-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.6) Gecko/20040113" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.6) Gecko/20040114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.6) Gecko/20040510" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.6) Gecko/20040405" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.6) Gecko/20040408" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040314" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040324" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040820" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040902" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.6) Gecko/20040117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6a) Gecko/20031125" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6) Gecko/20040116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6) Gecko/20040211 Lightningyak/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; es-ES; rv:1.6) Gecko/20040116" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (BMan; U; BManOS; bg-BG; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (en-AU; rv:1.7)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; de-AT; rv:1.7a) Gecko/20040225" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7a) Gecko/20040219" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7b) Gecko/20040421 netscape7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7a) Gecko/20040219" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040320" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040321" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040323" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040401" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040404" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Firefrog/0.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040626 FireFox/0.9.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040626 MSIE/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040730 Googlebot/2.1/2.1" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.7b+) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; hu-HU; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; nl-NL; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; da-DK; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7a) Gecko/20040123" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7a) Gecko/20040219" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040328" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040403" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040408" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040410" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040412" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040520 K-Meleon/0.8" + family: "K-Meleon" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Moonsnake/0.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Powersnake/0.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Powerwhale/0.8" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Pussyfag/0.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Spacebunny/0.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040616 WebWasher 3.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Moonlizard/0.9.1 (:w00t: to the world and the world :w00t:s back!)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)/0.9.1" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firepig/0.9.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Lightningspider/0.9.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Telnet/4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Ungawa/0.9.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Waterphoenix/0.9.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Webpony/0.8 ( polymorph)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Superlizard/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Superraccoon/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 XboxStore.com" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7a) Gecko/20031129" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-AT; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; Slackware; Linux i686; en-US; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; AIX 0006FADF4C00; en-US; rv:1.7b) Gecko/20040318" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7b) Gecko/20040422" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7b) Gecko/20040429" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040612" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; ja-JP; rv:1.7) Gecko/20040705" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; de-AT; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7) Gecko/20040619" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7) Gecko/20040724" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7) Gecko/20040803 Nevermind/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-CA; rv:1.7) Gecko/20040704" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-EU; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-EU; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-EU; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-UK; rv:1.7a) Gecko/20040105" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7a) Gecko/20040218" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040312" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040316" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040322" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040405" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040408" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040421" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040514" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040608" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040612" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040615 Lightningoyster/0.9 (Mozilla/4.0 (compatible; MSIE 6.0; WinNT; ATHMWWW1.1;))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040617" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040619" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040620" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040622" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040624 Debian/1.7-2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626 Microsoft/IE" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626 Mozilla/4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040702" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040703" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040704 Debian/1.7-4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040724" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040725" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040728" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040729" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040803 Lightningslimemold/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040805 Googlebot/2.1" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040808 Powertiger/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040809" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040828 Seagoat/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7rc1) Gecko/20040527" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fi-FI; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7) Gecko/20040617" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; PL; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7) Gecko/20040616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7) Gecko/20040627" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Mac OS; en-US; rv:1.7) Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OSF1 alpha; en-US; rv:1.7) Gecko/20040708" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7b) Gecko/20040319" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7c) Gecko/" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040517" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040610" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040618" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040623" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040920" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.2 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) )" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.1) Gecko/20040707 Mnenhy/0.6.0.104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fi-FI; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.1) Gecko/20040707 WebWasher 3.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.1) Gecko/20040707" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD 5.2.1 i686; en-US; rv:1.7.1+) Gecko/20020518" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.1) Gecko/20040724" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.1) Gecko/20040726" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040715" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040715 Debian/1.7.1-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040726 Debian/1.7.1-4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040730" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.1) Gecko/20040802 Debian/1.7.1-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; Athlon64; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; PL; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.2) Gecko/20040815" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.2) Gecko/20040816" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2;) Gecko/20020604 OLYMPIAKOS SFP" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040726" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040808" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040808 Debian/1.7.2-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040809" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040809 Debian/1.7.2-0woody1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040810 Debian" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040810 Debian/1.7.2-2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040815" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040816" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040819" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040819 Debian/1.7.2-3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040820 Debian/1.4-3 StumbleUpon/1.79" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040820 Debian/1.7.2-4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040825" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040906" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.2) Gecko/20040818" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; nl-NL; rv:1.7.2) Gecko/20040804" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.2) Gecko/20040829" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.2) Gecko/20040906" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.7.2) Gecko/20040823" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; de-AT; rv:1.7.2) Gecko/20040906" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.2) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.2) Gecko/20040813" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.2) Gecko/20040809" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.2) Gecko/20040810" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.2) Gecko/20040826" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; cs-CZ; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.3) Gecko/20040910,gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 IE/0.10" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040910 WebWasher 3.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.3) Gecko/20040910" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 WaterDog/0.10.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041111" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041207" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20040922" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.3) Gecko/20040914" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.3) Gecko/20040919" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.3) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040914" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040916" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040918" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040919" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040922" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040922 Debian/1.7.3-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040925" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040926" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041006" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041006 Debian/1.7.3-4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Debian" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041013" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041020" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041026" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041027" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041101" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041108" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.3) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.3) Gecko/20040913" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5 StumbleUpon/1.999" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; it-IT; rv:1.7.3) Gecko/20041007 Debian/1.7.3-5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.3) Gecko/20040921" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.3) Gecko/20041022" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Slackware GNU/Linux i686; pl-PL; rv:1.7.3) Gecko/20040913 --==MOZILLA RULLEZ ;)==--" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.3) Gecko/20040919" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.4) Gecko/20040926" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; ja-JP; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U; rv:1.7.5) Gecko/20041107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041107 Refrozen.com/2.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; it-IT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 MSIE/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.7.5) Gecko/20041210 MSIE/5.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; da-DK; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 google/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 IE/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 MSIE/1.0 (ax)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 TheBlacksheepbrowser/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217 Mnenhy/0.6.0.104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; de-AT; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; ; Win98; en; rv:1.7.5) Gecko/20041107" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041220" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.5) Gecko/20041213" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041128 Windows" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041221" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041228 Fedora/1.7.5-2.home" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.7.5) Gecko/20041108 MSIE/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7rc1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a4) Gecko/20040927" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a5) Gecko/20041122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040511" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.8a4) Gecko/20040930 Mnenhy/0.6.0.104" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8a) Gecko/20040425 `The Suite'" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040521" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040714" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a3) Gecko/20040817" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a5) Gecko/20041122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040420" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.8a2+) Gecko/20040524" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.8a2) Gecko/20040714" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8a2) Gecko/20040714" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.8a4) Gecko/20040927" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040607" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040704" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040713" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040714" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040812" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040817" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a4) Gecko/20040923" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a5) Gecko/20041122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041201" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041217" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040417" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040419" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040420" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040423" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040427" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040502" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040511" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8a2) Gecko/20040715" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; IRIX64 IP30; en-US; rv:1.8)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a1) Gecko/20040520" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040627" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040714" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040808" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a4) Gecko/20040927" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a5) Gecko/20041117" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a5) Gecko/20041122" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a5) Gecko/20041123" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040424" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040502" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8a3) Gecko/20040822" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.8a4) Gecko/20040929" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X; MSIE Incompatible; SyNiX; es-AR; rv:1.8a2/s) Gecko/20040814" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/2.02" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 (compatible; MSIE 6.0; X11; U; Linux i686; en-US; rv:2.5 P)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/3.0 (Compatible;Viking/1.8)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01Gold (Macintosh; I; 68K)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01Gold (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-GB; rv:1.0.2) Gecko/20020924 AOL/7.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.2) Gecko/20020924 AOL/7.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.0.1) Gecko/20030306 Camino/0.7" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.5b) Gecko/20030917 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.6a) Gecko/20031021 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.6b) Gecko/20031205 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7a) Gecko/20040105 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7a) Gecko/20040110 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040403 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040404 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040405 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040416 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040425 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040428 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040511 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040518 Camino/0.7+" + family: "Camino" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040623 Camino/0.8" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a2) Gecko/20040602 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a2) Gecko/20040607 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a2) Gecko/20040610 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a3) Gecko/20040804 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a3) Gecko/20040811 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20041130 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20041222 Camino/0.8+" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.2) Gecko/20040825 Camino/0.8.1" + family: "Camino" + major: '0' + minor: '8' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.2) Gecko/20040827 Camino/0.8.1" + family: "Camino" + major: '0' + minor: '8' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041201 Camino/0.8.2" + family: "Camino" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040517 Camino/0.8b" + family: "Camino" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.0.1) Gecko/20021220 Chimera/0.6+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030630 Epiphany/1.0" + family: "Epiphany" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030821 Epiphany/1.0" + family: "Epiphany" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030630 Epiphany/1.0.1" + family: "Epiphany" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.1) Gecko/20031114 Epiphany/1.0.4" + family: "Epiphany" + major: '1' + minor: '0' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031208 Epiphany/1.0.6" + family: "Epiphany" + major: '1' + minor: '0' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Epiphany/1.0.6" + family: "Epiphany" + major: '1' + minor: '0' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031229 Epiphany/1.0.6" + family: "Epiphany" + major: '1' + minor: '0' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040223 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.6) Gecko/20040115 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.6) Gecko/20040114 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.6) Gecko/20040115 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040114 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040115 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040118 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040317 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040324 Epiphany/1.0.7" + family: "Epiphany" + major: '1' + minor: '0' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040124 Epiphany/1.0.8" + family: "Epiphany" + major: '1' + minor: '0' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040312 Epiphany/1.1.12" + family: "Epiphany" + major: '1' + minor: '1' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040415 Epiphany/1.1.12" + family: "Epiphany" + major: '1' + minor: '1' + patch: '12' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040415 Epiphany/1.2.2" + family: "Epiphany" + major: '1' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040206 Epiphany/1.2.2" + family: "Epiphany" + major: '1' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040322 Epiphany/1.2.2" + family: "Epiphany" + major: '1' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040429 Epiphany/1.2.3" + family: "Epiphany" + major: '1' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040404 Epiphany/1.2.3" + family: "Epiphany" + major: '1' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510 Epiphany/1.2.4" + family: "Epiphany" + major: '1' + minor: '2' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040312 Epiphany/1.2.5" + family: "Epiphany" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040528 Epiphany/1.2.5" + family: "Epiphany" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040906 Epiphany/1.2.5" + family: "Epiphany" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040413 Epiphany/1.2.5" + family: "Epiphany" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.6) Gecko/20040414 Epiphany/1.2.5" + family: "Epiphany" + major: '1' + minor: '2' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040628 Epiphany/1.2.6" + family: "Epiphany" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040413 Epiphany/1.2.6" + family: "Epiphany" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040624 Epiphany/1.2.6" + family: "Epiphany" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040625 Epiphany/1.2.6" + family: "Epiphany" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040803 Epiphany/1.2.6" + family: "Epiphany" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040404 Epiphany/1.2.6.90" + family: "Epiphany" + major: '1' + minor: '2' + patch: '6' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040803 Epiphany/1.2.7" + family: "Epiphany" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040810 Epiphany/1.2.7" + family: "Epiphany" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040818 Epiphany/1.2.7" + family: "Epiphany" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040819 Epiphany/1.2.7" + family: "Epiphany" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040922 Epiphany/1.2.7" + family: "Epiphany" + major: '1' + minor: '2' + patch: '7' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.2) Gecko/20040821 Epiphany/1.2.8" + family: "Epiphany" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.2) Gecko/20041016 Epiphany/1.2.8" + family: "Epiphany" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040804 Epiphany/1.2.8" + family: "Epiphany" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040807 Epiphany/1.2.8" + family: "Epiphany" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040820 Epiphany/1.2.8" + family: "Epiphany" + major: '1' + minor: '2' + patch: '8' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510 Epiphany/1.3.0" + family: "Epiphany" + major: '1' + minor: '3' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041112 Epiphany/1.4.4" + family: "Epiphany" + major: '1' + minor: '4' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041020 Epiphany/1.4.4" + family: "Epiphany" + major: '1' + minor: '4' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041113 Epiphany/1.4.4" + family: "Epiphany" + major: '1' + minor: '4' + patch: '4' + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.3) Gecko/20041126 Epiphany/1.4.5" + family: "Epiphany" + major: '1' + minor: '4' + patch: '5' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041116 Epiphany/1.4.6" + family: "Epiphany" + major: '1' + minor: '4' + patch: '6' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030504 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030610 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4b) Gecko/20030623 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; IRIX64 IP30; en-US; rv:1.4b) Gecko/20030618 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5b) Gecko/20030722 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Solaris Sparc; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4b) Gecko/20030517 Mozilla Firebird/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Idefix hic erat!; Fenestra 50a.Chr.n.; la; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5a) Gecko/20030801 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5a) Gecko/20030801 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5a) Gecko/20030811 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5a) Gecko/20030905 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5a) Gecko/20030912 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5a) Gecko/20030918 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5b) Gecko/20030821 Mozilla Firebird/0.6.1+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5b) Gecko/20030910 Firebird/0.6.1+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.5a) Gecko/20030908 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.5a) Gecko/20030729 Mozilla Firebird/0.6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.5) Gecko/20031026 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; cs-CZ; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6a) Gecko/20031002 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6a) Gecko/20031105 Firebird/0.7+ (aebrahim)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6b) Gecko/20031208 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6b) Gecko/20031216 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040114 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040429 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; PL; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; fr; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031023 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20031208 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.5) Gecko/20040415 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031015 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031110 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031120 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031215 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031225 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20040114 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20040120 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20040130 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20040201 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6a) Gecko/20030924 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6a) Gecko/20031012 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040116 Firebird/0.7+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.5) Gecko/20031007 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.5) Gecko/20031020 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.5) Gecko/20031202 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.5) Gecko/20040114 Firebird/0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7a) Gecko/20040113 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7a) Gecko/20040210 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7a) Gecko/20040120 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7a) Gecko/20040129 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040410 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20040409 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7a) Gecko/20040118 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7a) Gecko/20040210 Firebird/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Firefox)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win64 (AMD64); en-US; Firefox" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040815 Lightningraccoon/0.9.1+ (All your Firefox 0.9.1+ are belong to Firesomething!)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040413 Waterdog/0.8.0+ (Firefox/#version# polymorph)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox_123/0.9.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.6) Gecko/20040210 Firesalamandre/0.8 (User Agent modifie grace a Firesomething. Telechargez Firefox en francais sur http://frenchmozilla.org/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux; en-US) Gecko/20040101 Firefox" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Firefox (Gecko)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla Dark Firefox" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla (Windows;+U;+Windows; en-GB) Gecko Firefox" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; rv:1.7.3) Gecko/20040913 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; rv:1.7.3) Gecko/20040913 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.3) Gecko/20040925 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040908 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 Firefox/0.10.1 WebWasher 3.3" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 Firefox/0.10 StumbleUpon/1.999" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040928 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10 StumbleUpon/1.996" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040911 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.10 Mnenhy/0.6.0.104" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.10 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040928 Firefox/0.10 (MOOX M2)" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; rv:1.7.3) Gecko/20040913 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; rv:1.7.3) Gecko/20040913 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; rv:1.7.3) Gecko/20040914 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041011 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1 StumbleUpon/1.999" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040911 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040913 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040914 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040919 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040923 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040924 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040928 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040929 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 Mnenhy/0.6.0.104" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041003 Firefox/0.10" + family: "Firefox" + major: '0' + minor: '10' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; rv:1.7.3) Gecko/20040911 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (MacOS; U; Panther; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041103 Mozilla Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041109 Firefox/0.10.1 (MOOX M3)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.7) Gecko/20040803 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040913 Firefox/0.10.1 (Firefox/0.10.1 rebrand: Mozilla Firesomething)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20040930 Firefox/0.10.1 (MOOX M3)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.7.3) Gecko/20041006 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 (MOOX M3)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/0.10.1 (MOOX M2)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a5) Gecko/20041031 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040910 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040911 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 (ax)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 StumbleUpon/1.999" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Thunderchicken/0.10.1 (All your Firefox/0.10.1 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7.3) Gecko/20041027 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; Slackware; Linux i686; Slackware; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; IRIX64 6.5; rv:1.7.3) Gecko/20041020 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040911 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040913 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040914 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040916 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040921 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040928 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041001 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041001 Firefox/0.10.1 (Linux/GTK)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041001 Firefox/Slackware-0.10.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041003 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041005 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041007 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041008 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041011 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041012 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041013 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041014 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041015 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041019 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041020 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041021 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041023 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041025 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041026 Firefox/0.10.1 (Debian package 0.10.1+1.0PR-4)" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041028 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041031 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041103 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041106 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041110 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041119 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041123 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20041202 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; rv:1.7.3) Gecko/20041022 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; rv:1.7.3) Gecko/20041020 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; rv:1.7.3) Gecko/20050220 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; rv:1.7.3) Gecko/20040916 Firefox/0.10.1" + family: "Firefox" + major: '0' + minor: '10' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Linux) Firefox/0.3" + family: "Firefox" + major: '0' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20041122 Firefox/0.5.6+" + family: "Firefox" + major: '0' + minor: '5' + patch: '6' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20041122 Firefox/0.5.6+" + family: "Firefox" + major: '0' + minor: '5' + patch: '6' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.6 StumbleUpon/1.73" + family: "Firefox" + major: '0' + minor: '6' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040407 Firefox/0.6 StumbleUpon/1.66" + family: "Firefox" + major: '0' + minor: '6' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.6.1 StumbleUpon/1.89" + family: "Firefox" + major: '0' + minor: '6' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 Firefox/0.6.1 StumbleUpon/1.87" + family: "Firefox" + major: '0' + minor: '6' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 Firefox/0.6 StumbleUpon/1.902" + family: "Firefox" + major: '0' + minor: '6' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041116 Firefox/0.6.1 StumbleUpon/1.87" + family: "Firefox" + major: '0' + minor: '6' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050110 Firefox/0.6.1 StumbleUpon/1.8 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '0' + minor: '6' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.5) Gecko/20050101 Firefox/0.6.4" + family: "Firefox" + major: '0' + minor: '6' + patch: '4' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.7 StumbleUpon/1.901" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.7 StumbleUpon/1.902" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.7 StumbleUpon/1.904" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040310 Firefox/0.7 StumbleUpon/1.895" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.7 StumbleUpon/1.9" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040313 Firefox/0.7" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626 Firefox/0.7 StumbleUpon/1.9" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040809 Firefox/0.7 StumbleUpon/1.89" + family: "Firefox" + major: '0' + minor: '7' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 Firefox/0.8 Mozilla/5.0 (compatible; Konqueror/3.2; Linux) (KHTML, like Gecko)" + family: "Konqueror" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.7b) Gecko/20040410 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.7b) Gecko/20040412 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Linux) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Firefox/0.8; Win32) Gecko/20040206" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Linux; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.903" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040308 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040311 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040314 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7b) Gecko/20040325 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040509 Firefox/0.8.0+ (MMx2000)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040519 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040531 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040608 Firefox/0.8.0+ StumbleUpon/1.99" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a2) Gecko/20040616 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040417 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040501 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040503 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040510 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040513 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a) Gecko/20040517 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; fr; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; rv:1.8a2) Gecko/20040522 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Njindonjs HR; en-US; rv:1.6) Gecko/20040206 Firefox/0.8)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.908" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7b) Gecko/20040304 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7b) Gecko/20040318 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040608 Moonbadger/0.8.0+ (All your Firefox/0.8.0+ are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040803 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8a2) Gecko/20040525 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8a) Gecko/20040504 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; it-IT; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; ja-JP; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pt-BR; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; ru-RU; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; fr; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.6) Gecko/20040206 Firefox/0.8 (Firefox/0.8)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040803 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 (All your Firefox/0.8 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 (ax)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.904" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.905" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.908" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.909" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Moonbird/0.8 (Firefox/0.8 polymorph)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Superwolf/0.8 (All your Firefox/0.8 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040210 Firefox/0.8 (www.proxomitron.de)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.8 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7a) Gecko/20040218 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040226 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040304 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040320 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040404 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040414 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040417 Firefox/0.8.0+ (MozJF)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040524 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040605 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040608 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040608 Firefox 0.8+/0.8.0+" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040613 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.8 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.8 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a1) Gecko/20040520 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040521 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040523 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040525 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040604 Firefox/0.8.0+ (stipe) (Proxomitron Naoko 4.51)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040608 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040421 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040422 Firefox/0.8.0+ (TierMann VC++Tools)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040427 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040504 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040507 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040510 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040511 Firefox/0.8.0+ (ax)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040512 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a) Gecko/20040518 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7b) Gecko/20040412 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7b) Gecko/20040302 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.6) Gecko/20040206 Firefox/0.8 (Proud Firefox user - IE suckz)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7) Gecko/20040803 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-CA; rv:1.8a) Gecko/20040508 Firefox/0.8 Royal Oak (Mozilla)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-NZ; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firecow/0.8 (Firefox/0.8 Get over it!)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 (ax)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 - <>" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 (John Bokma, http://johnbokma.com/)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 MSIE 5" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.903" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.906" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.907 (All your Firefox/0.8 StumbleUpon/1.907 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.908" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.909" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Lightningdog/0.8 (All your Firefox/0.8 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Waterworm/0.8 (All your Firefox/0.8 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040210 Firefox/0.8 (Lohvarn)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040210 Firefox/0.8 (stipe)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.8 StumbleUpon/1.908" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7a) Gecko/20040221 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040302 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040310 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040313 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040315 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040318 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040321 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040321 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040321 Firefox/0.8.0+ (mmoy)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040322 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040323 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040324 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040326 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040327 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040329 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040330 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040331 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040331 Firefox/0.8.0+ (scragz)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040403 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040404 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040406 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040406 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040407 Firefox/0.8.0+ (djeter)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040408 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040408 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040409 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040410 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040411 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040412 Firefox/0.8.0+ (mmoy-O2-GL7-SSE2-crc32-quek01235)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040512 Firefox/0.8.0+ (MOOX)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040520 Firefox/0.8.0+ (MOOX-AV)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040521 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040521 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040523 Firefox/0.8.0+ (MOOX-AV)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040529 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040530 Firefox/0.8.0+ (Lohvarn)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040601 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040601 Firefox/0.8.0+ (MOOX-TK)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040607 Firefox/0.8.0+ (MOOX-AV)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040608 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040610 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Firefox/0.8 StumbleUpon/1.909" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Waternarwhal/0.8 (Firefox/0.8)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Firefox/0.8 StumbleUpon/1.909" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040629 Firefox/0.8 (MOOX-AV)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.8 Gumby" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.8 StumbleUpon/1.909" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.8 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.8 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a1) Gecko/20040520 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040521 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040522 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040522 Firefox/0.8.0+ (MOOX-TK)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040523 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040524 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040524 Firefox/0.8.0+ (BlueFyre)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040525 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040526 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040527 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040601 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040602 Firefox/0.8.0+ (bangbang023)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040605 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040710 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040807 Firefox/0.8 StumbleUpon/1.99" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040415 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040417 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040425 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040426 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040428 Firefox/0.8.0+ (dbright)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040430 Firefox/0.8.0+ (mmoy-O2-GL7-SSE2-crc32)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040502 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040502 Firefox/0.8.0+ (scragz)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040503 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040503 Firefox/0.8.0+ (mmoy-Pentium4a)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040504 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040505 Firefox/0.8.0+ (MOOX)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040507 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040512 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040516 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040517 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040518 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040518 Firefox/0.8.0+ (mmoy-2004-05-05-Pentium4b)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.6) Gecko/20040206 Firefox 0.8/0.8 (MSIE 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.6) Gecko/20040206 Firefox/0.8 StumbleUpon/1.906" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fi-FI; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.6) Gecko/20040209 Firefox/0.8 (Oxs G7 SSE optimized)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Firefox/0.8 StumbleUpon/1.99" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; tr-TR; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; de-DE; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040803 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040803 Firefox/0.8 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8a2) Gecko/20040601 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; cs-CZ; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040606 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; en-US; rv:1.6) Gecko/20040227 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040213 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040218 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040303 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040317 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040405 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040422 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040425 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040429 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040503 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040504 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040610 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040627 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040805 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040812 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; ja-JP; rv:1.6) Gecko/20040429 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.6) Gecko/20040212 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.6) Gecko/20040227 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.6) Gecko/20040428 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.6) Gecko/20040612 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.8a) Gecko/20040418 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.6) Gecko/20040429 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.6) Gecko/20040506 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-UK; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 Firefox/0.8 StumbleUpon/1.904" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 Firefox/0.8 StumbleUpon/1.99" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040207 Firefox/0.8 TGB579860FilterStats" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040208 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040209 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040211 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040212 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040216 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040220 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040221 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040222 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040223 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040224 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040226 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040227 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040228 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040229 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040301 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040301 Firefox/0.8 StumbleUpon/1.909" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040302 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040308 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040310 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040316 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040317 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040317 Firefox/0.8 - www.ubuntulinux.org" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040322 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040323 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040324 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040327 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040330 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040402 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040403 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040404 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040405 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040405 Firefox/0.8.0+ StumbleUpon/1.895" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040407 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040412 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040413 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040415 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040416 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040417 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040418 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040420 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040421 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040422 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040423 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040424 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040425 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040426 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040427 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040428 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040429 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040501 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040502 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040503 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040504 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040506 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040508 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040509 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040513 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040514 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040515 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040517 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040518 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040519 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040522 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040523 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040527 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040530 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040531 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040602 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040611 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040612 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040621 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040630 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040701 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040707 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040713 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040715 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040726 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.8 StumbleUpon/1.904" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.8 StumbleUpon/1.906" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041128 Firefox/0.8 (Debian package 1.0-4)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050110 Firefox/0.8 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7a) Gecko/20040218 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/02004032 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040313 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040326 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040328 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040403 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040411 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040608 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040630 Firefox/0.8 StumbleUpon/1.904" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040708 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040529 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040602 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040605 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040617 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040630 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040428 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040429 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040430 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040502 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040503 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040505 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040516 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040518 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040225 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040327 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040506 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040602 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.6) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040219 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040327 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040421 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040506 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040602 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.6) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; MS-is-evil; en-US; rv:1.6) Gecko/20040405 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.6) Gecko/20040219 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sl-SI; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sl-SI; rv:1.6) Gecko/20040212 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.6) Gecko/20040602 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.6) Gecko/20040207 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.6) Gecko/20040327 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.6) Gecko/20040603 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.6) Gecko/20040615 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.6) Gecko/20040527 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.6) Gecko/20040408 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.6) Gecko/20040609 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040324 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040825 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20040902 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20041228 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20050204 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.6) Gecko/20050228 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD macppc; en-US; rv:1.6) Gecko/20040822 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6) Gecko/20040210 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6) Gecko/20040211 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6) Gecko/20040214 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.6) Gecko/20040403 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040629 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/6.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040614 Firefox/0.8" + family: "Firefox" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040222 Firefox/0.8.0+ (mmoy)" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a2) Gecko/20040604 Firefox/0.8.0+" + family: "Firefox" + major: '0' + minor: '8' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040628 Firefox/0.9.1 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040614 Firefox/0.9 StumbleUpon/1.999" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040815 Firefox/0.9.3 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pl-PL; rv:1.7) Gecko/20040614 Firefox/0.9 Mnenhy/0.6.0.104" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.5) Gecko/20041107 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.9 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040614 Lightningdog/0.9 (Firefox/0.9 polymorph)" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040617 Firefox/0.9.0+" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a2) Gecko/20040711 Firefox/0.9.0+" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9.3 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9.3 StumbleUpon/1.998" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Firefox/0.9 Mnenhy/0.6.0.104" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040608 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040608 Firefox/0.9.0" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Firefox/0.9 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Firefox/0.9 WebWasher 3.3" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 INTERNET COMMANDER/0.9 (All your Firefox/0.9 are DEREK SMART'S BECAUSE HE HAS A PHD AND YOU DON'T)" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040623 Firefox/0.9.0+" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040625 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040703 Firefox/0.9.0+" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.0" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 StumbleUpon/1.999" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040808 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.9.3 StumbleUpon/1.995" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Firefox/0.9 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040629 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040615 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040615 Firefox/0.9 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040615 Seaant/0.9 (All your Firefox/0.9 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040616 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040617 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040619 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040620 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040624 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1 Mnenhy/0.6.0.104" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040701 Firefox/0.9.0+ (daihard: P4/SSE2)" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040704 Firefox/0.9.0+" + family: "Firefox" + major: '0' + minor: '9' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 StumbleUpon/1.999" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7) Gecko/20040616 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040615 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040616 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "UserAgent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040614 Firefox/0.9" + family: "Firefox" + major: '0' + minor: '9' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.3) Gecko/20040831 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040628 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a3) Gecko/20040810 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a5) Gecko/20041121 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.7) Gecko/20040629 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.2) Gecko/20040819 Firefox/0.9.1+ (ax)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040713 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.8a6) Gecko/20041127 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040811 Firefox/0.9.1+ (pigfoot)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9.1 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040804 Firefox/0.9.1+ (bangbang023)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040808 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a3) Gecko/20040815 Firefox/0.9.1+ (MOOX-TK)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a5) Gecko/20041110 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-AR; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040810 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040811 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040812 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040814 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040814 Firefox/0.9.1+ (MOOX M3)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20040629 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9.1 StumbleUpon/1.993" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9.1 StumbleUpon/1.994" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040626 Spacepanda/0.9.1 (Firefox/0.9.1 serious edition)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040729 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040802 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040802 Firefox/0.9.1+ (moox)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040805 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040726 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040811 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040820 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040827 Firefox/0.9.1+ (MOOX M3)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040901 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a3) Gecko/20040904 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a5) Gecko/20041114 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040629 Firefox/0.9.1 (MOOX-AV)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; it-IT; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win NT 5.0; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040706 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040725 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040729 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040804 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040806 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7) Gecko/20040629 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; pt-BR; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040819 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040825 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040629 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040630 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040701 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040702 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040704 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040705 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040706 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040708 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040710 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040711 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040714 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040715 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040719 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040721 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040729 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040730 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040730 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040801 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040802 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.1+ (lokean SVG-enabled)" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040804 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040730 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040805 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040824 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040902 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a5) Gecko/20041027 Firefox/0.9.1+" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7) Gecko/20040712 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7) Gecko/20040719 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20040629 Firefox/0.9.1" + family: "Firefox" + major: '0' + minor: '9' + patch: '1' + - user_agent_string: "Firefox 0.9.2 (The intelligent alternative)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.7) Gecko/20040711 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pt-BR; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2 (ax)" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pt-BR; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2 (ax)" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040707 Waterbug/0.9.2 (All your Firefox/0.9.2 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040709 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040708 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040712 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040716 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040801 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040802 Firefox/0.9.2" + family: "Firefox" + major: '0' + minor: '9' + patch: '2' + - user_agent_string: "Firefox 0.9.3 (compatible;MSIE 6.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Firefox/0.9.3 (compatible;MSIE 6.1; Windows 98)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Firefox 0.9.3 (compatible MSIE is gay;Linux)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Firefox/0.9.3 [en] (All your base are belong to us)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (i686; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; it-IT; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3 (#)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 WebWasher 3.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040803 Firejackalope/0.9.3 (All your Firefox/0.9.3 are belong to Firesomething)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040805 Firefox/0.9.3 (djeter)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; tr-TR; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; fr; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD amd64; en-US; rv:1.7) Gecko/20041015 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040806 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040807 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040811 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040813 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040830 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040910 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20040927 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7) Gecko/20041016 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7) Gecko/20040808 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ca-CA; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7) Gecko/20040809 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3 Mnenhy/0.6.0.104" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040804 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040805 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040806 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040807 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040808 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040809 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040810 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040813 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040814 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040818 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040819 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040823 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040824 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040825 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040827 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040830 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040831 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040901 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040904 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040914 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040917 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040920 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040926 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040928 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu) StumbleUpon/1.999" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.7) Gecko/20040803 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; uk-UA; rv:1.7) Gecko/20040809 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; de-DE; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7) Gecko/20040813 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; fr; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7) Gecko/20040902 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7) Gecko/20040817 Firefox/0.9.3" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; WinNT; es-AR; rv:1.7) Gecko/20041013 Firefox/0.9.3 (Ubuntu)" + family: "Firefox" + major: '0' + minor: '9' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20050302 Firefox/0.9.6" + family: "Firefox" + major: '0' + minor: '9' + patch: '6' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040626 Firefox/0.9.6" + family: "Firefox" + major: '0' + minor: '9' + patch: '6' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050302 Firefox/0.9.6" + family: "Firefox" + major: '0' + minor: '9' + patch: '6' + - user_agent_string: "Best website about travels.(New Zealand, Thailand, Bolivia)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "appName/appVersion (Windows; U; Windows NT 5.0; zh-CN; rv:1.7.5) Gecko/20041107 Firefox/1.0 (vendorComment)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "(Firefox/1.0; Mac OS X Panther)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Firefox/1.0 Mozilla/5.0 Netscape/7.1elezeta (Debian GNU/Linux)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.17; Mac_PowerPC) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.001 (Windows NT 5.0) [en] Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Amiga OS; U; Amiga OS 5.3; en-US; rv:5.3) Gecko/20040707 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (ca-AD; Celtric) Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; ; Apple ][) Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (en-US; rv:1.7.5) Gecko/20050110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Gameboy Color; U; Gameboy OS 2005; de-DE) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Linux; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Linux i686; nb-NO; rv:1.7.5) Gecko/20041108 Firefox/1.0 Frodo" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Linux; U; Windows NT 5.1; es-ES; rv:1.7.3) Gecko/20041027 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.3) Gecko/20041026 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.3) Gecko/20041026 Firefox/1.0RC1 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2 (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.0 (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041130 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20050208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20050208 Firefox/1.0 StumbleUpon/1.9991" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7) Gecko/20040628 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20041207 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20041211 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20041222 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20041225 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8a6) Gecko/20050109 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b2) Gecko/20050220 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b2) Gecko/20050224 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b2) Gecko/20050225 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050128 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050128 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050202 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050205 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050209 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050212 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050216 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050217 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050218 Firefox/1.0+ (PowerBook)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; fi-FI; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; ja-JPM; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; ja-JPM; rv:1.7.5) Gecko/20041108 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; nl-NL; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; zh-TW; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (; U;;; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; de-DE;SKC) Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 Windows Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; de-AT; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; ja-JP; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; cs-CZ; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; da-DK; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; el-GR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:1.7.5) Gecko/20041113 Firefox/1.0 (MOOX M1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.3) Gecko/20041026 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (*mh*)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 SR" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8a6) Gecko/20050108 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8a6) Gecko/20050110 Firefox/1.0+ (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8b2) Gecko/20050302 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8b) Gecko/20050115 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.8b) Gecko/20050218 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; es-ES; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; hu-HU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; hu-HU; rv:1.7.5) Gecko/20041110 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; it-IT; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; ja-JP; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; nl-NL; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pl-PL; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; pt-BR; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; sv-SE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; tr-TR; rv:1.7.5) Gecko/20041208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; zh-CN; rv:1.7.5) Gecko/20041124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; zh-TW; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; nl-NL; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; sv-SE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows 98; nl-NL; rv:1.7.5) Gecko/20041112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ca-AD; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; cs-CZ; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; da-DK; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; da-DK; rv:1.7.5) Gecko/20041118 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.3) Gecko/20041027 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.5) Gecko/~20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0 WebWasher 3.3" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.3) Gecko/20041026 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.3) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 -awstats-exclude" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 Mnenhy/0.6.0.104" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 PR" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.998" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.9991" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041108 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041108 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041115 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041123 Firefox/1.0 (Community Edition FireFox P4W-X2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20050114 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5; Google-TR-1) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040812 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6) Gecko/20041209 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6) Gecko/20050101 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6) Gecko/20050107 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8a6; Google-TR-1) Gecko/20050101 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b2) Gecko/20050301 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050117 Firefox/1.0+ (BlueFyre)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050118 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050122 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050131 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050201 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050202 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050204 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050206 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050206 Firefox/1.0+ (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050209 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050210 Firefox/1.0+ (BlueFyre)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8b) Gecko/20050215 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.7.5) Gecko/20041210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fi-FI; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fi-FI; rv:1.7.5) Gecko/20041108 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; hu-HU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7.3) Gecko/20041027 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ko-KR; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; nl-NL; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; nl-NL; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ru-RU; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; sl-SI; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; sv-SE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-CN; rv:1.7.3) Gecko/20041101 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-CN; rv:1.7.5) Gecko/20041124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-CN; rv:1.7.5) Gecko/20041124 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-TW; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; bg-BG; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ca-AD; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; da-DK; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-bn; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.3) Gecko/20041027 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0 Mnenhy/0.6.0.104" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0 WebWasher/1.2.2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0 (CK-UKL)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0 StumbleUpon/1.999,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.5) Gecko/20041124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; el-GR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-AU; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-CA; rv:1.8b2) Gecko/20050226 Firefox/1.0+ (nightly)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-CA; rv:1.8b) Gecko/20050216 Firefox/1.0+ (trunk)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-EN; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-gb; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0 StumbleUpon/1.9992" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041113 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041128 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.5) Gecko/20041129 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-NZ; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-UK; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040903 Firefox/1.0 PR (NOT FINAL) (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20041026 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041106 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 Ad/www.yetanotherblog.de" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (All your Firefox/1.0 are belong to us)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (Arjan says HI!)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (Goobergunchian Edition)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 Mnenhy/0.6.0.104" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 Mnenhy/0.7.1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (Not Netscape 7.1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 sexyfox/0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.9991" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.9992" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 WebWasher 3.3" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 www.city.poznan.pl/1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Superjellyfish/1.0 (All your Firefox/1.0 are belong to Firesomething)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041108 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041108 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M3) Mnenhy/0.6.0.104" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 StumbleUpon/1.999 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 StumbleUpon/1.999 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041112 Firefox/1.0 (stipe)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041114 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041115 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050129 Firefox/1.0 (pigfoot)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050206 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050207 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050209 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050211 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20050214 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5; Google-TR-1) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5; Google-TR-1) Gecko/20041107 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5;ME) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0 StumbleUpon/1.9992" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20040103 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041204 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041206 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041209 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041211 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041214 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041215 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041218 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041220 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041221 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041229 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20041230 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050101 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050104 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050108 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050109 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050111 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a6) Gecko/20050131 Firefox/1.0+ (Firefox CE Trunk 2004-12-23 P4W-X15)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050222 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050301 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b2) Gecko/20050305 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050113 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050115 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050116 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050117 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050118 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050123 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050124 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050125 Firefox/1.0+ WebWasher 3.3" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050126 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050128 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050131 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050201 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050204 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050205 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050206 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050207 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050210 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050211 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050213 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050215 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050216 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050217 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b) Gecko/20050218 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0; ortzzuwt" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.5) Gecko/20041107 xFirefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.5) Gecko/20041108 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.5) Gecko/20041208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.5) Gecko/20041210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.5) Gecko/20041210 Firefox/1.0 Internet Watcher 2000/ V1.4" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fi-FI; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fi-FI; rv:1.7.5) Gecko/20041108 Firefox/1.0 StumbleUpon/1.9991" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.3) Gecko/20041027 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.5; Google-TR-1) Gecko/20041109 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; hu-HU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.3) Gecko/20041027 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.5) Gecko/20041108 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.5) Gecko/20041108 Firefox/1.0 StumbleUpon/1.996" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.5) Gecko/20041110 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-VE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.5) Gecko/20041108 Firefox/1.0,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.7.5) Gecko/20041111 Firefox/1.0 (JTw)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.8a6) Gecko/20050107 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ko-KR; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nb-NO; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.5) Gecko/20041116 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.7.5) Gecko/20041110 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.8a6) Gecko/20050109 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.8b2) Gecko/20050220 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.8b) Gecko/20050206 Firefox/1.0+ (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-PT; rv:1.8b) Gecko/20050218 Firefox/1.0+ (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ro-RO; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.3) Gecko/20041027 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sk-SK; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sl-SI; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sl-SI; rv:1.7.5) Gecko/20041113 Firefox/1.0 (largie's)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7.5) Gecko/20040321 Firefox/1.0 DEBUG" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; tr-TR; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; tr-TR; rv:1.7.5) Gecko/20041208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.7.5) Gecko/20041124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.7.5) Gecko/20041124 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20041108 Firefox/1.0 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.5) Gecko/20050208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8a6) Gecko/20050110 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8b2) Gecko/20050228 Firefox/1.0+ (MOOX M1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8b) Gecko/20050114 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; es-es; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; es-ES; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; it-IT; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; ru-RU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-TW; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 6.0; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; es-ES; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; ; Windows NT 5.1; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Slackware - current; Linux i686; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Slackware; Linux i586; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Darwin Power Macintosh; en-US; rv:1.7.5) Gecko/20041208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD amd64; en-US; rv:1.7.3) Gecko/20041104 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD amd64; en-US; rv:1.7.5) Gecko/20050104 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-UK; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.3) Gecko/20041029 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041113 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041114 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041115 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041120 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041123 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041125 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041127 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041130 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041203 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041207 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041209 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041215 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041218 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041222 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041224 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041227 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041228 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041229 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050102 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050104 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050105 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050106 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050115 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050117 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050120 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050123 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050125 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050127 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050204 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050205 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050207 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050212 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050215 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050225 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20050226 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; ja-JP; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i686; es; rv:1.7.5) Gecko/20041128 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux) Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0 (Debian package 1.0-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20050103 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; chrome://navigator/locale/navigator.properties; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20041119 Firefox/1.0 (Debian package 1.0-3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.5) Gecko/20050206 Firefox/1.0 (Debian package 1.0+dfsg.1-5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-CH; rv:1.7.5) Gecko/20040107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041111 Firefox/1.0 (Debian package 1.0-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041128 Firefox/1.0 (Debian package 1.0-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041207 Firefox/1.0 (Debian package 1.0-5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20041211 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20050202 Firefox/1.0 (Debian package 1.0+dfsg.1-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.7.5) Gecko/20041209 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu4-warty99)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8) Gecko/20050101 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040907 Firefox/1.0 PR (NOT FINAL)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041026 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041029 Firefox/1.0RC1 (Debian package 0.99+1.0RC1-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041030 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041030 Firefox/1.0RC1 (Debian package 0.99+1.0RC1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041102 Firefox/1.0RC1 (Debian package 0.99+1.0RC1-3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041105 Firefox/1.0RC1 (Debian package 0.99+1.0RC1-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041112 Firefox/1.0RC1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041009 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041106 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0 (Debian package 1.0-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0 SPELLSHIDO!" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041113 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041114 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041115 Firefox/1.0 StumbleUpon/1.998" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041116 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041116 Firefox/1.0 (Ubuntu) StumbleUpon/1.999 (Ubuntu package 1.0-2ubuntu3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041116 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041117 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041117 Firefox/1.0 (Debian package 1.0-2.0.0.45.linspire0.4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041119 Firefox/1.0 (Debian package 1.0-3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041120 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041120 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041121 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041123 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041125 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041126 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041127 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041128 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041128 Firefox/1.0 (Debian package 0.99+1.0RC1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041128 Firefox/1.0 (Debian package 1.0-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041129 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041129 Firefox/1.0 (Debian package 1.0-3.backports.org.1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041130 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041201 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041203 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041204 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041204 Firefox/1.0 (Debian package 1.0.x.2-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041205 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041206 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041207 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041207 Firefox/1.0 (Debian package 1.0-5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041207 Firefox/1.0 StumbleUpon/1.999 (Debian package 1.0-5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041208 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041209 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041209 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu4-warty99)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041211 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041212 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041213 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041214 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041214 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041215 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041215 Firefox/1.0 Red Hat/1.0-12.EL4" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041216 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041218 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041219 Firebunny/1.0 (Firefox/1.0)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041219 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041219 Firefox/1.0 (Debian package 1.0+dfsg.1-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041219 Firefox/1.0 (Debian package 1.0+dfsg.1-1) Mnenhy/0.7.1" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041220 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041222 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041223 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041223 Firefox/1.0 Yoper/FIREFOX_RPM_AM" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041224 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041225 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041226 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041227 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041228 Firefox/1.0 Fedora/1.0-7" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041228 Firefox/1.0 Fedora/1.0-8" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041230 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041231 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050103 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050104 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050105 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050106 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050109 Firefox/1.0 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050113 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050115 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050116 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050120 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050120 Firefox/1.0 (Debian package 1.0+dfsg.1-3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050121 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050121 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-2ubuntu2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050123 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050123 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-2ubuntu3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050125 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050126 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050127 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050128 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050128 Firefox/1.0 (Debian package 1.0.x.2-13)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050128 Firefox/1.0 (Ubuntu)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050128 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-2ubuntu5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050129 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050130 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050131 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050201 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050202 Firefox/1.0 (Debian package 1.0+dfsg.1-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050203 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050203 Firefox/1.0 (Debian)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050203 Firefox/1.0 (Debian package 1.0.x.2-15)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050205 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050206 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050206 Firefox/1.0 (Debian package 1.0+dfsg.1-5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050207 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050209 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050210 Firefox/1.0 StumbleUpon/1.999 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050215 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050218 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050221 Firefox/1.0 (Ubuntu)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050221 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-6ubuntu1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050222 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050223 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050225 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20050228 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20041013 Firefox/1.0.0" + family: "Firefox" + major: '1' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a6) Gecko/20041204 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050117 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050201 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050207 Firefox/1.0+ (daihard: P4/SSE2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050212 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8b) Gecko/20050218 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20041128 Firefox/1.0 (Debian package 1.0-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20041210 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.7.5) Gecko/20050128 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-2ubuntu5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; es-MX; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fi-FI; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.5) Gecko/20041108 Firefox/1.0 Mnenhy/0.7" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20041115 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20041116 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0-2ubuntu3)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20041119 Firefox/1.0 (Debian package 1.0-3 Moostik.net)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20041128 Firefox/1.0 (Debian package 1.0-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20050110 Firefox/1.0 StumbleUpon/1.998 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20050202 Firefox/1.0 (Debian package 1.0+dfsg.1-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20050206 Firefox/1.0 (Debian package 1.0+dfsg.1-5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; he-IL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; hr-HR; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.7.3) Gecko/20041101 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7.5) Gecko/20041128 Firefox/1.0 (Debian package 1.0-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; nl-NL; rv:1.7.5) Gecko/20041202 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; nl-NL; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; nl-NL; rv:1.7.5) Gecko/20050221 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-6ubuntu1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.5) Gecko/20041108 Slackware Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.5) Gecko/20050110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ru-RU; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.7.5) Gecko/20050110 Firefox/1.0 StumbleUpon/1.999 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.7.5) Gecko/20050128 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-2ubuntu5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; sv-SE; rv:1.7.5) Gecko/20050210 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; tr-TR; rv:1.7.5) Gecko/20041208 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; us; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; zh-TW; rv:1.7.5) Gecko/20041119 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i786; en-US; rv:1.8b2) Gecko/20050225 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i786; en-US; rv:1.8b) Gecko/20050212 Firefox/1.0+" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20041116 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20041125 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20041209 Firefox/1.0 (Debian package 1.0-5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20041220 Firefox/1.0 (Debian package 1.0+dfsg.1-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20050110 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20050123 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.5) Gecko/20050128 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-2ubuntu5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux ppc; es-US; rv:1.7.5) Gecko/20041220 Firefox/1.0 (1.0)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux; sl-SI; rv:1.7.5) Gecko/20041112 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; da-DK; rv:1.7.5) Gecko/20041118 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; de-DE; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041112 Firefox/1.0 (Debian package 1.0-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041116 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041117 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041130 Firefox/1.0 (Debian package 1.0-4)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041204 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041214 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041218 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20041226 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050104 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050106 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050111 Firefox/1.0 (Debian package 1.0+dfsg.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050114 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050124 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050128 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-2ubuntu5)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050211 Firefox/1.0 (Debian package 1.0+dfsg.1-6)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.5) Gecko/20050221 Firefox/1.0 (Ubuntu) (Ubuntu package 1.0+dfsg.1-6ubuntu1)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; MSIE 6.0; Linux i686; en-US; rv:1.7.5; IDF-BCC;) Gecko/20041111 Firefox/1.0 (Debian package 1.0-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.5) Gecko/20041114 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.5) Gecko/20050103 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.5) Gecko/20050126 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.7.5) Gecko/20050128 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD amd64; en-US; rv:1.7.5) Gecko/20050122 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.7.5) Gecko/20041128 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.7.5) Gecko/20050101 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Slackware; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Slackware; Linux i686; pl-PL; rv:1.7.5) Gecko/20041108 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7.5) Gecko/20041213 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.7.5) Gecko/20050101 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.5) Gecko/20041109 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.5) Gecko/20041110 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.5) Gecko/20041130 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.5) Gecko/20041207 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7.5) Gecko/20050213 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "WhoreNuts/2.0 (Windows; U; Win98; en-US; rv:1.7.5) ScabCount/123883 Firefox/1.0" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Gecko/20041108 Firefox/1.0; Mac_PowerPC)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Gecko/20050225 Firefox/1.0.1 Antares; U; Antares 5.5" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Gecko/20050228 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 StumbleUpon/1.9991" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.6) Gecko/20050227 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; hu-HU; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1,gzip(gfe) (via translate.google.com)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; nl-NL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-GB; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050222 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050224 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 robert" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 StumbleUpon/1.9991" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 StumbleUpon/1.9992" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1 (MOOX M1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-CN; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ca-AD; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; el-GR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 StumbleUpon/1.9992" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050224 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050224 Firefox/1.0.1 (pigfoot)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1 (MOOX M2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1 (MOOX M3)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6; Google-TR-1) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.6) Gecko/20050303 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; hu-HU; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; it-IT; rv:1.7.6) Gecko/20050226 Firefox/1.0.1 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl-NL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.6) Gecko/20050301 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.6) Gecko/20050303 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; cs-CZ; rv:1.7.6) Gecko/20050301 Firefox/1.0.1 Fedora/1.0.1-1.3.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050224 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050224 Firefox/1.0.1 Fedora/1.0.1-1.3.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 Red Hat/1.0.1-1.4.3" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050226 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050227 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050228 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050301 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050301 Firefox/1.0.1 (Debian package 1.0.1-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050302 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050302 Firefox/1.0.1 Fedora/1.0.1-1.3.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050303 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050305 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050306 Firefox/1.0.1 (Debian package 1.0.1-2)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.7.6) Gecko/20050301 Firefox/1.0.1 (Debian package 1.0.1-1)" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; it-IT; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.7.6) Gecko/20050224 Firefox/1.0.1 Fedora/1.0.1-1.3.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.6) Gecko/20050223 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.6) Gecko/20050302 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.6) Gecko/20050308 Firefox/1.0.1" + family: "Firefox" + major: '1' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.7.6) Gecko/20050225 Firefox/1.0.2" + family: "Firefox" + major: '1' + minor: '0' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.3) Gecko/20041101 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2 StumbleUpon/1.999" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20041030 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20041031 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20041101 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041102 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2 (ax)" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pl-PL; rv:1.7.5) Gecko/20041104 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041103 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041105 Firefox/1.0RC2" + family: "Firefox" + major: '1' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Linux Slackware; U;Linux Slackware 10.1; en-US; rv:1.8.0) Gecko/20050616 Firefox/1.1" + family: "Firefox" + major: '1' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0) Gecko/20050304 Firefox/1.1" + family: "Firefox" + major: '1' + minor: '1' + patch: + - user_agent_string: "Mozilla Firefox/5.0" + family: "Firefox" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040206 Firefox/7.1" + family: "Firefox" + major: '7' + minor: '1' + patch: + - user_agent_string: "Firefox 7.1.3(compatible MSIE is gay;Linugz)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Linux Slackware x86_64 BlackBox; de_AT; Intel@Xeon) Firefox/Gecko" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.2b) Gecko/20021016 K-Meleon 0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2b) Gecko/20021016 K-Meleon 0.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8" + family: "K-Meleon" + major: '0' + minor: '8' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.1" + family: "K-Meleon" + major: '0' + minor: '8' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031016 K-Meleon/0.8.2" + family: "K-Meleon" + major: '0' + minor: '8' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040608 MultiZilla/ StumbleUpon/1.995" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040613 MultiZilla/1.5.0.4h" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.2) Gecko/20040803 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.7) Gecko/20040617 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.8a3) Gecko/20040819 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.3.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.2) Gecko/20040803 MultiZilla/1.6.3.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.2) Gecko/20040804 MultiZilla/1.6.4.0b (ax)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.6) Gecko/20040113 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-AT; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3.1; MultiZilla v1.4.0.3J) Gecko/20031007 MultiZilla/1.6.0.0d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6a) Gecko/20031030 MultiZilla/1.6.0.0a" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040803 MultiZilla/1.6.0.0e" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040316 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040316 MultiZilla/1.6.3.1c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040318 MultiZilla/1.6.1.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040514 MultiZilla/1.6.4.0a" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040616 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.6) Gecko/20040113 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7.2) Gecko/20040803 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-AT; rv:1.7) Gecko/20040616 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031007 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.0.0e" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.3.0d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.3.1c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.3.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.1) Gecko/20040707 MultiZilla/1.6.3.2c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.1) Gecko/20040707 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040803 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 MultiZilla/1.6.2.0c (ax)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 MultiZilla/1.6.4.0b (ax)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.3) Gecko/20040910 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041217 MultiZilla/1.6.0.0e" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040421 MultiZilla/1.6.3.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040514 MultiZilla/1.6.3.2f" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040514 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040608 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040616 MultiZilla/1.6.2.1a" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040616 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a1) Gecko/20040520 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a2) Gecko/20040714 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a4) Gecko/20040927 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8a) Gecko/20040429 MultiZilla/1.6.3.2c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.4) Gecko/20030624 MultiZilla/1.6.1.0b (ax)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Debian GNU/Linux - only dead fish go with the flow - i686; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040301 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040113 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040115 MultiZilla/1.6.2.1a" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040115 MultiZilla/1.6.3.0e" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040413 MultiZilla/1.6.3.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040510 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040528 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040804 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040913 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041014 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040316 MultiZilla/1.6.3.0e" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040421 MultiZilla/1.6.2.0c" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7b) Gecko/20040425 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040608 MultiZilla/1.6.2.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040618 MultiZilla/1.6.2.1d" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a3) Gecko/20040805 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8a) Gecko/20040501 MultiZilla/1.6.4.0b" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 MultiZilla/v1.1.20" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2b) Gecko/20021007 Phoenix/0.3" + family: "Phoenix" + major: '0' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.3a) Gecko/20021207 Phoenix/0.5" + family: "Phoenix" + major: '0' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.3a) Gecko/20021207 Phoenix/0.5" + family: "Phoenix" + major: '0' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3a) Gecko/20021207 Phoenix/0.5" + family: "Phoenix" + major: '0' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MS FrontPage 6.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MSFrontPage/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.0; Windows 3.1)" + family: "IE" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.0; Windows 3.1; Sculptor; Rules)" + family: "IE" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.0; Windows 95)" + family: "IE" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.0; Windows 95) via HTTP/1.0 coder.internet-elite.com/" + family: "IE" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/3.0 (compatible; MSIE 3.0; Windows NT 5.0)" + family: "IE" + major: '3' + minor: '0' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.01; Windows 3.1)" + family: "IE" + major: '3' + minor: '01' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.01; Windows 95)" + family: "IE" + major: '3' + minor: '01' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.02; Windows 95)" + family: "IE" + major: '3' + minor: '02' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.02; WindowsCE" + family: "IE" + major: '3' + minor: '02' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.02; Windows CE; PIEPlus 1.2; 240x320; PPC)" + family: "IE" + major: '3' + minor: '02' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.02; Windows CE; PPC; 240x320)" + family: "IE" + major: '3' + minor: '02' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; MSIE 3.02; Windows CE; Smartphone; 176x220)" + family: "IE" + major: '3' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; MSN 2.5; Windows 95)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows 95)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows 95; FunWebProducts-MyWay)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows 95; .NET CLR 1.1.4322)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows NT)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows NT 4.0)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows NT 5.0)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows NT 5.1)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; Windows XP)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; AOL 4.0; Mac_PPC)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; AOL 4.0; Windows 95; Toshiba Corporation)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; AOL 5.0; Mac_PPC)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Mac_PowerPC)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; MSN 2.5; AOL 3.0; Windows 98; Compaq; wGoVols)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; MSN 2.5; MSN 2.5; AOL 4.0; Windows 98)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; MSN 2.5; Windows 98)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 2000)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 95)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 95; FREESERVE_IE4)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 95; iOpus-I-M)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 95; QXW0300f)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 95; TriStar Enterprises)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98;CP=MS)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98; DigExt)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98; DT)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98; Messages.co.uk)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; 240x320)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; MSN Companion 2.0; 800x600; Compaq)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; PPC; 240x320)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; Smartphone; 176x220)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows NT)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 5.0)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.01; Windows; U; 32bit)" + family: "IE" + major: '4' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.5; Mac_PowerPC)" + family: "IE" + major: '4' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.5; Windows 98; )" + family: "IE" + major: '4' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.5; Windows NT 5.0)" + family: "IE" + major: '4' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5; Windows NT 5.1; Windows XP SP2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.00; Windows 98" + family: "IE" + major: '5' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 4.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 5.0; Windows 95; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 5.0; Windows 95; DigExt; DT)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 5.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 5.0; Windows 98; DigExt; DT)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 6.0; Windows 98; Compaq; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 6.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 7.0;TargetAOL7.0; Windows 95; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 7.0;TargetAOL7.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 7.0; Windows 95; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 7.0; Windows 98)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 7.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 7.0; Windows 98; DigExt; FunWebProducts)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 7.0; Windows 98; Hotbar 4.3.2.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; AOL 8.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0b1; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC; AtHome021)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC; e412357VZ_IE50M)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC; p412360OptusCabl)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC; s412454BPH6mac)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC; s412514Mac/m/4.5)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC; S425166QXM03307)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC) (via translate.google.com)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC; X111923v13b.08)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; MSN 2.0; AOL 7.0; Windows 95; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; MSN 2.5; AOL 5.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; MSN 2.5; AOL 5.0; Windows 98; DT; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; MSN 2.5; MSN 2.5; Windows 98)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; MSN 2.5; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; MSN 2.5; Windows 98; DigExt; CindyKlett 1)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; MSNIA; AOL 7.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; AT&T WNS5.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; BTinternet V8.4; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; 1.21.2 )" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; AtHome0107)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; btclick.com Build BTCFSOHOQ2)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; DT)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; freenet 4.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; Hotbar 2.0; AT&T CSM6.0; FunWebProducts)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; JUNO)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; LILLY-EMA-EN)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; QXW0330q)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; QXW03314)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; sureseeker.com)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; tco2)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DigExt; YComp 5.0.2.4)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DT)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; DT; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; OZEMR1999V01)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95) VoilaBot BETA 1.2 (http://www.voila.com/)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95; ZDNetSL)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; {10708F41-46D9-11D9-9941-0008A127FF36})" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; {251744E0-8FEE-11D8-8ED7-00045A9E19B3})" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; {BD767A21-2BDF-11D9-B494-0050BAFA5FC2})" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; Compaq; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; Compaq; DigExt; FunWebProducts)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0(compatible; MSIE 5.0; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; A084)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; AIRF)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Arcor 2.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; AtHome033; FunWebProducts)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; AT&T CSM6.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Creative)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; */E-Plus-002)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; freenet200)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; freenet 4.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; FreeSurf myweb.nl v1.0.1)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; FunWebProducts)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; FunWebProducts; Creative)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; FunWebProducts; FunWebProducts-MyWay)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; FunWebProducts-MyWay)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Hotbar 2.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Hotbar 4.3.2.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Hotbar 4.3.5.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; iebar)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt);JTB:15:88fba442-193e-11d9-bb86-0050fc8126b1" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; KITL27; (R1 1.3))" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; LanguageForce)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Mannesmann Arcor)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Matrix Y2K - Preview Browser)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; MAX1.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; MCNON1.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; MindSpring Internet Services)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc21; v5m)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; MSN 6.1; MSNbMSFT; MSNmen-us; MSNczz; v5m)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; MSNIA)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; pbc4.0.0.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; pi 3.0.0.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; QXW0331m)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; QXW0331w)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; (R1 1.3))" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; SC/5.07/1.00/Compaq)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; searchengine2000.com; sureseeker.com)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; StudentenNet)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; sureseeker.com)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; TencentTraveler )" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; TiscaliFreeNet)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; tn3.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; V1.0Tomorrow1000)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt) via Avirt Gateway Server v4.2" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Virgilio3pc)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; VNIE5 RefIE5)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; vtown v1.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; www.ASPSimply.com)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; YComp 5.0.2.4)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; YComp 5.0.2.5)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; YComp 5.0.2.6)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; yplus 1.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; formatpb; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; FunWebProducts)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; FunWebProducts; Hotbar 4.4.5.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; NETACT; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; provided by VSNL)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; Q321120)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; QXW03301; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; QXW03301; DigExt; sunrise4)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; Software Trading Edition)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; WebHopper)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; YComp 5.0.0.0; Cox High Speed Internet Customer; sbcydsl 3.12" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows ME)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT;)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 4.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.1)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; Bob)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; Adam's Mark Hotels)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; AT&T WNS5.0; AT&T CSM6.0; AT&T WNS5.0 IE5.0.01)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; DT)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; DTS Agent" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; (R1 1.3))" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; TBIT)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; Yahoo-1.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DT; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; QXW0330d; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 [fi] (compatible; MSIE 5.0; Windows 98)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 [fr] (compatible; MSIE 5.0; Windows 98)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.0; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.0; Windows 98;)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.0; Windows NT/95/98))" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "MSIE 5.0" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "MSIE 5.0 (compatible; noyb; Windows5.1)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; AOL 4.0; Windows 98)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; AOL 4.0; Windows 98; QXW0332b)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; AOL 5.0; Windows 95; QXW0332b)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; AOL 7.0; Windows 98)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; AOL 7.0; Windows 98; YPC 3.0.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; AOL 8.0; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; CS 2000; Windows 95; AT&T WNS5.0; DigExt)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; MSN 2.5; Windows 98)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; MSNIA; Windows 95; MSNIA)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; BCD2000; FunWebProducts)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; DT)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; Microplex 1.0.1.5; OptusIE501-018)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; Microplex 2.0; OptusIE501-018)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; MSNIA)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; QXW0332b)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; QXW0332i)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; QXW03336)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; QXW0333a)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; SEARCHALOT.COM IE5; iOpus-I-M)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; USA On-Site)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 95; Xtra)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; 1012SurfnetVersion2.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; 1&1 Puretec)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; 981)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; AO1.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; AskBar 2.01; Hotbar 4.4.5.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; AT&T CSM6.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; BCD2000)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; BPH32_57a)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; BT Internet)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Config C)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; DT)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; F-5.0.1SP1-20000718; F-5.0.1-20000221)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; FDM)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Feat Ext 19)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; FREE)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; FunWebProducts)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; FunWebProducts; FunWebProducts-MyWay)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; GTE_IE5)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Hotbar 2.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Hotbar 3.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Hotbar 4.4.2.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Hotbar 4.4.7.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Hotbar 4.5.1.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Hotbar4.5.3.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; KSC)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Linux 2.4.2-mvista_01) [Netgem; 4.0.6; InterDigital-T]" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Linux 2.4.2-mvista_01) [Netgem; 4.4.2; i-Player; netbox; NetgemUK]" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Linux 2.4.2-mvista_01) [Netgem; 4.4.3b1; i-Player; netbox; NetgemUK]" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Linux 2.4.2-mvista_01) [Netgem; 4.5.2a; i-Player; netbox; btdigitaltv]" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Linux 2.4.2-mvista_01) [Netgem; 4.5.2a; i-Player; netbox; NetgemUK]" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Linux 2.4.2-mvista_01) [Netgem; 4.5.2b; i-Player; netbox; NetgemUK]" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; MRA 2.5 (build 00387))" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; MSNIA)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; MSOCD; AtHome020)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; OptusIE501-018)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; pi 3.0.0.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; QXC03304)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; QXW03335)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; QXW03336)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; (R1 1.3))" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; SEARCHALOT.COM IE5)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; SPINWAY.COM)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; SQSW)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; sureseeker.com)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; surfEU DE S1)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Teleos)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; TNET5.0NL)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; {World Online})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows 98; YComp 5.0.2.6)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 4.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {2BBC0D6A-BD8E-43C8-9CA1-81673682EF32})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {31BF9C41-DE4C-49B8-B050-19E27C86DC76})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {59C0EB25-1B95-4B4C-AF0B-C247D74597B0})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {87CA9FD1-DEE6-4CB5-98FE-62BA2CA583DE})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {944D8EEF-056A-4073-B8F3-C317B94BA3C0})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {A68BF0C3-9B5E-4F63-A05B-0ADCAF21F0C8})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {ABF22706-058D-48D2-B032-BC3A65229618})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Admiral Group Limited -)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; AHP)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Assistant 1.0.2.4)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; AtHome021SI)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Bitscape Solutions, India)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Boeing Kit)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {CDC8EB20-F4B7-4407-BD64-40AB1B97D85C})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Coles Myer Ltd.)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Creative)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; DigExt)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; DigExt; iebar; (R1 1.5))" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; DigExt; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; DigExt; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; digit_may2002)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; DT)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {E73D9CB8-6F87-458B-9943-F0284A59F969}; FDM)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; {EEC83506-405F-4B48-BA4F-047A5AA92F3E})" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; */E-Plus-002)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; F-5.0.1-20021031)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FDM)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FPC 014)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FunWebProducts)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FunWebProducts),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FunWebProducts-MyTotalSearch)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FunWebProducts-MyWay)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FunWebProducts; .NET CLR 2.0.40607)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; FW1)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; H010818)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)Host: www.pgts.com.au" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 3.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 3.0) via NetCache version 3.1.2c-Solaris" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 4.2.4.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 4.3.1.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 4.4.2.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 4.4.5.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 4.4.5.0; FunWebProducts)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar 4.4.6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Hotbar4.5.3.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; i-NavFourF)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; iOpus-I-M)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Launceston Church Grammar School)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Mohammad Ali Jinnah University)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; MRA 4.0 (build 00768))" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; MSOCD; AtHome020)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; .NET CLR 1.0.2914)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; .NET CLR 2.0.40607)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Netcom_BA_DD)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; OptusIE55-31)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; PCUser)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; PhaseOut-www.phaseout.net; PhaseOut-www.phaseout.net)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Q312461)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Q321120)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Q321120; Feat Ext 20)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; (R1 1.1))" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; (R1 1.3))" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; (R1 1.5))" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Sgrunt|V106|671|S-1000478620)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; Smart Explorer 6.1)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; surfEU DE M2)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; T312461)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; TencentTraveler )" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; TNT Australia Pty Ltd)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; T-Online Internatinal AG; MSIECrawler)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; WebTap)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; YComp 5.0.2.5)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; YComp 5.0.2.6; FunWebProducts)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.1)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; Aztec)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; BWB 09032000; BWB 07032000)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; DT)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; freenet 4.0)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; FunWebProducts)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; IE4SUPER; IE4COPLEY; proxyho; proxyinternet)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; IE501NTAb)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; OIZ - Switzerland)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; QXW0332s)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; QXW03336)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; [R1 1.3])" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; SBC)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; Sears Roebuck and Co. 2001)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; S.N.O.W Workstation)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; v1.0 C1; v2.0 C3; v4.0 C3; v2.0 C1)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; v1.0 C1; v4.0 C3)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; www.k2pdf.com)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; YComp 5.0.2.4)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "MSIE 5.01" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "MSIE 5.01 (Windows 98)" + family: "IE" + major: '5' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.05; Windows NT 4.0)" + family: "IE" + major: '5' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.05; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.12; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.13; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '13' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.14; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '14' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.15; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '15' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.16; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '16' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.17; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '17' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.17; Mac_PowerPC),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '17' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.2; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '2' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.2; Mac_PowerPC) - Internet Explorer 5.2, Mac" + family: "IE" + major: '5' + minor: '2' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.21; Mac_PowerPC" + family: "IE" + major: '5' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.21; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.22; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.23; Mac_PowerPC)" + family: "IE" + major: '5' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 95)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 95; Arcor 2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 95; EWE TEL)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 95; FDM)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 98; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 98; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 98; VV50110)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows 98; Win 9x 4.90; Q312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 6.0;TargetAOL6.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 6.0; Windows 95)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 6.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 6.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 95)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; {326AFFA0-90D0-11D8-9D83-444553540000})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; DT; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; Hotbar 4.2.1.1362)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; Q312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; QXW03371)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; Win 9x 4.90; AN10HaendlerWelcomeletter1200; AO1.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; Win 9x 4.90; Creative; (R1 1.3))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; Win 9x 4.90; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows 98; Win 9x 4.90; (R1 1.5))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 7.0; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 8.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 8.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 8.0; Windows 98; Win 9x 4.90; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 8.0; Windows 98; Win 9x 4.90; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 8.0; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 8.0; Windows NT 5.0; BTT V3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 9.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 9.0; Windows 98; Win 9x 4.90; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; AOL 9.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; CS 2000 6.0; Wal-Mart Connect 6.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; CS 2000 6.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; CS 2000 6.0; Windows 98; YComp 5.0.2.6)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; CS 2000; Windows 98; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; CS 2000; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSN 2.5; AOL 6.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSN 2.5; AOL 7.0; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSN 2.5; Windows 95; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSN 2.5; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSN 2.5; Windows 98; {476BCB60-A826-11D8-9866-444553540000})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSN 2.5; Windows 98; AT&T CSM6.0; YComp 5.0.2.5)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSN 2.5; Windows 98; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSNIA; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSNIA; Windows 98; AT&T CSM6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSNIA; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; MSNIA; Windows 98; Win 9x 4.90; MSNIA)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 3.11)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; AN10HaendlerWelcomeletter1200; AO1.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; A&R Internet; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; BCD2000)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; BPB32_v2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; CSO 3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; DigExt)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; indo.net IE40 users)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; iOpus-I-M)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; iPrimus)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; IT-Office)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; OptusIE501-018)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; OptusIE55-31)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; OptusIE55-31; BPH03)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; PC Games Hardware)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; QXW0333s)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; QXW0333x)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; QXW0334j)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; qxw03377)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; QXW03395)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; StumbleUpon.com 1.758)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; surfEU DE S3)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; SYMPA)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; T312461; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; T312461; UDWXQ08154711; Praise and Worship to the Lamb of God!)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; TBP_6.1_AC)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; TBP_7.0_GS)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; Tucows)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; wave internet services-LAN)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; WSIE)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; )" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98;)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)." + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible;MSIE 5.5; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible;MSIE 5.5; Windows 98);" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0(compatible; MSIE 5.5; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; 1 & 1 Internet AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; {25FDDD80-7A10-11D9-B0EA-00055D3406F7})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; 3301; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; {88CC0240-7784-11D9-B0EA-00055D3406F7})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; AIRF)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; AT&T CSM6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; AT&T WNS5.0; AT&T WNS5.2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; AT&T WNS5.2; AT&T CSM6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; AUTOSIGN W95 WNT VER01)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Avant Browser [avantbrowser.com])" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; AWWCD; OptusIE501-018)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; {B0727E40-7BFF-11D8-BF96-00028A14743D})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; {B85C43C0-6408-11D8-890A-005004AD1452})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; BPH32_59)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; brip1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; BTopenworld)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Chariot; Hotbar 4.3.2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; CNE-Internet 02252000)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; COM+ 1.0.2204)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Compaq)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Compaq; PeoplePC 2.3.0; ISP)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Config C; Config D)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Config D; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Creative)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; CSO 3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; CWMIE55WDU)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DAC)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DIL0001021)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; distributed by ish)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DT; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DT; Hotbar 3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DT; http://www.Abolimba.de)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DT; MSIECrawler)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; DT; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; */E-Plus-002)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; ESB{1B6DEFA6-3A18-4B9B-9022-99348A8910CF})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; {FE627F21-305D-11D9-A75F-00055D2D4DD4})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; freenet 4.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; FunWebProducts-MyWay)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; FunWebProducts-MyWay; DVD Owner)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; GlobtelNet)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; HanseNet ADSL v1.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Hotbar 4.3.1.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Hotbar 4.3.2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Hotbar 4.5.1.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; HTMLAB)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; HTMLAB; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Installed by Symantec Package)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Jet2Web Internet Service GmbH)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; KITV4.7 Wanadoo)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; KSK sp. z o.o.)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; L1 IE5.5 301100)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; MRA 3.0 (build 00614))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; MSN 6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; MSOCD; AtHomeNL191)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; NetCaptor 6.2.1A)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; .NET CLR 1.1.4322);JTB:15:82cffcc4-8761-4b59-9ba1-c2cba02980a7" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; N_o_k_i_a)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; OptusIE55-31)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; OptusIE55-31; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; OptusIE55-32)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; OTCDv1.4)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; PeoplePC 1.0; ISP)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Q312461; T312461; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0300Z)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0333s)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW03346)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW03347)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW03349)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0334h)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0334j)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW03354)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW03356)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0335n)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0335o)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0335v)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0336b)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW03373)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; qxw03376b)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0337i)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0337t)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0338o)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0338t)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0338t; MSIECrawler)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; QXW0530g)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; (R1 1.1))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; (R1 1.3))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; (R1 1.5))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Royal Perth Hospital)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; salzburg-online)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; SiteCoach 1.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; sureseeker.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; surfEU DE M2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; surfEU DE S1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; surfEU DE S3)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; T312461; Cox High Speed Internet Customer)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; T312461; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; T312461; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; T312461; V-5.5SP2-20011022)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; TBP_6.1_AC)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; TBP_7.0_GS)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; TBP_7.0_GS; DefensiveSurfing.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Teleos)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Teleos; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Terminal)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; tn3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; tn4.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Turk Nokta Net; AIRF)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; version55)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; VNIE55)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Wanadoo 6.0; Feedreader)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98) WebWasher 3.3" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Wegener Arcade)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; A084)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; AIRF; FunWebProducts; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; AN10HaendlerWelcomeletter1200)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; AN10HaendlerWelcomeletter1200; AO1.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Arcor 2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; AtHome021SI; (R1 1.5))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; AT&T CSM6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; AVPersonalSerial 728479f8326c352757535b791d2e62b027776bc6)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Circle0701)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; CNE-Internet 02252000)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Creative)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; {D7B0F19C-92C9-4506-96FC-7357186B5914})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; DT-AT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; DT; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; DVD Owner)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; EDISINETD02)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; FDM)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Feat Ext 19)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; freenet 4.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; FunWebProducts; FunWebProducts-MyWay)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; FunWebProducts; MSIECrawler)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; H010818; BTT V3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; H010818; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; H010818; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; HEP AS; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Hotbar 3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Hotbar 4.1.8.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Hotbar 4.3.2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Hotbar 4.4.2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; IDL Internet)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; iebar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; iOpus-I-M)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Kit Terra Premium; FunWebProducts),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; libero)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; MSIECrawler)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; MSN 6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; MSN 6.1; MSNbBBYZ; MSNmen-us; MSNc21; v5m)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; MSOCD)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; MyIE2; FunWebProducts; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; .NET CLR 1.0.3705; Hotbar 4.6.1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; .NET CLR 1.0.3705; Hotbar 4.6.1),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; ntlworld v2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; ONDOWN3.2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; OptusIE55-31)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; pbc4.0.0.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; PeoplePal 3.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Q312461; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; QXW0335v)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; (R1 1.3))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; (R1 1.5))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; sbcydsl 3.12; YComp 5.0.8.6; AT&T CSM6.0; AT&T CSM7.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; ScreenSurfer.de)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; SNET OLR v5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; SPINWAY.COM)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; StarBand Version 4.0.0.2; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; StumbleUpon.com 1.760; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Supplied by blueyonder)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; surfEU DE M2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; T312461; (R1 1.3))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; TBP_7.0_GS)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; tele.ring Version 4.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; TUCOWS)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; V1.0Tomorrow1000)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; V1.0Tomorrow1000; Q312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90) (via translate.google.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; Wanadoo 5.4; Wanadoo 5.5; Wanadoo 6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; www.vancouver-bc-canada-guide.com; NetCaptor 7.2.2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; YComp 5.0.2.5)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; YComp 5.0.2.6)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; ZDNetIndia)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; ZDNetIndia.com browser)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; ZDNetIndia; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; ZDNetSL)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Zon CD-rom versie 2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows CE)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; 1 & 1 Internet AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; 1&1 Internet AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; AIRF)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; by IndiaTimes)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; c_commcd1; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; CHIP Explorer :-)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; DekaBank; DGZ-DekaBank; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; DERA IE 4.01 Install 1.0.0.6-CD)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; DEV4012; SP4012)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; DigExt)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; DigExt; QXW03346)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; ENR 2.0 emb)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; F-5.0.0-19990720)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; FR 09/05/2000)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; FunWebProducts; Hotbar 4.4.5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; GDMS_98A_BRAZIL)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Gothaer Versicherung Mobil)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; H010818; DoJ-SOE-4.0.0.0-build-20000213)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; H010818; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; H010818; HEWLETT-PACKARD -- IE 5.5 SP1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Housenet Full 1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Humana1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; HVB 2/2001; T312461; HVB)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; ICN - 000407; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; IE55232Ab)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; i-NavFourF)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Installed by Symantec Package)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; IT-Office)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; L1 IE5.5 December 2000)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Logica 5.01.1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; LycosDE1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; MATAV_IE_55_HUN)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; MI Brandenburg; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; MSIE-5.5-DZBANK)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; .NET CLR 1.0.3705; Googlebot; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Googlebot)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; N_O_K_I_A)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; norisbank; iOpus-I-M)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; P20314IEAK1; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Provided by UAL)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; QXW03002)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; QXW0330d)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; QXW0333v)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; QXW03346)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; QXW0334h; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; QXW03356)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; QXW03371)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; (R1 1.3))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; (R1 1.5))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; RBPD2711)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Sema UK Telecoms upgrade)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; SQSW)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Suncorp Metway Ltd)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461; FunWebProducts-MyWay)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461; IK)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461; (R1 1.1))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; T312461; Unilever Research)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; TIN ie4a32bit rel.1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Tucows)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; USHO-111203)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; v4.0 C3; v5 C5)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; Version 2/5.5 Customised)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT5)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5;Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; 1 & 1 Internet AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {2F8067D2-867C-4351-A289-786E8307965E})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; 3304)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; 3305)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; 360networks)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {4D391717-5781-46B1-9B5E-82D8014C43B0}; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {54ACD89C-CE9B-4CD3-9617-E30DE3DA8738})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {5A4938A5-F50D-46DE-80AA-C659EC68625D}; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {5C8D4EB8-815B-42DD-BF83-63A5F7F7377D}; Hotbar 4.4.6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {63AE5C75-6D69-4DC2-B8E2-F8E204D31206})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; 828750)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {A4E04F4A-3C7A-484D-B1E0-DE64E78EB309})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0) Active Cache Request" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {AF9A0710-ED4B-4DEE-884C-E0BB887C2E44})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Agilent Technologies IE5.5 SP2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Agilent Technologies IE5.5 SP2; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Airservices Australia)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Alexa Toolbar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; AspTear 1.5)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; AT&T CSM6.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; AT&T CSM7.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; AWWCD)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; bkbrel07)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; BOCSIE55SP2; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; BTopenworld)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0) But of course, that's a fake. I'm really running Mozilla on a non-Microsoft OS, and I've only set these headers to get around the restrictions of people who are ignorant enough to exclude the browser that " + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {C89A4139-160D-4323-B132-B58019B2AF1A})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; CBC/SRC)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; CHEP Australia; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; CHMC)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Coles Myer Ltd.)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; compaq)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; compaq; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Config D)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Config D; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Connex 13/02/2001; Connect 25/07/2002)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Creative)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; CSC)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; CWMIE55WODU)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; CWMIE55WODU; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; DAF)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Dept. of Primary Industries)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; DEUBA)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; DGD (AutoProxy4))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; DPU; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; DT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; DT; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; [eburo v1.3])" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; [eburo v1.3]; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; [eburo v1.3]; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; {EE17FE27-30FE-41A1-992C-71356B0262D1})" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; ESB{FC3DA1FF-49D4-4235-B656-6358FBC0D57B}; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; FDM)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Fisher-Price)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; FREE; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; FunWebProducts; maxweb)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; GameBar)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; GEP IE 5.5 SP2 Standard; GEP IE 5.5 SP1 Standard)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Groupe DANONE)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; 828750)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; Navstd27juin2001en)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; Q316059)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; H010818; UB1800; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Hotbar 2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Hotbar 4.1.8.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Hotbar 4.2.8.0; H010818)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Hotbar 4.4.5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; HTMLAB)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; ICT)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Installed by Symantec Package)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Installed by Symantec Package; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; iOpus-I-M)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0);JTB:104:a95eef30-9f35-4ec0-bc43-66a16a703faf" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; KSK sp. z o.o.)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; LCPL)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; LILLY-US-EN)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; LLY-EMA-EN)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Logica 5.5 SP2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Merrill IE 5.5 SP2 Install Kit; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; mhs)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; MSOCD; AtHomeEN191)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Nambour State High School (Queensland Australia); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.2914)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; N_o_k_i_a)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; N_O_K_I_A)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Nokia 7650; 240*320)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; N_O_K_I_A; (R1 1.5))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; NSW.net)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; nwb)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; OptusIE55-31)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; OptusIE55-31; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Oregano2 )" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Patriot V5.5.1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; PRU_IE55SP1; PRU_IE55)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Q312461; iOpus-I-M)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Q312461; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; QXW0336o)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; qxw0337d)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; QXW0338d)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; (R1 1.1))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; (R1 1.3))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; (R1 1.5))" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; RA; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; RA; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; RC7.4 release)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; RC7.4 release; i-NavFourF)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; SCF - Mean & Nasty; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; SDS IE5.5 SP2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; S.N.O.W.2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; S.N.O.W.2; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; surfEU DE M1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; SWS)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; CAT-COE)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; DOJ3jx7bf)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; F-5.5SP2-20011022)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; F-5.5SP2-20011022; F-5.0.1-20000221)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; FunWebProducts)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; Guidant IE5 09302001 Win2000 Distribution; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; istb 702; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; ITS 2.0.2)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; MSIECrawler)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; .NET CLR 1.0.3705)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; PC SRP 2.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T312461; POIE4SP2; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; TBPH_601; Feat Ext 19)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; TheFreeDictionary.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Thiess Pty Ltd)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; T-Online Internatinal AG)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; U)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; Unknown)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0) (via translate.google.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; www.ASPSimply.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; www.bfsel.com)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; WYETH)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; YComp 5.0.0.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; YComp 5.0.8.6)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; ZDNetIE55)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.1)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.7 [en] (compatible; MSIE 5.5; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.8 [en] (compatible; MSIE 5.5; Windows NT 5.1; U)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (compatible;MSIE 5.5; Windows 3.11)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (compatible;MSIE 5.5; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.5; Windows NT 5.0)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.5; Windows XP);" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.1 (compatible;MSIE 5.5; Windows 98)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/7.2 (compatible; MSIE 5.5; Windows 98; DigExt)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "MSIE 5.5" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5.1; Windows NT 4.0; T312461; spw500; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "MSIE 6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 (compatible; MSIE 6.0; Windows 98; 240X320; PPC; Default)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.00; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 5.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 5.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 5.0; Windows 98; Win 9x 4.90; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 6.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 6.0; Windows 98; Creative)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 6.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 6.0; Windows 98; Win 9x 4.90; Q321120)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 6.0; Windows NT 5.1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows 98; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows 98; Win 9x 4.90; freenet 4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; FunWebProducts; SV1; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; Hotbar 4.3.2.0; BCD2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; Hotbar 4.4.7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; PCUser; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; Q321120; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; Q321120; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 7.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; {5F4036E0-6271-11D8-8929-000AE67C2897})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; AT&T CSM6.0; FunWebProducts; Hotbar 4.2.9.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; Compaq)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; GA55sp2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98);JTB:2:825c2721-bc07-11d8-bdea-444553540000" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; Win 9x 4.90; AT&T CSM6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; Win 9x 4.90; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; Win 9x 4.90; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows 98; Win 9x 4.90; OUBrowser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; {1EB73F69-5BFB-4D8C-9BA8-72A428DA75D3}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; {3B4748F2-EE14-4317-B069-7AB6F7AEFE69})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; BTOW V9.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; CDSource=storecd_01_03; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; CDSource=v9e.05)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; DigExt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; FunWebProducts; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; generic_01_01; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; Hotbar 4.4.6.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; SaveWealth)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; StumbleUpon.com 1.751)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; SV1; FunWebProducts; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; YComp 5.0.0.0; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; YComp 5.0.0.0; SYMPA; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; Win 9x 4.90; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; Win 9x 4.90; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; Win 9x 4.90; YPC 3.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows 98; YComp 5.0.0.0; AT&T CSM6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.0; Hotbar 4.3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.0; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {07D8E8DA-0530-4B69-A0A4-7EB7CB54C821}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {2E4B39C0-67F6-4E50-BD40-FAD19B5CAA8A})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; 3305)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {7197B170-E810-4522-9DC0-088AAD5AD6E9}; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {723EBBEB-CBB8-4A00-AD75-0A0B1A0517ED})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {8B658E16-E35C-4C43-A913-307AA2BADC55}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {9CCDF57C-A828-47C1-9431-3670BDEC44B6}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {9D60457B-6A0F-4CAF-8C22-B463BC201CBB})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; BCD2000; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; CDSource=storecd_01_03; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; CDv5.1.1_1099)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {D2F65954-6A14-43B5-86BE-42556275B763})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; dial)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; DigExt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; ESB{67E15522-64F5-4326-B157-10FF147CA5E9}; ESB{EF27D6C9-1D19-4ED9-B494-FA921D24CCB0}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; {FD960C72-0B96-40FA-BFF5-6B1CE3F64B60}; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; SV1; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; FunWebProducts; YPC 3.0.2; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; generic_01_01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Hotbar 4.2.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Hotbar 4.3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; iOpus-I-M; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Preload_01_07)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Q312461; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Q312461; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; (R1 1.5); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Roadrunner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Roadrunner; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; Creative; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; FunWebProducts; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; Grip Toolbar 2.07a; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; Hotbar4.5.3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; Media Center PC 3.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Media Center PC 3.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; SV1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; v8c.01; Hotbar 4.2.11.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; Wanadoo 5.5; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; YPC 3.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.0; Windows NT 5.1; YPC 3.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; AOL 9.9; Beta 0.9.4201.270; Browser Control 0.9.0.4; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98; {DB0219C0-5374-11D9-81F0-00010292A080})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98; GTelnet1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98) OmniWeb/v496" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98; Win 9x 4.90; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 4.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 4.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0; iOpus-I-M; SEARCHALOT.COM IE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows 98; Compaq)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows NT 5.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows NT 5.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; CS 2000 6.0; Wal-Mart Connect 6.0; Windows NT 5.1; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; AOL 8.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; AOL 8.0; Windows 98; {99AEF9F6-AD65-4E28-B512-F173232EBD29})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; AOL 9.0; Windows 98; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla /4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; AT&T WNS5.0; AT&T CSM6.0; AT&T CSM8.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; FunWebProducts; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; iPrimus; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; PCUser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; sureseeker.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; sureseeker.com; searchengine2000.com; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows 98; YPC 3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.5; Windows NT 5.1; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.6; Windows 98; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.6; Windows 98; T312461; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSN 2.6; Windows 98; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; Creative)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; Hotbar 4.3.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; MSOCD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; T312461; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSNIA; Windows 98; Win 9x 4.90; AT&T CSM6.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 3.1; Wanadoo 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 95)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 95; PalmSource; Blazer 3.0) 16;160x160" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/ 4.0 (compatible; MSIE 6.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98);" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible;MSIE 6.0;Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; 100)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; 1&1 Internet AG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; 1&1 Puretec)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; 1&1 Puretec; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {12Move})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; 1.57.1 )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {1A030500-6279-11D8-91F9-00055D306537}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {29C5C4C0-87CA-11D8-94C0-00E07DE10B20})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {3171E4C0-49BB-11D9-8CA9-D07E76ABD032})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; 3304; MSN 8.0; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; 3305)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {57F5F0C1-E226-11D8-A9B2-00C04F5BBF26})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {62FF51C0-7B8B-11D8-AD78-004F4905E079})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {6C917480-655F-11D8-8622-444553540000})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {728C4D40-8C75-11D9-86F6-D73001167134}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {7E8AF401-1A03-11D9-BF45-444553540000})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {7EC49A61-187E-11D9-824D-0008A15DF7A2}; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {8F9DB3A0-A757-11D8-A1FE-444553540000}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {9C20C200-1109-11D8-8F74-444553540000})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AAPT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AIRF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AIT; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; alice01; DP1000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; alice01; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; alice01; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Alitalia Custom)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; APC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; APCMAG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; APCMAG; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AskBar 3.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AskBar 3.00; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AskBar 3.00; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AtHome0107)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AtHome0107; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AtHome033)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AtHomeI0107)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AtHomeI0107; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AT&T CSM6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AT&T CSM6.0; AT&T CSM7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AT&T CSM6.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AT&T CSM6.0; Q312461; AT&T CSM7.0; AT&T CSM8.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AT&T CSM7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AT&T WNS5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AT&T WNS5.0; MSOCD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; austarnet_2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; AUTOSIGN W2000 WNT VER03)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Avant Browser [avantbrowser.com]; OptusNetDSL6)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {B3EB8D41-DE48-11D8-BBF4-00804815CB32})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BB1.0 IE5.5.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {BBA839A0-7F6C-11D9-8278-0080C8E10726})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BCD2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BCD2000; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {BDBAC461-139C-11D9-B962-00A0CCD11F28})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BIGPOND_ADSL_42)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BIGPOND_ADSL_42; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BPB32_v2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; bpc; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BPH03)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BPH32_55a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BPH32_59; OptusIE501-018)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BTO E1.07; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BTOW)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BTOW V9.0; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BTOW V9.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; BTOW V9.5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {CA066580-6E9C-11D8-97BC-0060088DA696}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; CDSource=cannonst)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; CDSource=v2.15e.04)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; CDSource=vBB1c.00; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Centrum.cz Turbo2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Compaq)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Computer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Cox High Speed Internet Customer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Cox High Speed Internet Customer; NetCaptor 7.5.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Cox High Speed Internet Customer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; cPanelGui 6.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Creative)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Creative; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; CSOLVE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DCSI)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Deepnet Explorer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DigExt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DigExt; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; digit_may2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DIL0001021; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DP1000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DVD Owner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; DVD Owner; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {E39750C0-6F5B-40B4-9D70-0681DB8795DA})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; eBook)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)::ELNSB50::0000411003200258031c016c000000000506000800000000" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)::ELNSB50::0000411003200258032001df000000000507000900000000" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)::ELNSB50::000041100400030003de0208000000000502000800000000" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)::ELNSB50::000081900320025803140197000000000502000800000000" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; ESB{13B30CE0-EC80-11D8-83BE-0001031746AB})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; ESB{BBA298E0-3889-11D8-9F02-0010B5525635})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; ESB{F0B8BB20-643F-11D0-9C90-00C0F0741766}; yie6_SBC; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; ezn73ie5-1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; EZN/PC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; EZN/PC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {F361FD20-F590-11D7-AFAF-0050FC225B60})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; F-5.0.0-19990720; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; {FD464440-B8BD-11D8-9957-00010273BF2C}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; formatpb)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FREE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; freenet DSL 1.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; freeonline)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; fs_ie5_04_2000i)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; fs_pb_ie5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; Feat Ext 21)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; FunWebProducts-MyTotalSearch)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; Hotbar 4.4.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts-MyWay; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; NN5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; FunWebProducts; SEARCHALOT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; GFR)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; APCMAG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; Hotbar 4.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; i-MailBook)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; MathPlayer 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; VZ_IE6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; H010818; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hellas On Line; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.1.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.1.8.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.3.1.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.3.2.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.3.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.4.5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.5.1.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.5.1.0; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; HTMLAB; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; ICONZ IE5CD; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; IDG.pl)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; IE5.x/Winxx/EZN/xx)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; IESYM6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iiNet CD1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; i-Nav 3.0.1.0F)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Installed by Symantec Package)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; InterNetia 0002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iOpus-I-M; ISP40; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iOpus-I-M; MyIE2; FunWebProducts-MyWay)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iOpus-I-M; NetCaptor 7.5.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iP-BLD03)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iPrimus)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; iPrimus; OptusIE501-018)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98);JTB:140:1255fb21-285b-11d9-bc23-444553540000" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98);JTB:15:344477a2-2c6d-11d9-a611-000854034fa2" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; JUNO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; JyxoToolbar1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; KB0:176933)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; KPN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MADE BY WEBO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MathPlayer 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MathPlayer 2.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MathPlayer 2.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MindSpring Internet Services)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSN 8.0; MSN 8.5; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSN 8.0; MSN 8.5; MSNbQ001; MSNmen-us; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSN 9.0;MSN 9.1; MSNbQ001; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSN 9.0; MSNbBBYZ; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSOCD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSOCD; AtHome021SI; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSOCD; AtHomeEN191)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSOCD; Cox High Speed Internet Customer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MSOCD; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MyIE2; iOpus-I-M; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MyIE2; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; MyIE2; Q312461; Maxthon)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Neostrada Plus 5.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Neostrada TP 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Neostrada TP 6.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; NetCaptor 7.5.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; NetCaptor 7.5.3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.1.4322),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.1.4322; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; NN4.2.0.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusIE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusIE501-018; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusIE501-018; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusIE55-27)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusIE55-28)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusIE55-31)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusIE55-31; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusNetCable-02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusNetDSL6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OptusNetDUI6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OZHARLIT6.0_1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OZHARLIT6.0_1_PP3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; OZHARLIT6.0_1_PP3; Hotbar 4.1.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Panoramic IT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCM_04; DVD Owner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCM_06a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCQuest)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCQuest; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCUser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCUser; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PCUser; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PeoplePC 1.0; hpford)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PeoplePC 2.4.5; ISP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PeoplePC 2.4.5; ISP; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Pioneer Internet - www.pldi.net)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PKBL008; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; PowerUp IE5 1.01.02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; pro)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; provided by blueyonder)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; AT&T CSM6.0; AT&T CSM7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; DF23Fav/2.5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; H010818; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; H010818; yie6_SBCDSL; sbcydsl 3.12; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; TUCOWS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q312461; YComp 5.0.0.0; NN5.0.3.3; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q321017)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Q321120; Feat Ext 1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW03398)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW03399)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW0339a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW0339b; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW0339c)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW0339d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW0339m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW03404)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW0340e; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW0340k)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; QXW03416)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; (R1 1.1); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; (R1 1.3); (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Roadrunner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Roadrunner; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Rogers Hi-Speed Internet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Rogers Hi-Speed Internet; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; sbcydsl 3.12)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; sbcydsl 3.12; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SEARCHALOT.COM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Sgrunt|V108|867|S538318592|dial; snprtz|S03066638220053; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SIK1.02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SIK30)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SIK30; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SIS; {SIS})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SiteKiosk 5.5 Build 36; HBBKLP01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Skyline Displays, Inc.; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SL102000; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SpamBlockerUtility 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Spartipps.Com PS Edition; iOpus-I-M; MyIE2; DX-Browser (V4.0.0.0; http://www.dxbrowser.de))" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SPINWAY.COM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Strato DSL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; StumbleUpon.com 1.735)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; StumbleUpon.com 1.758)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; StumbleUpon.com 1.760; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Superonline)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Supplied by Cloudnet, Inc.)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; supplied by tiscali)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; sureseeker.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SYMPA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; SYMPA; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Hotbar 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Newman College)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Q312461; Hotbar 4.0; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T312461; V-5.5SP2-20011022)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; TBP_6.1_AC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; tco2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; telus.net_v5.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; telus.net_v5.0.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; TencentTraveler )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; TeomaBar 2.01; Wysigot 5.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; tiscali)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; TNET5.0NL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; T-Online Internatinal AG; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Total Internet; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; TUCOWS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; TUCOWS; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; TUCOWS; Q312461; FunWebProducts; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Ubbi)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; V1.0Tomorrow1000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; v11b.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; V-5.5SP2-20011022)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; VNIE5; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; VNIE5 RefIE5; SCREAMING_IE5_V2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; VNIE60)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; VZ_IE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; VZ_IE6; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; W3C standards are important. Stop fucking obsessing over user-agent already.)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Wanadoo 5.6),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Wanadoo 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Wanadoo 6.0),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Wanadoo cable; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; WC/qrDwCOdiRzNfl)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Web Link Validator 3.5" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) WebWasher 2.2.1" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; WestNet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x4.90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; 1&1 Internet AG by USt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; {2A23FA2A-F9FD-484E-801D-DF232F7C64BA}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; {74787047-5497-4FC4-8302-D08B74E01B4B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; APCMAG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; AskBar 3.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; AT&T CSM6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; AT&T CSM6.0; AT&T CSM8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; AT&T CSM6.0; VZ_IE6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; AT&T ELC5.5; T312461; {Cablevision Optimum Online})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; AT&T WNS5.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Avant Browser [avantbrowser.com])" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Avant Browser [avantbrowser.com]; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Avant Browser [avantbrowser.com]; YPC 3.1.0; iOpus-I-M; .NET CLR 1.1.4322)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; BIGPOND_ADSL_42)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; BIGPOND_ADSL_42; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; brip1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; BT Business Broadband)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; BT Openworld BB; YPC 3.0.2; FunWebProducts; yplus 4.3.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; BTopenworld; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; {C954D864-F84E-7490-1E6D-7AF74AE2E175})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; CDSource=ALLIED_01_01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Charter B1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Cox High Speed Internet Customer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Creative)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; c't)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; DT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; DT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; DT; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; DT; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; {E895B1EF-805F-4965-88D8-54AF2D5541F7})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; EnterNet; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; ESB{6BC1B80D-8E38-4080-99B0-2440E59328A1})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; {F77382BC-AB24-49B4-8059-71D9365FEEB2})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Feedreader)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FREE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; freenet 4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FREESERVE_IE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FunWebProducts; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FunWebProducts; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FunWebProducts; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FunWebProducts-MyTotalSearch; FunWebProducts; Hotbar 4.4.6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; FunWebProducts; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; generic_01_01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; H010818; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; H010818; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar 4.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar 4.1.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar 4.2.11.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar 4.2.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Hotbar4.5.3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; HWE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; iebar; MSN 9.0;MSN 9.1; MSNbQ002; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; JJ)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Mailinfo [1999999999999999])" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MSN 9.0;MSN 9.1; MSNbQ002; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MSN 9.0;MSN 9.1; MSNbQ002; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MSN 9.0; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MSOCD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MSOCD; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; MyIE2; Free Download Manager)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; ONDOWN3.2; AtHome021SI)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; OptusIE55-31)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; OptusIE55-31; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; OptusIE55-31; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; OptusNetCable-02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; OptusNetDUI6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; OUBrowser; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; PC ACTUAL (VNU Business Publications España)),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; PCUser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; PCUser; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; PCUser; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Provided by Alphalink (Australia) Pty Ltd; H010818; FunWebProducts);JTB:15:d16f74f8-64d6-4024-a74d-b8724a1c548c" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; FtSoJ 666)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; Hotbar 4.1.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; Hotbar 4.5.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; LDE0308a; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; SEARCHALOT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461) WebWasher 3.3" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q312461; YPC 3.0.1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Q321120; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Queens-ITS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; QXW0337s)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Roadrunner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Rogers Hi-Speed Internet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Rough Cutz)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; sbcydsl 3.12; FunWebProducts; yplus 3.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; sbcydsl 3.12; YPC 3.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; SIK1.02; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; SIK30)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; SIK30; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; son0302CD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Sunet v2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Supplied by blueyonder)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Supplied by blueyonder; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Supplied by blueyonder; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; SYMPA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; T312461; Headline-Reader; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; T312461; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; T312461; Wanadoo 5.3; Wanadoo 5.5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; T312461; Wanadoo 5.5; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; TeomaBar 2.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; T-Online Internatinal AG; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; TUCOWS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Virgin 3.00; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; VZ_IE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; VZ_IE6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; Xtra)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; YComp 5.0.2.5; SIK30)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; yie5.5_SBCDSL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; yie6_SBC; YPC 3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; YPC 3.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; YPC 3.0.1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; WRV)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; www.ASPSimply.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; www.k2pdf.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; www.spambully.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Xtra)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Xtra; Hotbar 4.3.5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.0.0; Cox High Speed Internet Customer; sbcydsl 3.12" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.0.0; OptusIE55-31)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.2.4; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.2.5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YComp 5.0.2.6; IESYM6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBCDial; YPC 3.0.0; FunWebProducts; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBCDSL; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBCDSL; sbcydsl 3.11; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBCDSL; sbcydsl 3.12)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBCDSL; sbcydsl 3.12; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBCDSL; sbcydsl 3.12; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBCDSL; sbcydsl 3.12; yplus 3.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6_SBC; YPC 3.0.1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; yie6; YComp 5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.0.0; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.0.0; BT Openworld BB; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.0.1; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.0.2; BT Openworld BB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.0.2; BT Openworld BB; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; YPC 3.1.0; yplus 4.5.03b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; MyIE2; PPC; 240x320; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows compatible LesnikBot)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; 11-12-2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; 3COM U.S. Robotics)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; ABN AMRO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; AIRF; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; APC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; APCMAG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Aztec)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Bank of New Zealand)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; BVG InfoNet V5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; CLS4; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; CNETHomeBuild03171999; DigExt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; COLLAB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config A V1.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config A V1.3; Config C V1.3; v5 C5; Config D V1.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config A V1.3; Config D V1.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config A V1.3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config A V1.3; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config A V1.3; v4.0 C3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config A V1.3; v5 C5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Config A V1.0; Config D V1.3; Config A V1.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; CT2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Deepnet Explorer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; digit_may2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; digit_may2002; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; eircom/june2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Girafabot; girafabot at girafa dot com; http://www.girafa.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; H010818; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; H010818; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Hays Personnel Services)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Hotbar 4.1.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Hotbar 4.1.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Hotbar 4.4.5.0; Config A V1.0; Config A V1.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; HVB 2/2001; HVB-GROUP, 0001_CIT; spunt-ois-intranet; ois-intranet; HVB: NT-OIS; HVB; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; HVB 2/2001; HVB; NT-Zentrale; HVB-GROUP, 0001_Zentrale; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; IE55CX1; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; JPMC_CDI)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; MCS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; MRA 2.55 (build 00423); MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; MSIE5.0; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; MyIE2; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; NAB PC IE6SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; NetServ; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; P20314IEAK1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; PCQuest; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; PCUser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; po; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Q312461; QXW0339m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Q342532)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Qwest - 11122003-a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; QXW0339c)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; QXW0339m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; RBC; 9LA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; RZNT2000.010)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; SDE 2/12/02 1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; SEARCHALOT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; STIE5-000710)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; supplied by tiscali)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; DI60SP1001; DOJ3jx7bf; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; Hotbar 4.1.8.0; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; Q312461; (R1 1.1); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; Q312461; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; SI; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; T312461; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; terranet.pl; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; TESIEAK6a; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; TTC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; TUCOWS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Union Pacific Corporate Image)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; v1.0 C1; v4.0 C3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; v1.0 C1; v4.0 C3; iOpus-I-M; v2.0 C1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; v1.0 C1; v4.0 C3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; www.ASPSimply.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; Yahoo-1.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; YComp 5.0.0.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible;MSIE 6.0; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {01B9B056-41CF-4C49-9F15-FBFD356FACB9}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {06123460-5191-47D8-9801-E64CEE8E7D7C}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {061F9742-FB3A-4B13-8D81-F1DBCFA49E24})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {06537897-63B2-495D-BD75-97D5F17AEF61}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {0D43CA9A-9A2A-4AD3-9FB3-D11ED856701C})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ¾ÜÆÄÀÏ (atfile.com); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {109E9252-FC9D-4712-9D79-AC1C6061FD02}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 1&1 Internet AG by USt; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 123-Reg The Cheapest & Easiest Way to Get a Domain Name)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {12AB035D-BD79-4DED-B042-E95ED524B435}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {143F7CDC-2BEF-45ED-9CA0-9B2076F467D4}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {144098F2-DE3D-4A0E-AA56-C97DABCBEC15})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 1.57.1 )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {19449247-55EC-4B9A-A99C-A1FD75AB322A})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {1AAA4471-A825-4D94-9F91-18DF18D97101}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {1B07E273-0A6C-440D-8E04-CBB9F30106AD})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 2.5.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {282E02E6-44BF-4FF6-9C84-59755CC87202}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {298A087F-0FE1-40C9-A893-97A76A73F88E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {2C0881E9-B6B7-45DB-BFDF-F70BB47FA680}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {2DABB6D9-031A-4174-9C59-D87776C152AC}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {2E487848-058A-4532-83EE-AFF12A987739}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {305B1A70-D1DC-45EF-AA35-F707BBEE85EC}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 3303; iebar; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {338C77F9-6668-40F2-B9AA-7B8B3AACAADA}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {3504DB01-C872-40F5-90A1-A76E8C7BA7F8})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {359046E3-C000-44A8-90B3-BA1FA146D3ED}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {3FD9CEF8-894A-4FFE-BD59-6B3A28A6967A}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 3M/MSIE 6.0;; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 3M/MSIE 6.0;; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {4E075391-5B06-46A7-872B-70EB64C44294})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {4EC4D46A-2224-42E4-B20E-263A00146AD5}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {4F1675AF-7549-42E8-A055-6E4554DDB2B6})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {53D150F0-3948-40FB-AED0-BC12A07D16CB}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {57B317DC-AF18-477D-B26C-D635B7BC0C6C}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {59290DD6-57E1-419C-A050-BC983EB72656})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {5C6515F0-765B-4AD8-A168-3761FB537EBB}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {5DB0254E-3F8C-4DDA-A3D4-6C543537187B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {607C5361-86F7-42A1-8BC4-E3BB7EF36E49}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {62BA8785-A517-4CF6-8456-56716A6D1158}; iebar; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {649E2463-3332-4F08-A0B1-8CCC13C2A5B6}; CLX-IE-5.5sp2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {665CA5DF-6149-4382-9952-7B39C4A56AD1})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {68B11FD1-3CDB-4433-8D4B-FAC8D8352E6E}; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {6B81900A-D6AA-461E-8FC6-1620330AC921}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {6B9216F6-4521-47B0-B084-2A8E511A0B9F}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {6D3765E4-9B4F-43FA-A724-82E2F0EF0D1F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {6E0F184F-9748-4A0E-8B0C-F812273A1D33})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {6E678899-843C-496E-9B27-A35206C3E26B}; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {6EFA4147-88FB-4570-8DA4-EE21FA159006}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {70E73558-8F52-4A75-9312-C8E68DEDAB57})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {7144A0D4-D427-4095-B265-D15A8756742F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {79AF7E55-D81C-44D9-8636-94129DF9DF37}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {79CEA9FC-BE53-45A3-B81D-B66479A78C7D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {7A9D705C-6447-43AF-9CBD-F3EBBC64467D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {8036F106-4980-4D9C-8E40-BC990D1C5340}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {81629412-DDAE-4320-9573-1909044055F5})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {86464A58-0461-4217-8D58-67F6F1813A02}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {89CD3E7F-86F4-4766-8A15-773ED2B1ECDA}; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 90)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {90333DAB-0FE6-4FE7-9F0A-37211DA1DD26})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {90A67E22-1FA8-46DB-913D-5BFAB83B9187}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {9444DFA5-F00A-4C9C-A481-D228454293AC})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {96C6F6D2-27AB-4CE8-A693-5FB34DED41C9})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {9C8127EF-235E-4DB5-A132-FB67DCB6DB9E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; 9L5.5; 9LA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A253E2A3-43A6-4F7C-ACE5-7ACE750E8496}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A26143E3-E395-4A08-906C-2094F96F9992}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A39C4CA3-D28E-48DF-A362-5D0862045D4B}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A45DB481-08E3-4625-85C0-18D272EFA672})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A5E3D903-A7D5-493D-8319-D7A126A43C4E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A64C95F3-2891-4793-8163-A6165CF588EC})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A6B5140D-D366-4853-A784-224D481F964A})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {A6E2595A-77BF-4A90-BDD6-581660B19BAF}; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AAL; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AAPT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ABACUS LABS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Abbey National PLC; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Abiliti Solutions; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ABN AMRO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ABN AMRO; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ABN AMRO; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Agilent Technologies IE5.5 SP2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Agilent Technologies IE5.5 SP2; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Agilent Technologies IE5.5 SP2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AGIS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AIRF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AIRF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AIRF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AJA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Alcatel Portugal IE6 SP1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Alexa Toolbar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; alice01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ANZ Banking Group)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ANZ Banking Group; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AOL 9.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APC; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APCMAG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APCMAG; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APCMAG; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APCMAG; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APCMAG; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APC; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; APC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AQL - Groupe Silicomp; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AskBar 3.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AskBar 3.00; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AskBar 3.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AskBar 3.00; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM6.0; AT&T CSM 6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM6.0; AT&T CSM7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM6.0; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM6.0; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM6.0; www.ASPSimply.com; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM7.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM7.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T CSM8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; AT&T WNS5.1; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser 6.5.1.3 [avantbrowser.com]; .NET CLR 1.1.4322)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser 7.0.0.8 [avantbrowser.com]; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]; Feedreader)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]; i-NavFourF; NetCaptor 7.2.2)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]; .NET CLR 1.1.4322)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avant Browser [avantbrowser.com]; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Avi 1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {B0B866F5-5095-4A87-AD12-D436006DEE38}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; b2c01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {B42D1284-FDB2-4F37-A1DF-857CBBCA89B2})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {B75CE5DB-567A-44D7-920D-1228B51B3B3E}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Bank of New Zealand)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BAssF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BB1.0 IE5.5.2; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BB1.0 IE5.5.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BB&T Standard Load (IE 6 sp1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BCD2000; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BCIE6SP1; .NET CLR 1.0.3705; Working 081103 Rev 6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BCUC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; bfz Aschaffenburg)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; bgflie; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BIGPOND_ADSL_42)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BIGPOND_ADSL_42; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Boeing kit)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Boeing Kit)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Boeing kit; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Boeing Kit; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Boeing kit; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BOTW)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BOUK)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; brip1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; brip1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BSS; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BT [build 60A])" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; btclick.com Build BTCFMFQ3; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BT Openworld BB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BTopenworld; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; bull ;-) ; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Business 1st; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; BWL 5.5 IEAK; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; by Hi-HO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; c20010830)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {C545DFFA-2A55-4A99-AC19-EB846E5457EA})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {C5C1AC35-93B1-48C0-BAD1-FD616C71A118}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {C6A15346-4AC9-4272-8CF7-151480C6A9D4})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {C7132536-FBAC-4135-9D87-C6DEC6B0AFE0}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {C8EA929F-150F-4C5F-81E2-A258BEDBF712})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {Cablevision Systems Corporation})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {CB1C5177-05C4-4DFE-B687-AD6AF39ACD3E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {CB46BCEF-212D-452A-9341-734FBBA61540}; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CBC/SRC; Hotbar 4.4.9.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CCSU; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {CD8D3547-6274-46D5-947D-12B00C362FD5}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=ALLIED_01_01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=ALLIED_01_01; ESB{1A596234-D5AD-49CF-A3D5-B814562D9F84})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=ALLIED_01_01; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=BP1b.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=BP1b.00; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=v2.15e.03; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=v2.15e.04)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CDSource=vBB1c.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {CF867BA5-3DE3-4197-A46B-0C7BBF5C2285}; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {CF8E2F64-C6B1-4DAE-BFDE-0D69737FAA8A})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Chemopetrol)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CHOP_IE55_V2; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CHWIE_SE60)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CIBA SC Standard Setup)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CIBA SC Standard Setup; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; City of Mesa, Mesa, AZ, USA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CL_P2K_1_1_2_1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CNGTRUST)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CO770; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Coles Myer Ltd.)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Coles Myer Ltd.; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Coles Myer Ltd.; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; COM+ 1.0.2204)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Combellga; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; compaq)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Compaq; DigExt; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; compaq; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; compaq; T312461; Hotbar 4.1.8.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Compatible; Version; Platform; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Computer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Computer) WebWasher 3.3" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Config D; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Conman 2.5; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Cox High Speed Internet Customer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Cox High Speed Internet Customer; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Cox High Speed Internet Customer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CoxIE55)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CoxIE55; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CPT-IE401SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CPWR)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Creative)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Creative; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CSMMWebClient1001; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CSUF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; cust 2.01 r7; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Customized by Adrian Connor; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; CyberZilla; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {D208973F-8755-4E82-A102-0AAA11511D7B}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {D4183739-BB5C-46AB-B754-64727133F2A5}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {D48C8B2F-108A-48C8-9F5F-058A0125BFB9})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {D86494B1-7D5D-4748-838D-529552349E2B}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {DA7D9C31-C746-405E-A35A-6798A9DD3842})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Data center)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Datavend Internet Services)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DCC=6.SP1-E)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {DD52EB3A-6F72-4BDC-8490-161016E9E39C})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Debian Linux; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Deepnet Explorer 1.3.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Deepnet Explorer 1.3.2; Lunascape 1.4.1)" + family: "Lunascape" + major: '1' + minor: '4' + patch: '1' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Deepnet Explorer 1.3.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Deepnet Explorer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Deepnet Explorer; .NET CLR 1.1.4322; .NET CLR 2.0.40607; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Deptartment of Premier & Cabinet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Dept. of Primary Industries)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DeptoMtz/237)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DET_ITD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DHSI60SP1001)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DHSI60SP1001; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DHSI60SP1001; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; dial)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Dialer/1.10/ADSL; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; dial; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; Hotbar 4.2.11.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; MyIE2; FDM)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; OZHARLIT6.0_1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; Q312461; NetCaptor 7.0 Beta 3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; Q312461; NetCaptor 7.0 Beta 5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; ScreenSurfer.de; http://www.ScreenSurfer.de; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; Tucows)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DigExt; YPC 3.0.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; digit_may2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; digit_may2002; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; digit_may2002; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; digit_may2002; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DIL0001021)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DOF-IE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DOJ3jx7bf; T312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; drebaIE-ZE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DrKW=IEAK; DrKW; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DrKW; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DT-AT; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DT; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; DVD Owner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {E39E04A9-A873-4BEB-8AC9-8AAE2C5F4B36}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {E4CBDA2C-2AD6-4963-934B-78AA66873B09})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; E5; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {E6BC9F59-0BE1-42F0-B30B-28E630FC426C})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; [eburo v1.3])" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {EDEBBC92-1A23-4CCF-A287-E7C446EE184E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; EDS; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; eircom/june2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; EMC IS 55; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Endeavour Sports High School)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Era)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ERACON AG; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{18990B24-B930-4963-9F4A-61EC73B586A7})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{262D05ED-F4C4-41AA-9DF8-72398CBAFD6B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{3B40AD5C-7E2F-46D4-9A6A-7C43322AC378}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{3E1AFDF1-14A8-422C-AE93-58363EDEAF96})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{5CEA4270-4309-43DE-913E-4A34AC4DDAC0})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{5D6E1D2C-9FB8-4423-8E9D-9AD635CED031}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{6000F0D1-9B3D-429E-9991-2DA84AB29E7A}; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{69A214B6-5A7B-43E5-89D8-E8F4A9946F3E}; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{97B6FDFD-F75F-4CB4-8F1D-FA16B707E202})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{9FFE22ED-496B-4730-B4EA-CFCDCAF1FCAE})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{A6A5FEED-9585-4F90-8424-38ED6FD61D32}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{CDD58A96-417A-4783-B196-B39BD35B879E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{E8E61902-FB81-4DDA-8BD2-1CE907F88866}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{F512E5D9-AF79-49FE-A3A6-83693239F5C0})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ESB{F7D303AF-E887-4662-945C-FF4B3413A379}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; EV20020426A; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; EXPRESS_004; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ezn)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {F1EA689F-1B1F-474B-8E21-C2122AD49CE8})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {F30610B3-0195-4745-BFEF-D07509032CA2})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; F-5.0.1SP1-20000718; F-5.0.1-20000221; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {F60857FB-3034-40CF-9E34-A28D3EF30C9F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; F-6.0SP1-20030218)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; F-6.0SP1-20030218; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {FABA9F34-879A-44F2-84B8-83E37CC31579})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FastWeb)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FastWeb; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FCP Intranet Browser; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {FD5A89C5-E2DA-4278-BBCB-B19DA07185AB}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {FD604FB4-DBBF-481F-A46F-543390363E21})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; {FDD074C3-CFD3-4CD5-B6FA-1A4AE8C0852D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FDM; COM+ 1.0.2204)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FDM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Feat Ext 21)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Feedreader)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Feedreader; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Feedreader; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Flow Systems)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; formsPlayer 1.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; formsPlayer 1.3; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FORSCOM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Franciscans Australia; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FREE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FREETELECOM; Wanadoo 6.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FREE; Wanadoo 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Fujitsu Services GmbH, Germany; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; bkbrel07)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; FunWebProducts-MyTotalSearch; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; GameBar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; Hotbar4.5.3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyTotalSearch)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyTotalSearch; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay; MSIE 6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay; .NET CLR 1.0.3705; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts-MyWay; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.0.3705; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.1.4322; Google-TR-1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 1.1.4322; .NET CLR 2.0.40301)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; (R1 1.5); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FunWebProducts; Telia; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; FUSAIE55SP2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GENA SDV2.1; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GEP IE 5.5 SP1 Standard)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GEP IE 5.5 SP2 Standard; GEP IE 5.5 SP1 Standard; GESM IE 5.5 SP2 Standard)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GEP IE 5.5 SP2 Standard; GEP IE 5.5 SP1 Standard; T312461; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GEP IE 5.5 SP2 Standard; GEP IE 5.5 SP1 Standard; T312461; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GIS IE6.0 Build 20020920)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GIS IE6.0 Build 20031007)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GIS IE6.0 Build 20031007; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GIS IE6.0 Build 20031007; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GMX AG by USt; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Google)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Googlebot)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GPM - MSIE 6.0 SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Gulfstream Aerospace)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; 3M/MSIE 6.0;; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; 824145)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; 824145; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; 824145; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; 828750; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; 828750; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; ANZ Banking Group)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; AT&T CSM7.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; BASA Standard)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; BB55; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; BCIE6SP1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; brip1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Client Engineering 20010828; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; HEWLETT-PACKARD -- IE 5.5 SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Hewlett-Packard; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Hotbar 4.3.1.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Inovant)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Inovant; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; iOpus-I-M; YComp 5.0.8.6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Q316059)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; Roadrunner; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; RVQhNDHN5fHE9Vytg36u/rdyxKj6LSKTLgkNEyABZ==)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; SILSOE; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; T312461; Hewlett-Packard; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; T312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; UB1.4_IE6.0_SP1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; UB1.4_IE6.0_SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; UB1.4_IE6.0_SP1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; H010818; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HCJME)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Heath Park High School; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Het Net 3.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Het Net 4.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hewlett-Packard)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hewlett-Packard IE5.5-SP2; Hotbar 4.1.8.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hewlett-Packard IE5.5-SP2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hewlett-Packard; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HMEUK)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HO32600; HO32501; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HomePage)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 3.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 3.0; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0; Hewlett-Packard IE5.5-SP2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.2.14.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.2.4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.2.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.3.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.3.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.6.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.4.6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.5.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar4.5.3.0; MyIE2; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hot Lingo 2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hot Lingo 2.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HTMLAB; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; http://InternetSupervision.com/UrlMonitor)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; http://www.pregnancycrawler.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HWT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IBP; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IBP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ICT 20021217; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; &id;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IDG.pl)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE5.5_ SP2_wOLE; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ie6dist)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE6IEAK; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE6/SEF; IE6/FO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE6 SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE6SP1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE6SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iebar; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iebar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iebar; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE_EFY)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IESFYINTL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IESFYINTL; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IESYM6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IESYM6; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IESYM6; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IE UACh; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Illinois State University; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Illinois State University; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-MailBook; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF; FeedEater; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; i-NavFourF; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; InfoCommons)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; infor INTRANET; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Installed by Symantec Package)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Installed by Symantec Package; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Internet Cafe 324)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Internet Cafe 324; ICafe 324)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; internetsupervision.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; INTRANETUSER)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; INTRANETUSER; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; Alexa Toolbar; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; PRU_IE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iOpus-I-M; (R1 1.5); .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; iPrimus)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Issued by ACC Web Services; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; istb 644; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; istb 702)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; istb 702; AskBar 3.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; istb 702; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ISU; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; IWSS:PC-8684-ayrale; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; KC135ATS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; kiev.xvand.net; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322; hunter)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; kinglothar; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; KITV4.7 Wanadoo)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; KITV4.7 Wanadoo; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; KKman2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; KKman3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; KKman3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Kvaerner ASA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; L1 IE5.5 301100; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ; labs.giannone.unisannio.it; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LCAP-CB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LCPL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LDE0308a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LDE0308a),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; @lee-road.co.uk)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LendingTree.com; AIRF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LLY-EMA-EN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LM-MS; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LM-MS; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Lockheed Martin TSS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Logica 5.5 SP2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Logica 5.5 SP2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Loyal 4arcade.com User II)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LU)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; LWC-dev)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maersk Data AS, Denmark; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Magistrat Wien)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Magistrat Wien; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Manufacturing and Customization)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Marineamt Rostock; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MathPlayer 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MathPlayer 2.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MathPlayer 2.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MathPlayer 2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MathPlayer 2.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MathPlayer 2.0; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; Alexa Toolbar)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; MyIE2)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; MyIE2; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Maxthon; (R1 1.3))" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Mazillo)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MBsdk0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MenloIE; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MISCS 1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MMS Standard)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Monash University (Customised IE 5.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Mozilla/4.0 (compatiable; MSIE 6.0; Windows NT; Anexsys LLC))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Mozilla/4.0 (compatible; MSIE 5.0; Debian GNU/Linux; Windows NT); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Mozilla/4.0 (compatible; MSIE 5.0; Win9x/NT; JUNO))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HDR.05.01.00.06; .NET CLR 1.0.3705; .NET CLR 1.1.4322); .NET CLR 1.1.4322))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MRA 2.5 (build 00387))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MRA 4.0 (build 00768))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; msie 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc0z)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSOCD; AtHome020; Vj2qqm9YVSwdmA06; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSOCD; AtHome021SI; YPC 3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSOCD; AtHomeEN191)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSOCD; Hewlett-Packard)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MSP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MTK; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; Alexa Toolbar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; FunWebProducts)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; FunWebProducts; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; FunWebProducts; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; iebar; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; i-NavFourF)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; i-NavFourF; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; Maxthon)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; MRA 4.0 (build 00768); .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; NRTE; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; Poco 0.31)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; Poco 0.31; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; (R1 1.3))" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; (R1 1.5))" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; (R1 1.5); .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; Websearch4u 2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NAB PC IE6SP1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 6.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 7.0.2 Final)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 7.0 Beta 2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 7.5.0 Gold)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 7.5.0 Gold; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 7.5.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 7.5.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NetCaptor 7.5.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 2.0.40426)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; Alexa Toolbar; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; Free Download Manager)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 2.0.40301)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 2.0.40607; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322) NS8/0.9.6" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322) via Avirt Gateway Server v4.2" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322) WebWasher 3.3" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322) (www.proxomitron.de)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 2.0.40607; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 2.0.40607; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Net M@nager V4.00 - www.vinn.com.au)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Nevada DOT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NIX)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NN5.0.4.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; N_O_K_I_A)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; N_O_K_I_A; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; N_O_K_I_A; TheFreeDictionary.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Nomad)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Nordstrom; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Nordstrom; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NoSpiesHere)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Novo Nordisk Engineering A/S)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NSWFB SOEWKS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NSW.net)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ntlworld v2.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NTSSVCCORP04022001-ELSAUG2001; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; NZCity 6.0; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ODP links test; http://tuezilla.de/test-odp-links-agent.html)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Office of State Courts Administrator)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusIE55-27; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusIE55-31)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusIE55-31; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusNetCable-02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusNetCable-02; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusNetDSL6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; OptusNetDSL6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Orange Development Dinges)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PAS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCM_06a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCM_06a; Hotbar 4.4.1.1381; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCM_06a; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCnet Version January 2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCQuest)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PC SRP 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCUser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCUser; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PCUser; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PHS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PhysEd)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PIB99A)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Pierce County WA v1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Planet Internet PIM 2; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PNCStd; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PneuDraulics Inc - Rancho Cucamonga - CA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PowerGeekz Rulez; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PPI 05022002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Private information. DO NOT SHARE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Progressive Insurance; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Progressive Insurance; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Provided by Alphalink (Australia) Pty Ltd)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; provided by CRC North Keilor)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PRU_IE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PsyStudentDesktop)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PVH; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; PwCIE6v01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q123456)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; ADP Micro 6.0 SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Amgen.v1b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Amgen.v1b; YPC 3.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Amgen-v1c)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; APCMAG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; AT&T CSM 6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; compaq; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; ESB{586E8C53-5BFC-491B-928B-AA1E0EDEC154})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; ESB{E6216221-1B63-48B0-B352-CF03FD47282F}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Feedreader)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; HD 6.1 Custom; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Hotbar 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Hotbar 4.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; i-NavFourF; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; ir.ie6.v1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Marshfield Clinic)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Mind Your Own Damn Business!!!!!!)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; MSIE 5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; MTK; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; MyIE2; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; MyIE2; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; .NET CLR 1.0.2728; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322; ByteMe_6969)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; ONDOWN3.2; Cox High Speed Internet Customer; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; OptusIE55-31; OptusIE501-018)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; QXW0339r; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; sbcydsl 3.12; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; SEARCHALOT.COM IE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; SWFPAC NSB IE6sp1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; Walsrode Online http://www.walsrode-net.de)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YComp 5.0.0.0; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YComp 5.0.0.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YComp 5.0.2.6; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YComp 5.0.2.6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; YPC 3.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q321064)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q321120)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Q342532)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QPC MegaBrowser 1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QPC MegaBrowser 1.0; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QS 4.1.1.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QS 4.1.2.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QS 4.1.2.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW0333r; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW03399; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW0339a; MyIE2; Maxthon; i-NavFourF; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW0339d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW0339d; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW0339h)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW03411; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW03413)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW03416)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW03416; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; QXW03417; Gruss von BURGSMUE; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.1); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.1); (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); .NET CLR 1.1.4322; SiteKiosk 5.5 Build 45; ALAMOANA2; SiteCoach 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.3); (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.5); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; (R1 1.5); .NET CLR 1.1.4322; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; RA_APAU)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; RayDen)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; RBC; 9LA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; RC75 Release)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; RC75 Release; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Reuters Global Desktop)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; RHIE6SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; RIS GmbH - 1.1 - A)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Roadrunner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Roadrunner; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Rogers Hi-Speed Internet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Rogers Hi-Speed Internet; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) RPT-HTTPClient/0.3-3" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SAA; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SailBrowser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SALT 1.0.4223.1 0111 Developer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SALT 1.0.4223.4223 0111; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SALT 1.0.4613.0 0111 Developer; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SALT 1.0.4613.0 0111 Developer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SALT 1.0.4613.0 0111 Developer; Search Box Toolbar 1.0b2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SBC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SBC; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SBC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.11; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; FunWebProducts; yie6_SBCDSL; yplus 3.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YComp 5.0.0.0; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YComp 5.0.0.0; UB1.4_IE6.0_SP1; iebar; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YComp 5.0.0.0; yie6_SBCDSL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YPC 3.0.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YPC 3.0.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sbcydsl 3.12; YPC 3.0.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SBC; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SCB; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SDS IE6 SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SDS IE6 SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SDS IE6 SP1; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SEARCHALOT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SEARCHALOT 102303)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SEARCHALOT.COM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SEARCHALOT.COM IE5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SEARCHALOT.COM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Siemens Testmanager; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SIK1.02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SIK30)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SIK30; FunWebProducts; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SIK30; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SiteKiosk 5.5 Build 45; SiteCoach 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SKM v1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SlimBrowser [flashpeak.com]; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SLM; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Smart Explorer 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Smart Explorer v6.0 ( Evaluation Period ); Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SMSHome (http://www.aggsoft.com); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; snft internet; SEARCHALOT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; S.N.O.W.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; S.N.O.W.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; snprtz|dialno; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SOEBUILD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SPEED; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SQSW)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SRA-60-05032003; RC-60-040226)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StarBand Version 1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StarBand Version 4.0.0.2; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Steria102002; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Steria Browser - MKG; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; STIE55-010209; STIE5-000710; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; STJUDE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; student.vuw.ac.nz)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.733; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.733; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.736; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.737; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.755)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.760)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.917)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; StumbleUpon.com 1.917; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; stumbleupon.com 1.924)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Supplied by blueyonder)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Supplied by Tesco.net; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; sureseeker.com; iebar; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; surfEU DE M2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SURFkit V5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SWSIT; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SYMPA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SYMPA; ESB{F8AB14A0-3270-47A7-9717-22047C6C04E7}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SYMPA; FunWebProducts; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SYMPA; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SYMPA; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; SYMPA; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Systems Management Server (4-28-03))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; t20010828; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; AIRF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; BTOW V9.5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461;DI60SP1001; {1D9923A3-DFFD-4703-95E9-DB38D1421256}; DI60SP1001; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461;DI60SP1001; {1D9923A3-DFFD-4703-95E9-DB38D1421256}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Digipub,Grape; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; DonRocks; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; DSCC/DLA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; EK60SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Emf!sysUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; F-6.0SP1-20030218)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; FunWebProducts; Hotbar 4.4.5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; FunWebProducts-MyWay; drebaIE-ZE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; FunWebProducts-MyWay; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; General Mills, Inc -6SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; General Mills, Inc -6SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Hewlett-Packard IE5.5-SP2; YComp 5.0.0.0; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Hotbar 4.2.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; iebar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; IE_DT2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; image_azv)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Infowalker v1.01; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; iOpus-I-M; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; istb 641; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; istb 702)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; MRA 4.0 (build 00768); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; MyIE2; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 1.0.3705; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 1.0.3705; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; PC SRP 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; PC SRP 2.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; PC SRP 2.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; PC SRP 2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; PGE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; PGE; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; POIE4SP1; POIE4SP2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; POIE4SP2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; PPG; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Q312461; (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; (R1 1.5); .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; sbcydsl 3.12; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; SBS V1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; SBS V1.1; SBS V1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; SLM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; TeomaBar 2.01; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; TTUHSC; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; Tyco Electronics 01/2003)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; YComp 5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461; YComp 5.0.2.6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Taunton School; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TBP_7.0_GS; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TBP_7.0_GS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TBP_7.0_GS; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TDSNET73INS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Teacher; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TELEFONICA DE ARGENTINA; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Telia; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TencentTraveler )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TencentTraveler ; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TencentTraveler ; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TencentTraveler ; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TeomaBar 2.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TeomaBar 2.01; formsPlayer 1.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TESIEAK6a; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Texas Instruments)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TheFreeDictionary.com; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; The Scots College)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TIDK)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TIETOS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T-Online Internatinal AG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TOYOTA CANADA INC.; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; T-SYSTEMS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TUCOWS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Tucows; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TUCOWS; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TUCOWS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TUCOWS; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TUCOWS; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; TYCHO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Tyco Electronics 01/2003)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Tyco Electronics 01/2003; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UB1.2_IE6.0_SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UB1.4_IE6.0_SP1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UB1.4_IE6.0_SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UB1.4_IE6.0_SP1; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; University of Leicester; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; University of Limerick, Ireland; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; University of Limerick, Ireland; T312461; .NET CLR 1.1.4322) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Updated-1-22-2004)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UPS-Corporate)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UPS-Corporate; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UQconnect)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UQL Public Workstation; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UrlMonitor)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; urSQL; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; user@ch.eu.csc.com; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; %username%)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; utvi160403)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; UWE Bristol; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; VB_ITS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; VBN; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; VDOT IE6 sp1 - Landesk Package 8-2003; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Verizon Wireless 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Verizon Wireless 2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; VEU)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Virgilio6pc)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Vodafone España)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Vodafone España; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Vodafone; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Volkswagen of America; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; VSAT500)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; V-TV Browser7.0.0.0 (Build 700))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; VZ_IE6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; W2K/KW; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Wanadoo 6.1),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Wanadoo 6.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) WebWasher 3.3" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; wg16)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; WHCC/0.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; WHCC/0.6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; WHCC/0.6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; WODC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; WRV)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.acction.com.au)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.amorosi4u.de.vu)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.amorosi4u.de.vu) (www.proxomitron.de)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.ASPSimply.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.ASPSimply.com; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.ASPSimply.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.bfsel.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.k2pdf.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.k2pdf.com; .NET CLR 2.0.40607; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; www.VanessaAmorosi.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; WYETH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Wysigot 5.22; Iconico-WebTools-Pro-v1-0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.0.0; SBC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.4; Hotbar 4.4.2.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.4; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.4; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.4; Supplied by Tesco.net)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.5; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.6; Hotbar 4.4.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YComp 5.0.2.6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBCDSL; sbcydsl 3.12)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBCDSL; sbcydsl 3.12; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBCDSL; sbcydsl 3.12; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBCDSL; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBC; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBC; YPC 3.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBC; YPC 3.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBC; YPC 3.0.1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; yie6_SBC; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.0; yplus 4.0.00d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.1; IBP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.1; yie6_SBC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.3; sbcydsl 3.12; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; YPC 3.0.3; sbcydsl 3.12; FunWebProducts; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ZDNetIndia; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; ZI Imaging Corporation; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0;Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {00E372B7-BEAF-4DE2-8656-D9E207B7A868}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {00FC4ECE-55C0-4CC0-B927-A257C53EEA9B}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {010372B4-6664-4F0F-9F72-69CDEAAEF34C}; SV1; sensis; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {01CCA09B-D5C0-494F-9AB2-C6A542FB3229}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {02E74E79-2624-4118-ACC0-B2B5E3303175}; SV1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {04C71239-93BC-463E-8049-E98C6347C7B6}; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {05292C4C-2C29-4A29-A4A3-07773831343F}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {059455F9-7AF0-4213-B2BF-552E61CC057A}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0840790C-3719-4A4D-95C6-1C8D668C09FB}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {096DD935-8F09-400D-862E-BAB1224F8D8B}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0A4A867A-C305-4125-BDE0-9596EAE3F231}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0A6E773D-A7D9-4536-BA0E-85BC13B3537F}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0A9BDEB0-929E-4F14-B6C5-EEF41B896043})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0AB53206-6DD9-450D-B4AA-685C7E5148B6}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0AB63054-8A7C-42DB-BFD8-DCBDA1D57B67}; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0DC2355B-02C9-42D8-9358-7CC385381704})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {0F233567-886D-460E-BCD2-88171D6F8C04}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {10D39F67-2519-4768-A71A-9F7915E2CABE}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {11C208DD-B1E1-49F3-A67C-2E8F81A0450E}; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 1&1 Internet AG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 1.21.2 ; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1272B23E-8FD1-4BBE-A149-41B4E94621EA})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 1.41.1 ; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {150A8501-CEA4-4B5F-A7C9-55616EDF8F6C}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {154813CD-3783-458E-B7E0-3294360CA69E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 1.56.1 )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 1.57.1 )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1639F6BF-2F23-4A84-AB07-B2FC5A94935A}; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1681F45C-A0AD-4298-922C-5469DF1CB2EB}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {16A0E5E0-30C1-4ACA-AB32-0719A8E952AA})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {17156865-D8E3-4E6C-B430-78B89BA7C978}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {177ECE14-992D-4AA3-894B-5071AFBC00D5}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {18154988-E91C-4941-B5B6-4FD487BC0525}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {18C2BD69-EEEF-4151-BBA4-23B98B4B6B03}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1903CC58-2135-4245-A3C4-C539A1B2F880}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1907B553-57F7-4A6E-870A-C4744E1B6316}; iebar; CustomExchangeBrowser; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1A29EBB4-B546-4452-A5BE-BECD78E4775F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 1C)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1DD69613-6D5A-4E27-862B-7CD98B580F7A}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {1E96F9A7-2DD2-4386-8EB8-7D4B33840A98}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 1ngo!)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 20040404; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2085FE1A-3A52-4263-9403-CB8938637154}; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {22311735-7766-4562-8318-CFBA42C160AD}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {22827DFF-8DEE-4B06-A2D8-42D90E0D53CA})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {23320F0D-2CA6-4BB2-B889-E23EDE240004}; AskBar 3.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {23521C6A-ECC2-4461-B2D4-9D9C390B90F0})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {24886906-C12D-4D24-8A85-046283E20B25}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {26335003-5381-431D-85FC-5FBAE901B682}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {28267C2F-1F37-4133-A363-3AE7FE96A5ED}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {284FBE28-A81E-404D-AF29-EDD0384E1E1F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 2919; 21231; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2C003D7B-598B-0DEA-1120-FD31003AE559})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2C283092-4E93-4C58-ABE1-07EC5031F0D5}; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2D23B066-4320-4A33-97E2-37D1E986227E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2D25856C-B035-4C44-A548-A4A90CFF8355}; ESB{0F85F697-7BE6-4024-9936-09124BD6C11D}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2EC67C21-DA69-496A-A8A2-C518BF746B76}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2F11EBA2-D79D-47CE-8038-E25C5C60CA50})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {2FD51919-0611-4405-A0C0-2B0757909879}; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 2XP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3043E601-196A-4FD7-89B3-30B82C26D3D1}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {32097A18-1D85-423C-913C-A7BFACBE9070}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3277AD62-7541-4E08-85FC-9058C62AFB67}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {328DDFC1-1867-4044-B118-01E6C8878FA6})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 3301)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 3304)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 3305)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 3305; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3328C095-323C-45D5-8C47-94D927422276})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {341A244C-4429-403A-953F-332E6B717C94}; FunWebProducts; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3463A193-AB0F-48A2-A40F-314E277D4FA8}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {35466D8B-0733-4318-9C15-90D01F7D18B4}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {35A6C8BC-4D10-464E-9059-0786612B0949}; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {35DE4964-76A5-4C61-A6C1-12ADF40CF932})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {360D7714-1669-40B4-8A79-8DC66280E427}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {364EDA13-8707-497D-8D19-043EC47F06E9}; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {366089E4-4B15-4161-81BD-0BE380E6C054}; urSQL; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {387DAA29-45E7-4360-9D07-3C17CEF67768}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3A536119-BE87-47FE-A2CA-00EC28725F68}; SV1; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3A584A4D-518C-4D0E-BC6B-541B7D69A3FE})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3CB6D22A-827A-4D5B-95D1-C25042B282C6}; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3D309697-A650-4F70-9E8B-3E5BBD8136D4}; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3F766A6E-FF5A-419A-8E0D-B410CC976848}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {3FD99CE8-4876-42EB-A98E-C3240840E16F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 3M/MSIE 5.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 3M/MSIE 5.5; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {40BEA18B-3AD4-4A88-87CB-9F3E34B672C5})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {41D06DE4-3B47-4AFE-8586-A2A0BC21128B}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {42662884-5207-488E-88DD-22D1EE5876E4})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {438A4A73-BC8A-4815-81F7-E684646FE3BB}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {4489F513-F2F4-428D-862D-E328E98846C1})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {474A61B2-06FD-4AC4-BD58-15A5EE8D135A}; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {48B30A43-F85C-421C-B89F-5D8DCE6F0C33})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {48BC54DC-03AC-43C8-98C3-6C74FAFA4CBF})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {4907EF1F-C744-4C7A-BD93-DB6598A4124F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {4910F99D-049A-4B1E-AA4C-6254837DE90E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {497D41FB-CBB2-4214-A8FA-2C8339E15215}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {4D0F642B-7758-4DD7-806D-22F5C327491B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {4DAD8D3C-DBF0-48FF-81D9-D8B6056B250A}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {4F0AA017-AB3E-4B63-94AC-3554E6E79E2B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {505431EF-B36F-4113-AD87-A9F319C9A9A7})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {505F1043-8A30-492E-A1F4-6D76A19DAFDC}; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {51B5AE33-C14D-49E0-B977-C367563556E8})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {52370F31-7911-CA01-5788-3A30A77F2822})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {53810FCF-D003-454B-BE56-53B2FCF44FD9}; www.kpas.net; IBP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {55173041-4495-432A-B14A-DC8C4904669C}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {55173041-4495-432A-B14A-DC8C4904669C}; .NET CLR 1.0.3705; .NET CLR 1.1.4322; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {5677AA33-67A1-4270-B68D-B5D5A4E95FA0}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {56B378DE-DAA6-4681-9973-9BEF2D4DDC6F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {56CD5059-BD0C-4315-9677-6D1C92EAF5A8}; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {56FA8E7E-12AB-4911-A191-21C37C311D65}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {581A1CD1-357D-4B8D-8953-C522246CC007}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {581CB45E-7FDC-4B9A-B71C-28266E860749})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {59632201-F778-4CBA-B1F4-C4CCD491D964}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {5B643202-DEAC-4D35-BC57-FE4279576E94})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {5C2F722D-C130-4AD3-8A07-5D3C659A6926}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {5C405188-4130-4F5D-801B-92844913257D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {5CD38EE8-DD84-47A1-9FD8-61C91D812942}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {5D6BCA52-DC20-46F7-B828-2B34BB4618F9}; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {5DF11A3C-26FC-451E-9C44-151B22E63F64}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 601-24)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6240A551-23EB-402C-8A79-008063B05AC2}; Alexa Toolbar; Feat Ext 18)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {625B82F8-3C54-4C68-B502-9EDAD5E5A2B0}; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {654B0711-4A85-42E7-983F-7C17305D0E48}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {66830790-BB7A-4162-B58C-8A914A9DFF5C}; SV1; 1.57.1 ; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {671249BD-E4C8-4962-8F4C-B5116D567611}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {67198D79-41B9-4775-88C5-FF11BF28DF6E}; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {676CA98F-335D-4002-AE68-06EC0FCD863E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {68070A19-8A16-4631-9EC8-4A06D22F83A6}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6A5F8282-BD7B-4C03-AA47-D5EA5EE6CC2C})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6A7ABDFC-3C88-42D6-8E5C-464935051D13})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6B03FCEC-E168-4CD2-946B-4E7C3171D66C})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6BC3FAAA-4F70-42A4-A3D9-5D6E7D38B6E6}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6BD7D868-97D7-4021-A0D1-AFAFDE7AED4A}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6BE32F1D-C93D-4A7A-AB49-C6C28663C805}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6C4A00C9-0682-4A2B-A5C5-7C066461D41A})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6C54EE4C-5F00-4EEB-AABA-A35C734E2654})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6D2550C2-E7EC-4A02-84F9-AE5DA7671170}; SV1; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6D733935-1BA5-402C-81CD-EFFD0A66928B}; SV1; OptusNetDSL6; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {6FC0CBD9-8501-A7A3-BC23-9E828B1739DD})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7029D658-033C-4F21-9334-3028D54A9C46}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {70A105A4-3B56-40B8-ACB3-0B9567712A0C}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7166AA8D-9F2D-45AF-BC84-3A13C84AB68C}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {716A884C-2833-41B9-B4A2-7CFF5CC19774}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {725986B4-361D-4262-888A-1DEF1D40A677}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7275A900-6883-4F2C-9D7B-9D7E6F1B1CAD}; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {73031379-6EF6-48A2-8182-5E04CA2B100D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {73CA2DB1-3D3A-4AA3-BE60-1AB52BBA5DC7})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {73FC897C-EB65-481A-9DFE-D5E6BA3549EF}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {746BDD15-B60E-45F9-8D9B-0DDBC59E6A16}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7564D434-679A-406F-BB78-7277EA46547A}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7609500E-F1F7-4395-AD02-DA8F288385DB}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {76558216-F653-405A-BD95-00857C519BFB})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {76CBD2B2-30E1-4D85-BD1B-D854AEB6FC5B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {76D1A158-5E58-4876-B3B5-09A18AF2D3AB}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {773D9899-3378-495E-AC5D-D9489250EB13})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {776316A7-FEC1-44A8-9DB5-8469FF21105D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {77820B37-7295-47CD-8842-0AA10651F383}; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {79D3BB58-8001-4C11-BB86-ADE061CEAF25})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7A834B30-AA9D-4D2B-AC38-919CE48D56E2})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7AAD7328-EFD7-4E69-8B69-7E9E6D5F4B2F}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7DABAE32-5850-47DE-A886-7BF64850D96D}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7DCFFE58-FF03-4A2A-B3E6-8149BB0EF19F}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7F82049C-378B-4A5A-98D6-E1D43E43CFA0})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {7FB10817-27B8-4D7C-86DD-C61DFD37585B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {80351674-652B-4DDA-8432-41F8E61AB1E7})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {82EFCD46-30E8-45E3-99B6-AD90BEBDAD6B}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {835E8FC0-7916-4D1F-AA80-DD7F553053C6}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {8421A6E1-44C8-4B7D-A950-5EDE1F3181F0}; SV1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {85192DB1-086A-4E53-A59F-BDB83377709A}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {858921CC-D456-4230-95D4-B968432409B3})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {8590B1C5-F4E9-41B0-A990-A8C325015392}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {8621CC8A-4F10-45B1-9C16-A289C29FB98E}; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {865C266F-BCAE-421B-BF88-F1B120A4F943}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {88516849-FDAF-4A0A-956F-FA2CF2F6D7F9}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {888CC72D-0C51-4514-9AA7-507E9D2D6A9E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {89E40FF4-BD77-4586-B092-EB6957FFEEC0}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {8F1D0313-7282-4B1C-B38B-E33B59B2B5B8}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {8F8DADE0-9F1C-406B-8D45-A3686358668D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {906090F7-10E4-4B25-B2D9-D258E722AFC4}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {913B3453-254F-4FC2-AB37-B3CB009590D0}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9520EB69-95A9-4B9E-B576-F9453174C6F8}; ESB{C8AD18A8-BC88-40E8-97D9-31784C41F582}; ESB{50D170B2-6884-4234-96B4-22273E912859})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {965166C4-481A-4D30-8597-0A4319911257}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 97828)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {97D5F745-44A2-4093-B7E1-E8235862D1CA}; SV1; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {996DA28F-748C-4439-ABC3-4546531ED0FC})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9AA7FFB2-7E7D-4B92-86AE-835F7B135CB9}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9AFC0F21-2679-4207-98D7-E2DB9CDC0E89})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9B8F54EC-CC98-489C-9050-D61EF01E6D45})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9C3408B0-029E-479E-93AD-AA8492C083CE})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9CD98633-D53A-4916-B25D-BBF0EC6299A5}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9CD98633-D53A-4916-B25D-BBF0EC6299A5}; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9CE63974-BFE2-4797-BEB8-B8C133A401B9}; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9E70E38E-EEFE-48E4-9B4C-BF0FEE5E94CD}; .NET CLR 1.0.3705; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {9FE37218-F0B4-43AA-8528-2B052E647F3C}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A159BA28-48C0-4189-BEE6-D59494BCDD76})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A27C75DF-D29F-4B21-834D-66C1B23297E5})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A2841CE9-E06C-4BB2-AF6B-14C4EAA0F0CF}; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A333877C-5AE7-4532-969B-A6004713EF80}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A4E5458B-4CE1-4552-9D0E-8C01D102C7FA}; FunWebProducts; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A5891798-8194-4EC2-BB31-8C33151147C0}; ESB{9E677553-0D9B-4A40-B6E7-8AD691A3065F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A61CE854-3B32-4B71-B3BD-60DCE467E30E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A88CFFCD-C389-47D6-8AEC-52C1DB0371C4})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A97D2399-C6DD-47F7-A9E3-4C2842744510}; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {A9D3BF59-505F-4316-AA7F-ABC49BF4B03E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AAPT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AAPT; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AAPT; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {ABC49948-9942-404D-B4FE-574FCA90475D}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ACSWorld; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; actually Firefox - assholes, support Mozilla/5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ADP Plaza - Build 64; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {AE17F330-EBBA-4B78-B5DF-3288211BACB4})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {AE480139-C1AA-4168-9BA2-24E090FBB8C7}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WILDdesigns; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF; Q312461; SV1; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AIRF; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AKH Wien; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Al Asad/Hunter Site, LSA Anaconda; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Alexa Toolbar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Alexa Toolbar; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Alexa Toolbar; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Alisys_ONO; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ALPHA/06)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ALPHA; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; anna mielec tani seks dziwka; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ANONYMOUS; Huntingtower [INTRANET ONLY]; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AOL7; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APCMAG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APCMAG; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APCMAG; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APCMAG; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APCMAG; OptusIE501-018; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APCMAG; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APCMAG; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APC; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; APU-XP; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Arcor 2.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Arcor 2.0; SV1; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Arcor Online 3.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 2.11; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00; .NET CLR 1.1.4322; Fluffi Bot+)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00; SV1; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskBar 3.00; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskJPBar 3.00; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AskJPBar 3.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHome021SI; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHome021SI; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHome033)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHome033; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHome033; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHome033; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHome033; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AtHomeEN191)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ATOM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; AT&T CSM 6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; AT&T CSM 6.0; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; AT&T CSM 6.0; YComp 5.0.2.6; FunWebProducts; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; AT&T CSM 6; SV1; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; AT&T CSM 6; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; AT&T CSM8.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc11; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; Q312461; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; Q312461; SV1; .NET CLR 1.1.4322; MSN 9.0; MSNbQ001; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; Roadrunner; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM6.0; YComp 5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM 6; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM 6; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; FunWebProducts; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; .NET CLR 1.1.4322; Feat Ext 13)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM7.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM8.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T CSM8.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T WNS5.2; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; AT&T WNS5.2; Q312461; AT&T CSM6.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; austarnet_2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; Alexa Toolbar)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; FunWebProducts-MyWay)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; MyIE2; Feedreader; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; MyIE2; SV1; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; .NET CLR 1.1.4322)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; SV1)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser [avantbrowser.com]; SV1; .NET CLR 1.0.3705)" + family: "Avant" + major: '1' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Awe¤6 - Adonay Web Explorer; Mozilla/4.0 (compatible; Awe¤6 - Adonay Web Explorer); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {B0832C32-9DEE-429D-9138-56DD764E4C9E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {B2570479-25DA-7559-C478-C0A0855A6BD5}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {B3215A47-A5E1-4B6A-9BB4-3DF0A424B6A1}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {B473E576-6FFF-4F71-9FE5-29224CE32692})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {B8106019-1D23-4C8E-808C-AE28616B449A}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {B9554770-CEA1-4514-BC49-A30D9169404D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {B98C23CE-0A06-492A-A248-BF4336DE4EDD})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BB B500 U2.02; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {BBD40907-B7C9-4947-9B8F-A62A288A98F9}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BB-INTRA-MAI2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BBT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; MathPlayer 2.0; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; Q312461; SV1; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; SV1; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; SV1; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCD2000; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BCIE6SP1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {BD0F71D8-0AC0-49F7-BD87-81F5C24E60E3})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {BF2D4BA4-80A1-46E5-AC3F-B62AED59596C}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {BF8B323E-06A3-459F-BAB5-ABE8401D417A}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; bgft)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BIGPOND_ADSL_42; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BIGPOND_ADSL_42; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BizLink; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; bmi ecommerce; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; bpc; SV1; (R1 1.3); (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BP E1.06; SV1; Smart Explorer 6.1; 1.41.1 ; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BPH32_56; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BRA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Brew_Browser_6.0_SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; brip1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; brip1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; brip1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; brip1; SV1; Sidewinder 1.0; formsPlayer 2.0; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .: BritishHeaven.de :.; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT [build 60A]; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Business Broadband; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTinternet V8.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTinternet V8.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTinternet V8.4; YComp 5.0.2.6; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTinternet V8.4; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTopenworld; AIRF; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTopenworld; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld BB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld BB; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld BB; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld BB; SV1; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld BB; YPC 3.0.0; yplus 4.3.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld BB; YPC 3.0.2; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld Broadband)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld Broadband; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld Broadband; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BT Openworld Broadband; YPC 3.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTopenworld; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTopenworld; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTopenworld; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTopenworld; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTopenworld; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTOW)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTOW; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTOW V9.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTOW V9.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BTT V3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; BWCH30; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C122D12A-1212-49C3-89B0-CD9F3ED9F7BD}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C1B43645-698E-4524-9042-76FC08FDE51A})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C2EED8D4-0E69-4BC2-8F34-3B246690F6DE}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C389C776-89D8-4251-A003-AC55DE5E6821}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C429A6DA-4192-4DD9-85EA-B5EC7CB4DA25}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C5D1D9A9-F1A0-4C62-8162-8BA0DD8C3BA4})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C67ED323-27F6-4127-B7F2-56691D7AC32F})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {C713E123-6F1C-41FC-84B3-880D9608E8D7}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {Cablevision Optimum Online}; (R1 1.3); Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CASPERXP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CASPERXP; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CASPERXP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {CD23D801-AD49-4451-BCEE-0E1BBFC3E71A})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=ALLIED_01_01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=ALLIED_01_01; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=ALLIED_01_01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=ALLIED_01_01; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=BP1b.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=BP1b.00; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=BP1b.00; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=storecd_01_03; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v11c.01; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v12a.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v13b.06; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDsource=v2.15e.03)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v3.12a.00; SV1; YPC 3.0.2; yplus 4.3.02b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v9e.01; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v9e.03; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v9e.05)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v9e.05; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v9e.05; NN5.0.2.12; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v9e.05; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=v9e.07)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CDSource=vBB1c.00; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {CE4189CF-B7E9-4F85-B301-6CC3C11A0196}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {CEDA55FF-C15E-4879-88A3-A83B90CAFEC5}; MCI Windows Corporate Image; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; :certegy Corporate; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Charlestown; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Charter B1; FunWebProducts; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Charter B1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Charter B1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CHWIE_NL70; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CHWIE_NO60; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CHWIE_NO70; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CHWIE_SE70; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CITGO09302002; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Cng)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CNnet Internet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; COE June 03, 2002; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; COE June 03, 2002; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; College of Business Administration Lab; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; COM+ 1.0.2204)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; compaq; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; compaq; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; compaq; YPC 3.0.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Compatible; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; @; Compatible; Version; Platform)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Compatible; Version; Platform)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Connect 1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Consorzio Operativo Gruppo MPS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; consumer; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Corporate Image; MCI Windows Corporate Image; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Cox High Speed Internet Customer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Cox High Speed Internet Customer; Hotbar 4.2.8.0; Hotbar 4.3.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Cox High Speed Internet Customer; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Cox High Speed Internet Customer; Q312461; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Cox High Speed Internet Customer; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CP; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CP; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CPT-IE401SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CPT-IE401SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CPT-IE401SP1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CPWR)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CPWR; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; ESB{AE9445A2-0ED0-4AC0-BDE4-3EA933008624}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; Hotbar 4.4.5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; Q342532)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Creative; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Crick Enhanced; Q312461; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {CSC})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {CSC}; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CSIE60SP01; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CS.v0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CursorZone 1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CustomExchangeBrowser; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Customized by Computer West; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CVnet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; CWCRDAY; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D009E04F-7285-4277-BAF6-77797A8417CF})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D03E5946-02C5-4FFB-BDF7-A2D658A27777})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D15E0797-FD3B-413C-B67B-63D937268BE0}; Feat Ext 21)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D1F76FF8-EE02-4E7F-BB77-5D6682CC4F46}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D2C0EFBA-26D7-48B4-8500-1F2483B6044C}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D379CF0A-4B77-463F-B99C-6E854BEACF65}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D546DB1D-E98F-468A-8876-49573C986A27}; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {D72714F6-A809-4DE6-B422-2B2ADCEBF152}; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DAgroupPLC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DATASIEL; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {DB056177-05D3-45EF-A868-F029A67735C0}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {DBF8B407-FE31-4D86-8C6E-2F831D79AB5B}; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {DC6A17BE-3A95-4B92-8292-A8EE80FB04CB})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {DCAEF9CE-8251-422E-ADD0-AD2B56DEFED3})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dcdev001; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DCSI; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {DD7B8EB4-6D8A-46BB-B262-45CEC0C799E8})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DDnDD; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Deepnet Explorer 1.3.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Deepnet Explorer 1.3.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Deepnet Explorer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Deepnet Explorer; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Deepnet Explorer; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Deepnet Explorer; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DesignLinks; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {DFD18BB5-E42B-42DE-9F12-A936648D0AF1})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DFO-MPO Internet Explorer 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DGD (AutoProxy4); .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; -D-H1-MS318089; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; -D-H1-MS318089; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DI60SP1001; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dial)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Dialer/1.10/ADSL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Dialer/1.10/ADSL; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Dialer/2.08/Frisurf; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dial; NetCaptor 7.0 Beta 2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dial; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dial; SV1; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dial; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dial; SV1; www.ASPSimply.com; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; AAPT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; Assistant 1.0.2.4; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; digit_may2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; FunWebProducts; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; KITV4.7 Wanadoo)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; NN4.2.0.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; OptusNetCable-02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; OptusNetDSL6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; Q312461; iOpus-I-M; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; Q312461; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; Rogers Hi-Speed Internet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; SV1; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; VNIE60; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; VNIE MESH_PC; YPC 3.0.2; yplus 4.4.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DigExt; YPC 3.0.2; yplus 4.3.02b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; digit_may2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; digit_may2002; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; digit_may2002; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Distance Learning, Inc.)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; D-M1-MSSP1; D-M1-200309AC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dna Internet; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DOJ3jx7bf; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DOJ3jx7bf; .NET CLR 2.0.40607; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DownloadSpeed; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DP1000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; dpx; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; drebaIE-ZE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DrKW; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DRS_E)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DRS_E; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DRS;Techcom Software Solutions Inc.;KDDS1277;IE6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; d:tnt7_ForumBrowser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; d:tnt7_ForumBrowser; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DVD Owner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; DVD Owner; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E2B5FAFC-1899-497E-BACC-EEEA7F24A5D2}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E2E07F6D-A6E7-1684-82DA-8DE003B9C217})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E422A9F3-43BA-41E7-AF5D-838A15EBE348}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E4BBB50E-5B1B-4D8C-A819-AD524233897E}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E5E08788-0480-4269-BC71-A7797C5D3C62}; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E69CE46B-FC60-6F41-B5CD-7789712032EA}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E85C6A09-3F78-4078-B300-293C2CD8FD03})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {E875708F-E195-B824-10FE-6BB954D80082})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {EA1C7663-ACC4-45B1-8A90-221B12478AF0})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {ED79526B-0CE1-4925-AAFF-F8C063DE0161})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {EE8C6E6D-7C14-493D-96D8-96189CDB443C})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {EEF090D2-AD10-4793-AA02-7C5F2B8F099F}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {EFACCBB9-0BDC-4B3A-A7B9-051398D9E119})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; eircom/june2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; EJGVNET; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; EK60SP1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; EMC IS 55; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Emiliano ti vede ....)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) [en]" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ENGINE; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; EROLS040199)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{02508E72-8688-4F8C-BF9C-73C3D029563C}; SV1; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{101D66DC-5446-428D-A6EA-ED273C9FC84B}; Hotbar 4.4.7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{10ED3712-AD0D-4BB1-8D3C-0B0E15A671C4}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{1234D1DF-0277-4F9A-A0EB-0FAF5D432EE2}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{133E6249-80BF-4741-9A39-10C8D7C998AC}; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{136B3929-78D3-4728-A726-73ECC4B983CF})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{180F232C-E374-4B08-A664-FA09F726DBE4})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{1C38363F-253A-4424-B102-4495048AF33E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{28878E88-F98C-4A17-878A-E36A996D5072}; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{2F39423D-9DBB-48B9-B343-20ACBF9CFDC2}; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{30E3976E-D14C-4C93-B9B7-9AFECD8F306F}; MyIE2; Maxthon)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{31889988-FC07-40BA-7F3E-AEBEA15391D6}; ESB{E2E93F3B-0BE5-472F-2ABB-1C9AEFB49813}; ESB{CC56F89D-FD35-4E39-6074-F0B433D7D482}; ESB{225AAA31-E92C-4034-89D0-14B9F20BE982}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{34824601-AC35-488E-B249-BCD4AAF8A1C6})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{35404506-8A98-49E1-9E17-D61E2C1BAC18})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{3D72EE78-2FEB-4C75-B8DC-3BF40C60D3C5})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{45F63CFC-FA29-4C6E-A6D6-B947491001C8}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{472D70C9-7893-4D2B-B119-BB44221294EC}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{4779B872-DBEE-40A8-8442-E0FF5DA484D7}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{484F9004-564C-4B12-AC4E-1418ECDE928A}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{4B268CB2-51FA-4C84-B624-6DE3F0D887DA}; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{4D3EA7A9-3801-4A63-91E9-5CCC71E6868C}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{4E071CF0-5E40-4332-8E3D-AF6371997B08}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{58553345-1609-429A-8ED6-D9F1B9A77DC2}; ESB{65E1A955-DCEC-465A-821C-54F40FF8B34A}; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{5D811861-EA95-45EE-B290-38265CDC5E35}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{62965017-4DF0-4965-87E8-BA0D8449C3DE})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{688258C8-E4A8-482F-9667-C29B4CABFA9A}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{68DE235B-522D-4012-A9D9-E5F196997BC0}; ESB{D7EC4F6C-EFE4-4DBB-A0BD-FFCA2CEF6E60})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{6AF1F99B-2A01-4167-B3EE-BC497D63F9D4}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{6EFB5336-7A45-448B-843F-9AC66EF6FBD1})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{73AE67D7-E15F-4325-B51F-124AB9646A23}; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{75618962-1051-4901-83E3-FA45F0DE1ADD})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{75E350B6-0105-4218-971A-A1CB090DC683}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{77A48D0F-61AF-44B4-BEFD-42E758642C6D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{7D07736D-DE37-4F7F-AC8E-C68237EBF022}; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{7F8B060C-274D-4956-B4B4-46DEFBCBF28A}; ESB{4B5E3CE7-C53E-4C53-A2EE-6D064498DF1F}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{82EA8C84-7DC3-489C-B779-A3469BE4708E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{83E1DA4B-9DEF-4AFB-883B-D347E5A6107D}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{87F2D8B2-4248-4885-A012-C7B7FA26F488})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{8C127829-44A0-4BB8-9D28-E81994F66EE0}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{8C9138AB-F2ED-4BB7-A14E-2A3D3D977E0B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{91E7C142-4F0C-49FA-81C3-1E8A6C52A2F3}; ESB{C50C0A96-9BEB-46E8-B245-4EC5EC3830E5}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{9981848E-AAB6-4A05-B8A4-3A0A5F328952}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{9B524756-DEC6-4F01-8E9F-5922E7097A74}; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{9C041F81-CD5B-4241-9C74-CD4FE075546E}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{A1F633C5-98D0-4F80-A38A-7A216501394C}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{A5C6ECFC-8673-444F-B7E7-DE0C5B59D622}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{ABA66D21-29BE-4BAF-BAD4-ED6812C1E033}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{ADA09EE9-2082-4E60-A551-973A98214068})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{B485C8BD-00D2-42A3-A424-90D47ECB16EA}; ESB{51D3AFB9-B34E-42EB-8AD7-D60D7CEF84E2}; ESB{B901E2E3-3130-4FD3-A611-F671E4D7D235}; ESB{F8ED9EF0-B332-437D-AF6F-E4D7929AAE51}; ESB{145C6EA3-68A6-4840-8583-FDE74" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{BC8D007D-0F64-48DF-9841-D9A5F8184B58}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{C48545AB-77DE-4E4E-AC5B-183794002D5B})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{C809320D-9E35-41B8-B589-1857D6C6B121}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{C9452703-6C32-4564-9A1C-E11A31A69CD4}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{CD23C4DA-697C-4A7E-B50B-884DD2A1A8E2}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{D65EE013-85EB-431B-A47F-633C4457E9BE})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{D6E592CA-A859-4145-A375-64AC4DFC291D}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{D8F6BF12-200C-466E-85E5-06BBD005995E}; YPC 3.0.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{E3E1E7D6-9A2C-4F39-843E-362AB50F6088}; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{E63A7B5D-0538-4B3D-BBAB-915D834B1FE3})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{E6DD635D-0921-4491-B013-17AF67B2E602}; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{EA155034-249E-47E4-988B-5576EA36F928}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{EA67BD1B-D57E-4131-BCEC-E5C35BD6A0CE}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{F0F896A7-E6EA-4914-B1DE-C16BBB4A67E1})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{F40811EE-DF17-4BC9-8785-B362ABF34098}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{F7A8BDDE-BB37-40C8-AA1D-4B57BD78EFBA}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{FE364DB1-9712-443D-8511-83A85984644A}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ESB{FF0BE471-F8FA-4219-8FFC-07515C5FCB9C}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Eurobell Internet; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; exNetPanel:1059240)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F1ECC819-455A-46BC-A405-EFB52BF85707}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F2024F27-DA75-4D6A-B590-2AD23305F9F7}; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F27B2FF4-5121-47B1-8A63-CE5BD1021640})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F29D822D-EED0-4E29-8B61-8B038CEC1C0A}; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F35D706E-FD32-451F-9A2F-DFD96F9F0DA6})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F3A9F2D1-57F6-4A32-8E00-5AA391FC89A2})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F467C9A2-D4AF-4B0F-890E-8F8923BAE9C2}; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F4E70CE0-6237-4227-906E-788A750F9FB4}; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; F-6.0SP1-20030218)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; F-6.0SP1-20030218; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F70A8590-C5BA-483C-BE5F-8589C20E9B38})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F7BF8B53-70AB-4EA6-915C-C70769C62210})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F8498490-1D66-4D29-9FCC-BB35327A6257}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {F8FE05B9-FCEF-4302-AC51-C4B61FFBF4B9})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FA63D7BD-846C-43EE-9287-0FB9150B1111}; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FB15F932-A469-4646-BCB4-8EB15AECFF9F}; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FC1AC744-B5CC-4237-96AA-E63B9FE6FE44})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FD749AFA-79D4-49DF-9348-6228D25835C8})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FDM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FE8FFD49-3EE4-412F-B700-175757E8EA1B}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Feat Ext 20)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Feat Ext 21)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FEB_2004-TPG; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Feedreader)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Feedreader; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Feedreader; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FF25C218-3C07-491B-BFCA-D6C5557A414F}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FF360BD3-4648-4D2D-94C7-F95404BDC9BB})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FF8CB3A2-81BE-4550-B98C-CC9DFAF7A452}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FF8CB3A2-81BE-4550-B98C-CC9DFAF7A452}; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {FFBF6A73-2389-4D4F-A470-862760ED16CD}; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FGL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FIDUCIA IT AG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FIPID-{6/j.Ss94W0oM{6KchRpCsLmMQ222656249)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; fisg IE 6.0 SP1 (FID r2.0); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FMRCo cfg. 6.01.3.1b1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FMRCo cfg. 6.01.3.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FORSCOM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Free Download Manager)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; FunWebProducts) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; SV1),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FREE; Wanadoo 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FreeWeb Explorer 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FS_COMPAQ_IE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; fs_ie5_04_2000_preload)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; fuck you; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; AskBar 3.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; BCD2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; dial; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; ESB{27845BE7-0EC6-473C-8064-3C4A063AB585}; ESB{5CEF3C99-0C80-47FB-B591-9EA0568D728D})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; FIPID-{8ORj5ZKEvfbg{8r02nwzw7eKE181427001)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; FunWebProducts-MyWay; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; FunWebProducts-MyWay; Wanadoo 6.1; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Grip Toolbar 2.07)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.3.5.0; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.1.0; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.2.0; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.5.0; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.5.0; MSN 8.0; MSN 8.5; MSNbBBYZ; MSNmen-us; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.5.0; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.7.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.4.9.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.5.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.5.1.0; MSN 6.1; MSNbMSFT; MSNmen-nz; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.5.1.0; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar4.5.2.0; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar4.5.3.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar4.5.3.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; HTMLAB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; IBP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; iebar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; iebar; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; KKman2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Maxthon; FREE)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MSN 6.1; MSNbMSFT; MSNmsv-se; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MSN 8.0; MSN 8.5; MSNbVZ02; MSNmen-us; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyTotalSearch)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyTotalSearch; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyTotalSearch; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; ESB{285EDB64-F0D5-40CE-9E80-0424E454F7A4}; ESB{82D87D6A-A9EA-4A92-A8E0-46F5501A1E54}; ESB{53A21F9E-0210-412D-A05D-A8145EBD094A}; ESB{B709ECE9-AE61-48D0-8788-FBBAD5FECB3E}; ESB{829700D" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; Grip Toolbar 2.07a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; JyxoToolbar1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; NetCaptor 6.5.0B6; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; .NET CLR 1.0.3705; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; OptusNetDSL6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts-MyWay; SV1; www.kpas.net; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; OptusNetCable-02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; OptusNetDSL6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; OZHARLIT5.5_1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; PP; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Preload_01_07; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Primus-AOL; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SIK30)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; AAPT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; ESB{793F2EFD-3EE8-4B36-AB38-1853C6EC257E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; Hotbar4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; Maxthon; MediaPilot; MediaPilotAd; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; Maxthon; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; MSN 6.1; MSNbDELL; MSNmen-us; MSNc22; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; snprtz|T04114572010350)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; son-OEM-1101; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; SV1; YPC 3.2.0; .NET CLR 1.1.4322; PeoplePal 3.0; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts; YPC 3.0.1; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FVSD#52)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; [Gecko])" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; generic_01_01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; generic_01_01; FunWebProducts; (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; generic_01_01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; generic_01_01; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GIS IE5.5 SP1 4-20-2001 DMG Build)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GIS IE6.0 Build 20030604; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GIS IE6.0 Build 20031007; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GIS IE6.0 Build 20031008; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GIS IE6.0 Build 20031008; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GIS IE6.0 Build 20031111; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GIS IE 6.0 Build 20040714; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Global Visioneers, LLC - www.GlobalVisioneers.com -; Globcal Visioneers, LLC - www.GlobalVisioneers.com -)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GMX AG by USt; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; GoldenWeb.it)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Googlebot)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Googlebot/2.1 (+http://www.googlebot.com/bot.html))" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Googlebot/2.1 (+http://www.googlebot.com/bot.html); Maxthon; FDM)" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Google-TR-1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; H010818)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; H010818; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; H010818; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; H010818; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; H010818; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HCI0430; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HCI0441; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Headline-Reader; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Het Net 3.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hewlett-Packard; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hewlett-Packard; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HinBox 0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HJS.NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; hlink5.5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.7.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.8.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.8.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.8.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.8.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.8.0; SV1; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.1.8.0; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.10.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.11.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.1.1281; MSN 6.1; MSNbMSFT; MSNmfr-fr; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.1.1367; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.1.1367; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.13.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.13.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.14.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.14.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.8.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.2.8.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.3.1.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.3.2.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.3.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.3.5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.3.5.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.1.1394)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.1.1394; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.1.1406; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar4.4.1.1415)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar4.4.1.1415; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; FunWebProducts; MSN 6.1; MSNbDELL; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.2.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0; FunWebProducts-MyWay; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.5.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.6.0),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.6.0; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.6.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.6.0; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.6.0; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.7.0; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.7.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.8.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.4.9.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.0.0; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.0.0; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.0.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.1.0; .NET CLR 1.1.4322; FDM; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.1.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.5.1.0; SV1; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar4.5.3.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar4.5.3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar4.5.3.0; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hotbar Unknown; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Hot Lingo 2.0; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HPC Factor; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HTMLAB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HTMLAB; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; hubbabubba)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; HW-IE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IBP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IBP; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IBP; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IBP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Ibrowse/3.2(Ibrowse3.2;AmigaOS4.0); SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Icewtr Network services (jen); SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ICLP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ICM60)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ICM60; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ICSLabs - USC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ICT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ICT; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IDG.pl)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE5.x/Winxx/EZN/xx; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.05; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE60BRMM by STASM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.0 (FID r1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.0 SP1 (FID r2.0))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.0 SP1 (FID r2.0); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.0 SP1 (FID r3.0); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.0 SP1 (FID r3.0); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.0 SP1 (FID r3.0); (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE 6.0 SP1 Unrestricted; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE6CFG32a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE6CFG32a; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE6SP1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; DP Oslo; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-in; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iebar; SV1; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IE; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IESYM6; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IgwanaBrowser; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; Feedreader; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; Feedreader; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; .NET CLR 1.1.4322; FB-Solutions)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IncoNet Starter Kit ver 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; INFINOLOGY CORP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; INFOAVE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; INFOAVE5; Q312461; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; INFOAVE5; Q312461; SV1; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Infowalker v1.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Infowalker v1.01; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; INTDUN; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; brip1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; Free Download Manager)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; Maxthon; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; MyIE2; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; IBP; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; MathPlayer 2.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; MyIE2; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iOpus-I-M; SV1; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iP-BLD03-PRE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iP-BLD03-PRE; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iP-BLD03; SV1; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iP-CMPQ-2003; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iP-CMPQ-HDD; FunWebProducts; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iP-CMPQ-HDD; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ip_internal_request; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iPrimus)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iRider 2.07.0018; SV1; Feedreader; .NET CLR 1.1.4322)" + family: "iRider" + major: '2' + minor: '07' + patch: '0018' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; isp1057; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; istb 702)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; istb 702; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ITS-Ver1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IWSS:MSC01048/00096b3da0d3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IWSS:SPH-XP-SACH02/0008a1091f37; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; IWSS:WXP4390/00904b631249; IWSS:WXP4390/000d567960f4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JackGTestLocalMachineValue; someFunkyString; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Others)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JAS; SV1; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JLC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JMV)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JMV; SV1; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1);JTB:15:817d2be2-fc1c-4568-8f4e-cc5f9a982e3b" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Juni)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JUNO; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JyxoToolbar1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JyxoToolbar1.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JyxoToolbar1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; JyxoToolbar1.0; SV1; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Katiesoft 7; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KITXP40NL; MSN 6.1; MSNbMSFT; MSNmnl-nl; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KKman2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KKman2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KKman3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Kmart; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Kmart; Q312461; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KPMG; InstantAlbert; XBOXToolbar; CustomToobar.com; Eduardo A. Morcillo; Custom Browser Inc.; SavantMedia; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KPMG; InstantAlbert; XBOXToolbar; CustomToobar.com; Eduardo A. Morcillo; Custom Browser Inc.; SavantMedia; SinglesToolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KPSWorkstation; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; LDS Church)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; LIB Staff; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Link Checker Pro 3.1.72, http://www.Link-Checker-Pro.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; LN; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; LTH Browser 3.02a; FDM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Lunascape 1.3.1)" + family: "Lunascape" + major: '1' + minor: '3' + patch: '1' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; luv u; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; lvw)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; LW0815)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Lycos-Online; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MADE BY WEBO; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MassCops Browser; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MathPlayer 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MathPlayer 2.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MathPlayer 2.0; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MathPlayer 2.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MathPlayer 2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MathPlayer 2.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MathPlayer 2.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Matrix Y2K - Preview Browser; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; Alexa Toolbar)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; FDM)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; iRider 2.20.0002)" + family: "iRider" + major: '2' + minor: '20' + patch: '0002' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; MyIE2; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; MyIE2; SV1)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; MyIE2; SV1; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; (R1 1.5))" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; SailBrowser 2005; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; Stardock Blog Navigator 1.0; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; SV1)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; SV1; Alexa Toolbar)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; SV1; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; SV1; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon; SV1; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; McInternetBrasil_MCAAE_3112; NusaQuiosque; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MCI Windows Corporate Image; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MCI Windows Corporate Image; QS 4.1.1.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MCI Windows Corporate Image; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MCI Windows XP Corporate Image; MCI Windows Corporate Image; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MediaPilot; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Megara Web; IE 6.05; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mercer Human Resource Consulting; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Metro C&C, Croatia)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MidBC001; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Miele & Cie. Explorer Version 6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MiniJv2 3.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; mip.sdu.dk)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mon_AutoConfig_v1.02_STL; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mountainside; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .Mozilla)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Menara); SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (Compatible; MSIE 6.0; Windows 2000; MCK); Mozilla/4.0 (Compatible; MSIE 6.0; Win; MCK); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0; -D-H1-MS318089))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; HDR.05.01.00.06; .NET CLR 1.0.3705; .NET CLR 1.1.4322); .NET CLR 1.1.4322); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible,MSIE 6.0; Windows NT; Brite Way Publishing; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0(compatible; MSIE 6; Win32; Mck))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0(compatible; MSIE 6; Win32; Mck); Mozilla/4.0 (Compatible; MSIE 6.0; Win; MCK))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Mozilla/4.0 (zgodny z ISO 900087635.5); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MPD JV v1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MRA 2.5 (build 00387))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MRA 3.0 (build 00614))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MRA 4.0 (build 00768))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MS Custom IE; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSIE6XPV1; KB824145; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; msie6xpv1; LM_POSTPLATFORM; MSIE6ENV6; MS04-004; CU_POSTPLATFORM; .NET CLR 1.0.3705; .NET CLR 1.1.4322; LM_50_POSTPLATFORM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; msie6xpv1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; msie6xpv1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmbr-br; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-sg; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc21)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmit-it; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 6.1; MSNbMSFT; MSNmtc-tw; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 8.0; MSN 8.5; MSNbBBYZ; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 8.0; MSN 8.5; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-gb; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 9.0; MSNbBBYZ; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 9.0; MSNbDELL; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSN 9.0; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; AtHome0200; T312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; AtHome021SI; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; AtHomeEN191; Hotbar 4.3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; AtHomeEN191; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; Q312461; Hotbar 4.0; SEARCHALOT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MSOCD; T312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MTI; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MTI; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Multikabel)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyHealthyVet; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2 0.3)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Alexa Toolbar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Deepnet Explorer; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; ESB{9D28903E-AE01-4815-A52A-AE2885F86845}; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; ESB{E225A099-D057-4FEF-BAC6-3BEC123804CC}; NN5.0.2.23)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Feedreader)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Feedreader; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; FunWebProducts)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Hotbar 4.5.0.0; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; i-NavFourF; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; iOpus-I-M; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; iRider 2.10.0008)" + family: "iRider" + major: '2' + minor: '10' + patch: '0008' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; JyxoToolbar1.0; iolbar-3.0.0.XXXX; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Matrix Y2K - Preview Browser; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; AIRF; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; iOpus-I-M; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; .NET CLR 1.1.4322; FDM)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; SV1)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; SV1; Deepnet Explorer; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; SV1; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; Maxthon; SV1; .NET CLR 1.1.4322; Tablet PC 1.7; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; NetCaptor 7.0.1)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; NetCaptor 7.5.3; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.0.2914; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; (R1 1.1); FDM)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; (R1 1.1); .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; (R1 1.3))" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; (R1 1.5))" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; (R1 1.5); .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; Alexa Toolbar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; CustomToolbar.com; Maxthon)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; Mailinfo [102065]; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; Maxthon)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; Maxthon; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; .NET CLR 1.1.4322; FDM)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; TheFreeDictionary.com)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Nahrain)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NARA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NaturaMediterraneoEEmare; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Neostrada Plus 5.6; FIPID-{2N8gA8m2Ta32{2nYX0EkruYpg585052490; i-MailBook)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Neostrada TP 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.0.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.0.2 Final; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.0.2 Final; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.1.0 Beta 2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.2.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.2.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.2.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.0 Gold)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.0 Gold; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.0 Gold; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.2; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.2; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.3; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NetCaptor 7.5.4; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3621)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .BGDID000017489A1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Dave)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Feat Ext 21)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Googlebot; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; &id;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; MSN 8.0; MSN 8.5; MSNbDELL; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; MSN 8.0; MSN 8.5; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.0.3621; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 3.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Tablet PC 1.7)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; XMPP TipicIM v.RC6 1.6.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; NetNearU)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; Tablet PC 1.7; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Alexa Toolbar; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Donut RAPT #51 Sugi)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322-dtb)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Feat Ext 18)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Feat Ext 19)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Feat Ext 21)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Free Download Manager)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Lunascape 1.4.1)" + family: "Lunascape" + major: '1' + minor: '4' + patch: '1' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmde-de; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc11; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmnl-be; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 8.0; MSN 8.5; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 8.0; MSN 8.5; MSNbVZ02; MSNmen-us; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 9.0; MSNbBBYZ; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 9.0; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; MSN 9.0; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40301)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40426)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.31113)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.40301)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.40426)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.40607; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.40607; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Netibar 1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; SpamBlockerUtility 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; Tobbes surfing board)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322) WebWasher 3.3" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; XMPP TipicIM v.RC5 1.6.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 2.0.40607; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 2.0.40607; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 2.0.40607; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Netpenny)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Netvitamine Toolbar (+http://www.netvitamine.com); i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; New Value #1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NISSC; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NISSC; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NN4.2.0.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NN5.0.2.23; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NN5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NN5.0.3.3; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NN5.0.3.3; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; NN5.0.600.15)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Nordstrom; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ntlworld v2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ntlworld v2.0; Hotbar 4.5.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ntlworld v2.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; nxforms/1.00; formsPlayer 1.1; formsPlayer 1.3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ONET; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Ongame E-Solutions AB; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ONLINE 5.5; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OnlyInternet.Net; Personal Computer Doctors)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ONS Internet Explorer 6.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OPT-OUT; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OPT-OUT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OPT-OUT; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE501-018)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE501-018; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE501-018; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-27)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-27; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-27; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-31; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE55-32)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusIE5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; SV1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetCable-02; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OptusNetDSL6; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Origin Energy Limited - SOE 3.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OZEHAR01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OZHARLIT6.0_1_PP3; FunWebProducts; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OZHARLIT6.0_1_PP3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OZHARLIT6.0_1_PP3; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; OZHARLIT6.0_HN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Paros/3.2.0" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PASSCALL; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PCAdvisor032002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PCPLUS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PCUser; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PeoplePal 3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Performance Technologies S.A.; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PGE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PhaseOut [www.phaseout.net]; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PKBL008; fs_ie5_04_2000i)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Plus a few changes)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PNCStd)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Poco 0.31; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Polkomtel S.A.; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PottsNet; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PowerBase6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Preload_01_07)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Preload_01_07; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Prepaidonline.com.au setup; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Primus-AOL)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PrimusCAlanEN; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PrimusDSLEN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PrimusPCEN)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PROGRATECH; MSIE6.0XP OpenBrowser CPOP5.2; DyGO.NET MailSRV; MyIE2; SV1; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Provided by Alphalink (Australia) Pty Ltd)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PRU_IE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PwCIE6v01; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PwCIE6v01; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q-06062002-K2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q-06062002-K2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312460)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; 1.21.2 ; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; AAPT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; AIRF; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Amgen.v1b; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; APCMAG; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; AT&T CSM6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; AT&T CSM6.0; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; BCD2000; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; BrowserBob; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; BTopenworld; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; CDSource=ALLIED_01_01; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; CDSource=storecd_01_03; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; COM+ 1.0.2204; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Cox High Speed Internet Customer; 1.41.1 )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Cox High Speed Internet Customer; i-NavFourF; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Cox High Speed Internet Customer; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Cox High Speed Internet Customer; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; DVD Owner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; ESB{6C1AEBB4-8C44-41AE-866F-707D5E75B0E9}; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; ESB{A44A754F-952B-4E88-802A-5725DBA66F0E})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; F-6.0-20020225)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Feedreader)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Feedreader; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; FunWebProducts-MyWay; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; FunWebProducts; NetCaptor 7.5.2; WebCloner 2.3; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; FunWebProducts; ntlworld v2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; GIL 2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hewlett-Packard; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 3.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.1.5.0; MyIE2; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.1.8.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.4.5.0; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.4.7.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.4.7.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.5.1.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Hotbar 4.5.1.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; IESYM6; Hotbar 4.5.0.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; IOpener Release 1.1.04)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; iOpus-I-M; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; iOpus-I-M; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; MathPlayer 2.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; MyIE2; Maxthon; SV1; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; MyIE2; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; MyIE2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.0.2914; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.0.3705; .NET CLR 1.2.2125; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; NN5.0.600.11)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; OptusNetDSL6; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Paul BunyaNet; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Q-07122002-K2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; (R1 1.3); .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Roadrunner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Roadrunner; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; Roadrunner; TheFreeDictionary.com; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; sbcydsl 3.12; YComp 5.0.0.0; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SIK30; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; 18ko/; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; ATB; Visited by ATB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; GIL 2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; IBP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; SV1; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; T312461; SV1; EnergyPlugIn; dial; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; TeomaBar 2.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; TeomaBar 2.01; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; TeomaBar 2.01; SV1; MSN 6.1; MSNbMSFT; MSNmja-jp; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; tiscali; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; TUCOWS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; TVA Build 2001-10-11)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.0.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.2.5; Hotbar 4.2.8.0; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YComp 5.0.2.6; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YPC 3.0.1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; YPC 3.0.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312462)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312463)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312464)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312465)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312466)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312467)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312468)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312469)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q321017)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q321017; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q321120; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q321120; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q321120; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q321150; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q342532)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q822925; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QinetiQ IE6 V02; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QS 4.1.1.2; DVD Owner; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QS 4.1.2.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QS 4.1.2.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QS 4.1.2.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Queensland Government; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QUT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QUT Printing Services; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Qwest - 11122003-a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Qwest - 11122003-a; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Qwest - 12302003-sms)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Qwest - 12302003-sms; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QXW0330d; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QXW0339d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; QXW0340e; www.ASPSimply.com; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.1); FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.1); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.1); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3)),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3); MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; [R1 1.3]; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3); .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.3); .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; (R1 1.5); (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; RD&E v.6.0 r.6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; RD&E v.6.0 r.6; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Really Firefox-It works fine asshole)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Renault)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Renault; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; RI-ADMIN12112003)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; FunWebProducts; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Roadrunner; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; Hotbar 4.4.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; Hotbar 4.4.2.0; SV1; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; TheFreeDictionary.com; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; YPC 3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; YPC 3.1.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Rogers Hi-Speed Internet; YPC 3.1.0; yplus 4.5.03b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; RSD66)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; rtc user)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; rtc user; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; RWE Dea AG)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)-s" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SALT 1.0.3404.1 1007 Developer; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SALT 1.0.4223.1 0111 Developer; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SALT 1.0.4223.1 0111 Developer; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SALT 1.0.4613.0 0111 Developer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SALT 1.0.5507.1 0111 Developer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SAVEWEALTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; ESB{E49F02C9-B446-4F5C-9EB8-5A2DF808DA80}; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; FunWebProducts; YPC 3.0.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; SV1; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; SV1; YPC 3.0.3; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.1.4322; yplus 3.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YComp 5.0.0.0; yplus 3.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; yie6_SBCDSL; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YPC 3.0.1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sbcydsl 3.12; YPC 3.0.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SBS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SBS; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SC/5.10/1.14/Telenor)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SC/5.10/1.14/Telenor; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SC/5.60/1.01/FS-Internett; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; School of Business and Computing; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SCL Build)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ScreenSurfer.de; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SEARCHALOT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SEARCHALOT.COM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SEARCHALOT.COM; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SearchFox Toolbar 2.0b1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sfgdata=5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SFIE60122601; SFIEAUTH1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SFIEAUTH1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SGC; SGC STUDENTS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Sgrunt|V107|634|S-1869674593|dialno; alice01; snprtz|dialno; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Sgrunt|V109|1684|S-129601565|dial; snprtz|S03037726560360)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Sgrunt|V109|622|S1290160941|dialno; snprtz|dialno)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Sgrunt|V109|69|S-327757572|dialno)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Shazam; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Siemens A/S; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; FunWebProducts; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; FunWebProducts; SV1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SIK30; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SINGNET)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SINGNET/HTMLAB; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SiteCoach 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SKY11a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SKY13; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SlimBrowser [flashpeak.com])" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Smart Explorer 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Smart Explorer 6.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Smart Explorer 6.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Smart Explorer v6.0 ( Evaluation Period ))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Smart Explorer v6.0 ( Evaluation Period ); .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; snft internet; SV1; OptusNetDSL6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; snopud.com client; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Snowdrop Systems; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; snprtz|dialno; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; snprtz|S03037726560360)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; snprtz|T03022004250337; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; snprtz|T04125278003990)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SOK)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SON-1102CD; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SON-1102CD; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; sp1, AHS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SP/6.35/1.01/ONLINE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SPARTA AREA SCHOOLS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SPServe)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; **SPS**; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SS.CC. Palma)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StarBand Version 1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StarBand Version 4.0.0.2; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StarBand Version 4.0.0.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StarBand Version 4.0.0.2; SV1; .NET CLR 1.0.3705; Media Center PC 2.8; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {Starpower})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; STB; 560x384; MSNTV 4.1; THMDR)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; STIE60-021004; STIE60-020212; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; STI; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; STI; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stokeybot)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Stonehenge School)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StopTrackingMe; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Stratford ISD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.733; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.735; MyIE2; SV1; Maxthon; JyxoToolbar1.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.735; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.736; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.744)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.755)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.755; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.758; MyIE2; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.758; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.760)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.760; iRider 2.21.1108; .NET CLR 1.1.4322)" + family: "iRider" + major: '2' + minor: '21' + patch: '1108' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.760; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.760; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.760; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.763)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.763; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.818; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.818; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.820; SV1; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.901; FDM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.906; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.910; Maxthon; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.910; SV1; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.910; SV1; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.917; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.917; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.917; SV1; Hotbar 4.5.1.0; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.919; Maxthon; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; StumbleUpon.com 1.919; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stumbleupon.com 1.923; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stumbleupon.com 1.923; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stumbleupon.com 1.924; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stumbleupon.com 1.924; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stumbleupon.com 1.925; .NET CLR 1.0.3705; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stumbleupon.com 1.926; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; stumbleupon.com 1.926; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; subagente; Agente; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Sunrise; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Supplied by blueyonder)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Supplied by blueyonder; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Supplied by blueyonder; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Supplied by blueyonder; SV1; Hotbar 4.5.1.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Supplied by blueyonder; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Supplied by Tesco.net)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Surf Mechanic; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; 1.41.1 ; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; 1.56.1 ; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; 9LA; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AAPT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; ACTC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AIRF; NetCaptor 7.2.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AIRF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Alexa Toolbar; jd; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Alexa Toolbar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Alexa Toolbar; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Alexa Toolbar; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; ALL YOUR BASE ARE BELONG TO US; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Antenna Preview Window)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Antenna Preview Window; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AOL7)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; APCMAG; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Arcor 5.002; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Arcor 5.002; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Arcor 5.003)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AskBar 3.00; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AT&T CSM6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AT&T CSM7.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AT&T CSM8.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AUTOSIGN W2000 WNT VER03)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AVPersonalSerial 2b206c294a291e6470432759423669f000255953; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BBIP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BCD2000; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Berg Network Client; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BMD Melbourne; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Boeing Kit; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; brip1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BTHS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BT Openworld BB; YPC 3.0.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BT Openworld Broadband; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BT Openworld Broadband; YPC 3.2.0; yplus 4.3.02d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; BTY; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Burnie High Student)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Canning College)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CaseDOSA/Operator; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CDSource=BP1b.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CDSource=v11c.01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CDSource=v9e.04; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CIM Gruppen; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Citrix)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Compatible; Version; ISP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Cox High Speed Internet Customer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Cox High Speed Internet Customer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Creative; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CSIE60SP02; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CursorZone 1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; CursorZone Grip Toolbar 2.08; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; custom; custom; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; custom; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Deepnet Explorer)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Deepnet Explorer 1.3.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Deepnet Explorer 1.3.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Deepnet Explorer 1.3.2; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Deepnet Explorer; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Deepnet Explorer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Deepnet Explorer; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DHSI60SP1001; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DI60SP1001)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DigExt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DigExt; FunWebProducts; Media Center PC 3.0; .NET CLR 1.0.3705; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; digit_may2002)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; D-M1-200309AC;D-M1-MSSP1; D-M1-200309AC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DOJ3jx7bf; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Domain user; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Donkey; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DownloadSpeed; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DVD Owner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; DVD Owner; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Editor 3.0 - http://www.e-ditor.com; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; ESB{77898B69-9C1F-433D-B8EA-FD6FA2B8A2CC}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; ESB{C6B1C008-FCCB-4A07-BF79-6BEED181D1F0})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; E-train)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; evUI; Agency Manager Management Console; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FDM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FeedEater; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Feedreader; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Feedreader; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Feedreader; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Feedreader; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Feedreader; (R1 1.5); .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; formsPlayer 1.3; nxforms/1.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FREE; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FTDv3 Browser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FTDv3 Browser; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; 1.56.1 ; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; 1.56.1 ; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Alawar 2.08; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Hotbar4.5.3.0; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Hotbar4.5.3.0; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc00; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Hotbar4.5.3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; i-NavFourF; onlineTV; www.cdesign.de; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts-MyWay)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts-MyWay; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts-MyWay; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.1.4322; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmnl-nl; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; (R1 1.1); (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; SpamBlockerUtility 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; FunWebProducts; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GambleEnt; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; gameland)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GIS IE6.0 Build 20031111; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GMX AG by USt; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; gogo)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Golfing Paradise; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Tablet PC 1.7)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Grip Toolbar 2.07a)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Grip Toolbar 2.08; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Headline-Reader; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; HEL INTERNET EXPLORER)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.2.14.0; .NET CLR 1.0.3705; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.4.5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.4.6.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.4.6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.5.1.0; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.5.1.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.5.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar4.5.3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar4.5.3.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar4.5.3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar4.5.3.0; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar4.6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar 4.6.1; MSN 6.1; MSNbMSFT; MSNmnl-nl; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hotbar Unknown; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; HTMLAB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; http://www.aztrx.com/ )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; http://www.tropicdesigns.net)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; http://www.tropicdesigns.net; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; IBP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; IBP; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; IBP; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; IBP; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iebar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iebar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iebar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iebar; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iebar; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Imperial College; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; i-NavFourF; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; i-NavFourF; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; i-NavFourF; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iOpus-I-M)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iOpus-I-M; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iOpus-I-M; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iOpus-I-M; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iOpus-I-M; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iOpus-I-M; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iOpus-I-M; Wanadoo 6.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iP-CMPQ-2003; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; iP-CMPQ-HDD; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; IWSS:wxp4432/00114366da97; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; JNet; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; JUNO)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; KATIESOFT 6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; KKman3.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; LetNet Connect, [www.letu.edu]; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; lWh.lgS.rfU.lxd; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Manor Trust::)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MathPlayer 2.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MathPlayer 2.0; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 2.0.41202)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MathPlayer 2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; Alexa Toolbar)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; FREE)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; FREE; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; NetCaptor 7.5.4)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322; FDM)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322; FDM; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Maxthon; (R1 1.5); .NET CLR 2.0.40903)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MaxXium; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Media Center PC 3.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Media Center PC 3.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Media Center PC 3.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MediaPilot)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT; Campus Bundaberg;))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 4.0 (build 00768); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 4.0 (build 00768); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSCS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbDELL; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmfr-fr; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 6.1; MSNbMSFT; MSNmnl-nl; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 9.0;MSN 9.1; MSNbQ002; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MTI; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MTK; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; iebar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; Maxthon)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; Maxthon; Alexa Toolbar)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; Maxthon; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; Maxthon; (R1 1.3))" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; Maxthon; TaxWise19.00[0016]; TaxWise19.01[0003]; TaxWise19.02[0005]; TaxWise19.03[0001]; TaxWise19.04[0001]; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; .NET CLR 1.0.3705)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Neostrada Plus 5.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Neostrada TP 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.2.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.0 Gold; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.2; FDM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.2; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.3; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.3; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.4; Media Center PC 3.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.4; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Alexa Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Media Center PC 2.8; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Media Center PC 2.8; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Media Center PC 3.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Media Center PC 3.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; MSN 6.1; MSNbMSFT; MSNmit-it; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 3.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 3.1; Googlebot/2.1)" + family: "Googlebot" + major: '2' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 3.1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 3.1; .NET CLR 2.0.40209)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Q342532)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Tablet PC 1.7)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; XMPP TipicIM v.RC6 1.6.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 2.0.40607; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Tablet PC 1.7)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Tablet PC 1.7; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; Tablet PC 1.7; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; 45c42354c4e5r4cw!(s)4sd)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Alexa Toolbar; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Alexa Toolbar; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322) Babya Discoverer 8.0:" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; FDM; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Hotbar 4.6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Hotbar 4.6.1; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Hotbar 4.6.1; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Lunascape 1.4.0beta3)" + family: "Lunascape" + major: '1' + minor: '4' + patch: '0' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Lunascape 1.4.1)" + family: "Lunascape" + major: '1' + minor: '4' + patch: '1' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Lunascape 1.4.1),gzip(gfe) (via translate.google.com)" + family: "Lunascape" + major: '1' + minor: '4' + patch: '1' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Lunascape 2.0.1)" + family: "Lunascape" + major: '2' + minor: '0' + patch: '1' + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmde-at; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-ca; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-gb; MSNc0z; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc11; MSNc11)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc11; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-us; MSNc21; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmit-it; MSNc0z; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbBC01; MSNmen-ca; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbBC01; MSNmfr-ca; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-gb; MSNcOTH)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcIA; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbMSNI; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbQ002; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSN 9.0;MSN 9.1; MSNbVZ02; MSNmen-us; MSNcOTH; MPLUS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MSNc11; MSN 6.1; MSNbMSFT; MSNmen-us)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.2914; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.2914; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Media Center PC 3.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; Version; Platform; Compatible)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40209)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40301)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40903; Avalon 6.0.4030)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.41115)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.41202)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50110)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50110; Avalon 6.0.4030)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50215)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; NOKTURNAL KICKS ASS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Q342532)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Secure IE 3.3.1263)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Tablet PC 1.7)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.40607; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.40607; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.40607; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.40607; .NET CLR 2.0.40426; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.40903; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.41118; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50126)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Net M@nager V4.00 - www.vinn.com.au)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetPanel:763771; npUID:763771; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NN4.2.0.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; N_O_K_I_A)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) NS8/0.9.6" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; nxforms/1.00; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OfficeWorld.com/1.082)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusIE55-31)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusIE55-31; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusNetCable-02)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusNetDSL6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusNetDSL6; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusNetDSL6; FDM; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusNetDSL6; MathPlayer 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusNetDSL6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; OptusNetDSL6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Overture; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; PeoplePal 3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Poco 0.31)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Poco 0.31; TencentTraveler ; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; PrimusDSLEN; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Prisoner; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; provided by blueyonder; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Q342532)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Quik Internet (0102098b))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.1))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.3); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.3); .NET CLR 1.0.3705; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.3); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.3); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.3); .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc0z; MSNc00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.3); (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); MSN 6.1; MSNbMSFT; MSNmen-us; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 3.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); onlineTV; www.cdesign.de)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (R1 1.5); snprtz|T04077983781234)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; RCBIE6XPMAN; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Rogers Hi-Speed Internet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SALT 1.0.3404.1 1007 Developer; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SALT 1.0.5507.1 0111 Developer; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SALT 1.0.5507.1 0111 Developer; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Sgrunt|V108|654|S-2135541317|dial; snprtz|T03087750360356; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Sgrunt|V109|34|S-1398421108|dialno; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Sgrunt|V109|547|S1107901103|dial; XBE|29|S04039483631143; snprtz|S04048557771347)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Sgrunt|V109|598|S76509116|dialno)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SIK30)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SIK30; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SIK30; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SLPS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SmartShop)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SON-1102CD)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SON-1102CD; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; SPARTA AREA SCHOOLS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; sumit)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Suncorp Metway Ltd; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Supplied by blueyonder)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Supplied by blueyonder; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Supplied by Tesco.net; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; surfEU FI V3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Tablet PC 1.7; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Tablet PC 1.7; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TBP_6.1_AC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TencentTraveler )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TeomaBar 2.01; AskBar 3.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TeomaBar 2.01; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TheFreeDictionary.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TheFreeDictionary.com; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; TNET5.0NL; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; urSQL; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; User Agent; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; UserAgent; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Virgin 3.00)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; VND Toolbar; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; VNIE5 RefIE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; VNIE5 RefIE5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; VNIE60; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; VNIE60; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Wanadoo 5.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Wanadoo 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Wanadoo 6.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Wassup; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; WebSpeedReader 8.6.96; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) WebWasher 3.3" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; WHCC/0.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; WHCC/0.6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; WHCC/0.6; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; WI4C 3.5.3.001; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; www.ASPSimply.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; www.aztrx.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; www.k2pdf.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Wysigot 5.51)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; XMPP TipicIM v.RC6 1.6.8; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; XN2K3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; yie6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; yie6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; yie6_SBC; YPC 3.0.3; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.1; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.2; .NET CLR 1.1.4322; yplus 4.4.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.3; .NET CLR 1.1.4322; yplus 4.0.00d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.0.3; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.1.0; bgft; Media Center PC 3.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.1.0; Media Center PC 3.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.1.0; yplus 4.5.03b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; YPC 3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SWSIT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SWSIT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Sykes Enterprises Inc. B.V.)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SYMPA)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SYMPA; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SYMPA; Q312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SYMPA; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; Artabus)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; DI IE 5.5 SP2 Standard; GESM IE 5.5 SP2 Standard; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; PGE; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; Q312461; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; SV1; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; SV1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; SV1; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; T312461; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TARGET HQ; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TaxWise19.00[0016]; TaxWise19.05[0002]; TaxWise19.07[0006]; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_6.1_AC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_6.1_AC; NetCaptor 7.5.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_6.1_AC; (R1 1.3); Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_7.0_GS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_7.0_GS; FunWebProducts; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_7.0_GS; Hotbar 4.5.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_7.0_GS; .NET CLR 1.1.4322; MSN 6.1; MSNbMSFT; MSNmen-au; MSNc00; v5m)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_7.0_GS; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBP_7.0_GS; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TBPH_601)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TDSNET8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; telus.net_v450HS; SV1; Hotbar 4.5.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; telus.net_v5.0.1; Hotbar 4.5.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TencentTraveler )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TencentTraveler ; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TeomaBar 2.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TeomaBar 2.01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TeomaBar 2.01; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Testing.net; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Texas Instruments)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Texas Instruments, Inc; [R1 1.3]; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; The Department of Treasury - Bureau Of The Public Debt)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TheFreeDictionary.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TheFreeDictionary.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TheFreeDictionary.com; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; The Free Lance-Star Publishing Company)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Thiess Pty Ltd)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; tip; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TiscaliFreeNet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Tiscali; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TMS Inst 5.5; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TNT Australia Pty Ltd; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Total Internet; Q312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TR.NET Dialup Ver.2.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TRPIT; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TRPIT; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TS User; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TUCOWS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TUCOWS; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TVA Build 2002-05-16)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; TVA Build 2002-05-16; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; U)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; UBIS-RESNET 2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; UKPORTAL; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; UrIE 4.0; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; urSQL; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; %username%; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 2.8)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; USERNAME_PASSWORD_IS_ENABLED; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; UUNET)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; V1.0Tomorrow1000; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; v11b.01; FunWebProducts; SV1; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; V6.00-003)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; v6.1b; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; V6; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Videotron)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Videotron; SV1; CustomExchangeBrowser; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VIRTUALIT.BIZ; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Virtual IT - http://www.virtualit.biz)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE4 3.1.814; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE5 RefIE5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE5 RefIE5; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE5 RefIE5; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE5 RefIE5; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE60)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE60; MyIE2)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE60; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE60; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; VNIE60; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Voicecrying.com; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Voyager II; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; vtown v1.0; FunWebProducts; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo042NLPP01HCFFFFFFEC; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo042NLPP01HCFFFFFFFA; AtHome033)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.5)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.5; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.5; SV1),gzip(gfe) (via translate.google.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.5; Wanadoo 6.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.5; Wanadoo 6.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.5; Wanadoo 6.2; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.6; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 5.6; Wanadoo 6.1; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; i-NavFourF)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; i-NavFourF; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.1; Wanadoo 6.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo 6.2; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wanadoo Câble 5.6; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Was guckst du?; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WCCTA; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; weasel & chicken; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WebSpeedReader 8.7.4; Hotbar 4.5.1.0; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) WebWasherEE/3.4.1 3.4.1" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Westerville Public Library; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WestNet)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Weybridge; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WHCC/0.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WHCC/0.6; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WHCC/0.6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WHCC/0.6; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WHCC/0.6; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WHO Synergy II; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wile E. Coyote Build - ACME)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Windows XP SP2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Windows XP SP2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WinXP-SOE v3.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WODC; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .WONKZ)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wooohooooooooooooooooooooooooooo!; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; World Interactive Software)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; {World Online})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WRV)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; W&S; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; WWIEPlugin; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.amorosi4u.de.vu)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.ASPSimply.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.ASPSimply.com; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.ASPSimply.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.ASPSimply.com; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.ASPSimply.com; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.ASPSimply.com; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.Bertram-Engel.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.BERTRAM-ENGEL.com Webmaster; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.k2pdf.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.k2pdf.com; Compatible; Version; Platform)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.k2pdf.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.k2pdf.com; SV1; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.k2pdf.com; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.oxy-com.com; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.spambully.com)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.spambully.com; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; www.wbglinks.net)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wysigot 5.22; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Wysigot 5.4; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; X Channel Browser)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; XTM02b Beta 1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; XTM02b Beta 1; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; FunWebProducts; Hotbar 4.5.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; FunWebProducts-MyWay; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; FunWebProducts; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; Hotbar 4.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; Maxthon; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; .NET CLR 1.0.2914)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; Rogers Hi-Speed Internet; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; sbcydsl 3.11; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; sbcydsl 3.12; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; SEARCHALOT; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.0.0; yplus 3.01)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.4)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.4; AskBar 2.11)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.4; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.5; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; Feedreader)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; Hotbar 4.4.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; ntlworld v2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.8.6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.8.6; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.8.6; SV1; yplus 1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; DVD Owner)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6)Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6_SBC)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6_SBCDSL; FunWebProducts; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6_SBCDSL; sbcydsl 3.12; YComp 5.0.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6_SBCDSL; sbcydsl 3.12; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6_SBC; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; sbcydsl 3.12; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6_SBC; YPC 3.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; SV1; (R1 1.5))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; YComp 5.0.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; YPC 3.0.3; (R1 1.3))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yie6; YPC 3.0.3; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; BT Openworld BB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; BTopenworld; yplus 4.3.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; FunWebProducts; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; SV1; (R1 1.1); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; SV1; yplus 4.0.00d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.0; yplus 4.3.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; FunWebProducts; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; FunWebProducts; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; Hotbar 4.4.2.0; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; NetCaptor 7.5.0 Gold)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.0.3705; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.0.3705; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; (R1 1.3); (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; (R1 1.5; yplus 4.1.00b))" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1; .NET CLR 1.0.3705; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; SV1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; yie6_SBC; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; BT Openworld BB)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; BT Openworld BB; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; BT Openworld BB; .NET CLR 1.1.4322; yplus 4.3.02d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; BT Openworld BB; SV1; yplus 4.3.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; BT Openworld BB; SV1; yplus 4.3.02d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; .NET CLR 1.0.3705; yplus 4.4.02d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; .NET CLR 1.1.4322; .NET CLR 1.0.3705; yplus 4.4.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; .NET CLR 1.1.4322; yplus 4.3.01b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; .NET CLR 1.1.4322; yplus 4.3.02b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; SV1; ESB{4146F2DC-3320-4F28-8906-D3591D69426E}; TheFreeDictionary.com; yie6-uk; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; SV1; yplus 4.3.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; SV1; yplus 4.3.02b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; yplus 4.3.02b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; yplus 4.3.02d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.2; yplus 4.4.01d)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; FunWebProducts; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; .NET CLR 1.1.4322; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; SV1; .NET CLR 1.0.3705; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; SV1; .NET CLR 1.1.4322; Hotbar 4.6.1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; SV1; .NET CLR 1.1.4322; yplus 4.0.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.0.3; SV1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.1.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.1.0; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.1.0; SV1; FunWebProducts)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.1.0; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.1.0; SV1; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.2.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YPC 3.2.0; .NET CLR 1.0.3705; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; yplus 4.1.00b)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Z-HARPE)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Zurich North America; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; {2C2E9759-7422-4D75-89A2-9C0419FE3957}; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; {2D24C5F8-6342-4582-8057-099D1FBBF5EC}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; {4372BAAC-73EB-4BF5-9A5F-E4F106925C4E}; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; {61F2E4DF-60B7-4C8A-8BD9-98853FF61315}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; {85167A96-330B-4FA4-B250-90A9AA0F0FCF}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; {8D08774B-017A-4392-97D1-F9D354660A55}; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; ATLAS.SK_01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Data Center; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2;;) [de]" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Deepnet Explorer 1.3.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; demne is my dog)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; digit_may2002; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; EFW TSC2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Feedreader; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; FunWebProducts-MyWay; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; FunWebProducts-MyWay; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; FunWebProducts; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Glazenzaal; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; GruppoMPS; Maxthon; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; H; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; i-NavFourF; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Infowalker v1.01; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; iTreeSurf 3.6.1 (Build 056); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; LCC Internal User - 010; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; LCC Internal User - 014; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Maxthon; .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Maxthon; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Maxthon; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Maxthon; (R1 1.5); .NET CLR 1.1.4322)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Maxthon; SV1; Deepnet Explorer 1.3.2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "Maxthon" + major: '0' + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Moneysupermarket.com Financial Group; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; MyIE2; iTreeSurf 3.6.1 (Build 056); .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; MyIE2; Maxthon; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; MyIE2; .NET CLR 1.1.4322)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; MyIE2; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "MyIE2" + major: "0" + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; NetCaptor 7.5.0 Gold; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; NetCaptor 7.5.1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; NetCaptor 7.5.3; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40420)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; FDM)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; MSIECrawler)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.40301)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.40419)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.41115)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 2.0.31113;)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Poco 0.31; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Q312461; .NET CLR 1.0.3705; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Q321120; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; (R1 1.5); .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; (R1 1.5); .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SALT 1.0.0.0 1007 Developer; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; stumbleupon.com 1.923; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; TencentTraveler ; .NET CLR 1.1.4322; Alexa Toolbar)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Weybridge; .NET CLR 1.1.4322; .NET CLR 2.0.40903)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Win64)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Win64; AMD64)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Win64; x64; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Win64; x64; SV1; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; WOW64; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; WOW64; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; www.ASPSimply.com; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 6.0; .NET CLR 1.2.30703)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT; MS Search 4.0 Robot)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows XP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible;MSIE 6.0; Windows XP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows XP Professional Bot v.5.)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows 2000)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible;MSIE 6.0; Windows 3.11)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.0; T312461)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible;MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; .NET CLR 2.0.40607)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.2)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 8.3; )" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Windows XP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (compatible;MSIE 6.0;Windows XP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 [de] (compatible; MSIE 6.0; Windows 98)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 [en] (compatible; MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/6.0 (compatible; MSIE 6.0; Windows 3.11 For workgroups; {6BD3E7C1-0732-43E8-8828-291A709CC070})" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MSIE 6.0 (compatible; MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE 6.0 (compatible; MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE/6.0 (compatible; MSIE 6.0; Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE 6.0 (compatible; MSIE 6.0; Windows NT 5.1)/4.78 (TuringOS; Turing Machine; 0.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE 6.0)\" (MSIE 6.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE 6.0 (+MSIE 6.0; Windows NT 5.0; Q312461;; MSIE; Windows)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE 6.0 (Windows NT 5.1)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "MSIE/6.0 ( Windows NT 5.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MSIE/6.0 (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MSIE 6.0 (Win XP)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.01; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.02; Windows 98)" + family: "IE" + major: '6' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.3 (compatible; MSIE 6.2; Windows NT 6.0)" + family: "IE" + major: '6' + minor: '2' + patch: + - user_agent_string: "Mozilla/6.1 (compatible;MSIE 6.5; Windows 98)" + family: "IE" + major: '6' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 7.66; Windows NT 5.1; SV1)" + family: "IE" + major: '7' + minor: '66' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 7.66; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" + family: "IE" + major: '7' + minor: '66' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 8.0; Windows 94)(2000/08/12-2000/08/24)" + family: "IE" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 1.0.3705)" + family: "IE" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 7.0a1; Windows NT 5.1; SV1; .NET CLR 1.1.4322; MS IdentiServ 1.4.12)" + family: "IE" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSXPLAYer2.014)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; MuscatFerret/1.6.3; claude@euroferret.com) via proxy gateway CERN-HTTPD/3.0 libwww/2.17" + family: "Other" + major: + minor: + patch: + - user_agent_string: "MVAClient" + family: "Other" + major: + minor: + patch: + - user_agent_string: "My Browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; NCSA_Mosaic; windows; SV1; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NCSA_Mosaic/2.6 (X11;IRIX 4.0.5F IP12)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01 (compatible; Netbox/3.5 R92.5; Linux 2.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01 (compatible; NetBox/3.5 R92.3; Linux 2.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01 (compatible; Netbox/3.5 R93rc3; Linux 2.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01 (compatible; Netgem/3.6.7; netbox; Linux 2.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ZoneSurf/2.4 (BeOS; U; BeOS 5.0 BePC; en-US; 0.8)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; NetPositive/2.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; NetPositive/2.2.1; BeOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; NetPositive/2.2.2; BeOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; NetPositive/2.2.3; FreeBSD 5.2.1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "netscape (compatible; netscape; linux; SV1; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Netscape 7.0; Windows 98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Netscape 7.0; Windows NT 4.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible;Netscape 7.1; Windows 98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Netscape 7.3R; Windows 92)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 Netscape 7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (Netscape 4.79; Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.5; Windows NT 5.0) Netscape 7.1" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Netscape 4.08; Windows 98; DigExt)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible;Netscape 4.76 Mozilla 1.4;Linux 2.6.7)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Netscape 7.0; Windows 98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Netscape Gecko/20040803" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows XP; en-US; rv:1.7.5) Netscape 7.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-CA; rv:0.9.4) Gecko/20011128 Netscape 7.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040113 Netscape 7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040626 Netscape Navigator 4.x/4.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.1) Gecko/20020921 BigBrother/Netscape6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/7.1 [en] (Windows NT 5.1; U)Netscape" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape (Windows; U; Windows NT 5.0; en-US; rv:1.7.5) Navigator/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape 1.22 (Win16; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape 2.1 (compatible; MSIE 2.0B1; Windows for Workgroup 3.11; i386; en-US)" + family: "IE" + major: '2' + minor: '0' + patch: + - user_agent_string: "Netscape 4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 [en]C-WNS2.5 (Wim95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 [en] (Win2000; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 [en] (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 [en] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 [en] (X11; I; HP-UX B.10.20 9000/712)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 [en] (X11; I; SunOS 5.5.1 sun4m)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.04 (Linux i686; 1.7.3; Linux i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.05 [en] (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.05 [en] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.05 [fr] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.05 (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.06 [en] (Direct Hit Grabber)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.06 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.06 [en] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.06 [en] (X11; U; Linux 2.0.27 i586)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.06 (Macintosh; I; PPC, Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.06 (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.07C-SGI [en] (X11; I; IRIX 6.5 IP32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.07 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.07 [en] (X11; I; Linux 2.0.36 i586)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.07 (X11; I; Nav; Linux 5.1.33 i586; )" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (Win16; I ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (Win16; U ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en](Win95; U; Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (Win98; I ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (Win98; U ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (Windows 3.11; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (WinNT; I ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (WinNT; U ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [en] (X11; U; Linux 2.4.9-34 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 [fr] (Win95; I ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 (Macintosh; U; PPC, Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.08 (PDA; PalmOS/sony/model atom/Revision:2.0.22 (en)) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.08 (PDA; PalmOS/sony/model atom/Revision:2.0.26 (de)) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.08 (PDA; PalmOS/sony/model luke/Revision:2.0.22 (en)) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.08 (PDA; PalmOS/sony/model luke/Revision:2.0.26 (de)) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.08 (PDA; PalmOS/sony/model prmr/Revision:2.0.22 (en)) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.08 (PDA; Windows CE/1.0.0) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.08 (PPC; Windows CE/1.0.0) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.08 (SmartPhone; Symbian OS-Series60/1.03) NetFront/3.2" + family: "NetFront" + major: '3' + minor: '2' + patch: + - user_agent_string: "Mozilla/4.1 (BEOS; U ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.1 [ja] (X11; I; Linux 2.2.13-33cmc1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.41 (BEOS; U ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [de] (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en]C-AtHome0405 (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en]C-CCK-MCD snapN45b1 (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en]C-CCK-MCD (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en] (X11; I; Alpha 06; Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [en] (X11; I; IRIX64 6.5 IP30) Mozilla/4.08 [en] (Win95; I ;Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 [fr] (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 RPT-HTTPClient/0.3-2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 (Windows; U; Windows NT 5.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape/4.5 (WindowsNT;8-bit)" + family: "Netscape" + major: '4' + minor: '5' + patch: + - user_agent_string: "Netscape Navigator 4.5 (Windows; U; Windows NT 5.1; sl-SI; rv:1.4) Netscape/4.5" + family: "Netscape" + major: '4' + minor: '5' + patch: + - user_agent_string: "Mozilla/4.51C-ASML_1N06S [en] (X11; I; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.51 [de]C-CCK-MCD DT (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.51 [de]C-CCK-MCD FS SBS (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.51 [de]C-CCK-MCD QXW03200 (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.51 [de]C-CCK-MCD QXW03200 (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.51 [de] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.51 [en]C-CCK-MCD (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.51 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.6 [de]C-freenet 4.0 (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.6 [de] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.6 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [de] (OS/2; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en]C-CCK-MCD (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en]C-CCK-MCD (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en] (OS/2; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en] (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en] (X11; I; Linux 2.2.13-33cmc1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en] (X11; I; Linux 2.4.25 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [en] (X11; U; ) - BrowseX (2.0.0 Windows)" + family: "BrowseX" + major: '2' + minor: '0' + patch: '0' + - user_agent_string: "Mozilla/4.61 [en] (X11; U; FreeBSD 4.9-RC i386)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 [ja] (X11; I; Linux 2.2.13-33cmc1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.61 (X11; )" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7C-CCK-MCD {C-UDP; EBM-APPLE} (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7C-CCK-MCD [en] (X11; I; SunOS 5.6 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de]C-CCK-MCD 1&1 PureTec Edition 02/2000 (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de]C-CCK-MCD QXW0322a (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de]C-freenet 4.0 (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de]C-SYMPA (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de] (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [de] (X11; Linux)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en]C-CCK-MCD EBM-Compaq1 (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en]C-CCK-MCD NSCPCD47 (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en]C-SYMPA (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en-gb] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en, US, en_US] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (X11; I; AIX 4.2)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (X11; I; HP-UX B.10.20 9000/782)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (X11; I; Linux 2.6.4 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (X11; I; OSF1 V4.0 alpha)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (X11; I; SunOS 5.8 i86pc)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [en] (X11; I; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [fr]C-CCK-MCD C_ASPI_1_0 (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [fr] (WinNT; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [fr] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [ja] (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [ja] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 [ja] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (Macintosh; ppc)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (X11; Linux)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7x [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7x [en] (Win9x)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.71 [en]C-NECCK (Win95; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.71 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.71 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.72 [en] (Win95; I) WebWasher 3.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.72 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.72 [en] (Win98; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.72 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.72 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.72 [en] (X11; I; Linux 2.2.14 i586)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.72 (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73C-CCK-MCD VerizonDSL (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [de]C-CCK-MCD DT (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [de]C-CCK-MCD DT (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [de]C-CCK-MCD DT (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [de] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [en]C-SYMPA (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [en] (Windows NT 5.0; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.73 [en] (X11; U; Linux 2.2.19 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.74 [en]C-DIAL (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.74 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.74 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75C-CCK-MCD {C-UDP; EBM-APPLE} (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75C-CCK-MCD {C-UDP; EBM-APPLE} (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75C-CERN UNIX pcjinr02 45 [en] (X11; U; Linux 2.2.19-6.2.1.1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 compatible - Mozilla/5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [de]C-CCK-MCD DT (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [de]C-CCK-MCD QXW0325g (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [de] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en]C-CCK-MCD {C-UDP; VUT} (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en]C-CCK-MCD {Nokia} (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en]C-CCK-MCD (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en] (X11; U; Linux 2.2.16-22 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en] (X11; U; SunOS 5.6 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en] (X11; U; SunOS 5.7 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 [en] (X11; U; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.75 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 (000000000; 0; 000)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76C-SGI [en] (X11; I; IRIX 6.5 IP32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en]C-bls40 (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en]C-CCK-MCD cf476 (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en]C-CCK-MCD (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (PalmOS; U; WebPro/3.0; Palm-Arzl)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; FreeBSD 5.2-RC i386)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; HP-UX B.11.00 9000/785)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; Linux 2.2.18 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; Linux 2.4.16 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; Linux 2.4.2-2 i586)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; Linux 2.4.2-2 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; OSF1 V5.1 alpha)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; SunOS 5.7 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; SunOS 5.8 i86pc)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; SunOS 5.8 sun4m)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 [en] (X11; U; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76iC-CCK-MCD [en_US] (X11; U; AIX 4.3)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 (Macintosh; I; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 (Macintosh; I; PPC; Incompatible my ass! What if I don't want your jerky, elitist, ugly-assed css crap? Screw you!)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.76 (X11; U; Linux 2.6.3 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 (BeOS; U; BeOS BePC; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77C-CCK-MCD {C-UDP; EBM-APPLE} (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [de] (X11; U; Linux 2.2.19-SMP i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en]C-SYMPAL (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en]C-SYMPAL (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (X11; U; AIX 4.3)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (X11; U; Linux 2.2.19-6.2.1 i586)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (X11; U; Linux 2.4.2-2 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (X11; U; Linux 2.4.24 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (X11; U; Linux 2.4.27-c800-1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (X11; U; Linux 2.4.9-34 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.77 [en] (X11; U; SunOS 5.7 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78C-br_XT_4_78 [en] (X11; U; SunOS 5.8 i86pc; Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78C-CCK-MCD [en] (X11; U; HP-UX B.10.26 9000/785)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78C-CCK-MCD vg_472 [en] (X11; U; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78C-ja [ja/Vine] (X11; U; Linux 2.4.22-0vl2.11 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [de]C-CCK-MCD DT (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [de] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [de] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [de] (X11; U; Linux 2.4.7-10 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (Win98; I) IBrowse/2.3 (MorphOS 1.4)" + family: "IBrowse" + major: '2' + minor: '3' + patch: + - user_agent_string: "Mozilla/4.78 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; AIX 4.3)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; Linux 2.2.13 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; Linux 2.4.16-4GB i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; Linux 2.4.7-10 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; Linux 2.4.8-26mdk i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; Linux 2.4.9-34 i686; Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; SunOS 5.9 i86pc)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [en] (X11; U; SunOS 5.9 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [ja] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [ja] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.78 [uk] (WinME; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79C-Boeing UNIX Kit [en] (X11; U; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79C-CCK-MCD [en] (X11; U; Linux 2.4.28-1-p4smp i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79C-CCK-MCD [en] (X11; U; SunOS 5.9 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79C-SGI [en] (X11; I; IRIX64 6.5 IP30)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79C-SGI [en] (X11; I; IRIX64 6.5 IP35)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79C-SGI [en] (X11; I; IRIX 6.5 IP32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [de] (X11; U; Linux 2.2.20 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en]C-CCK-MCD {UMUC/CCKUS} (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (WinNT; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; HP-UX B.11.00 9000/785)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; Linux 2.2.12 i386)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; Linux 2.4.18-3 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; Linux 2.4.2 i386)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; SunOS 5.8 sun4m)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; SunOS 5.8 sun4u; Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 [en] (X11; U; SunOS 5.9 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.79 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape 4.79" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 (AmigaOS 3.5; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8C-SGI [en] (X11; U; IRIX64 6.5 IP30)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8C-SGI [en] (X11; U; IRIX 6.5-ALPHA-1278921420 IP32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8C-SGI [en] (X11; U; IRIX 6.5 IP32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [de] (X11; U; Linux 2.6.4-52-default i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en]C-CCK-MCD EBM-Compaq (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en]C-CCK-MCD (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Linux; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (MSIE; Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Solaris)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Win3.11; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Win95; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Win98; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Windows NT 5.0; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (Windows NT 5.1; U) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (wouw)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.2.16-22 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.4.18-3smp i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.4.20-4GB i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.4.26 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.4.27-ow1 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.4.2 i386)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.4.2 i386; Nav)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; Linux 2.4.2 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [en] (X11; U; SunOS 5.8 sun4u)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [fr] (Windows NT 5.1; U)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 (Macintosh; U; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 [us] (X11; U; Linux 2.4.26 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.8 (Win)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.25 Netscape/5.0 (X11; U; IRIX 6.3 IP32)" + family: "Netscape" + major: '5' + minor: '0' + patch: + - user_agent_string: "Netscape/5.001 (windows; U; NT4.0; en-us) Gecko/25250101" + family: "Netscape" + major: '5' + minor: '001' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; m18) Gecko/20001108 Netscape6/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; m18) Gecko/20001108 Netscape6/6.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en; rv:1.0) Netscape/6.0" + family: "Netscape" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; m18) Gecko/20010131 Netscape6/6.01" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux 2.4.2-2 i586; en-US; m18) Gecko/20010131 Netscape6/6.01" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Linux 2.6.5) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:0.9.2) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1\"" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:7.01) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.6) Gecko/20040206 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US) Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; HP-UX 9000/785; en-US; rv:1.6) Gecko/20020604 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:0.9.2) Gecko/20011002 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.5 (Windows; U; Windows NT 5.1; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape 6.1 (X11; I; Linux 2.4.18 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; Netscape6/6.2.1; Macintosh; en-US)" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 Galeon/1.3.17 (X11; Linux i686; U;) Gecko/0-pie Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:0.9.4.1) Gecko/20020318 Netscape6/6.2.2" + family: "Netscape" + major: '6' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:0.9.4) Gecko/20011022 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:0.9.4) Gecko/20011130 Netscape6/6.2.1" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; fr-FR; rv:0.9.4) Gecko/20011130 Netscape6/6.2.1" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-CA; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:0.9.4) Gecko/20011019 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.4) Gecko/20011019 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:0.9.4) Gecko/20011019 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-CA; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 (CK-SillyDog)" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.4) Gecko/20011019 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.4) Gecko/20011022 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; mag1001; rv:0.9.4) Gecko/20011019 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 (ax)" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4) Gecko/20011019 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; pl-PL; rv:1.7.6) Gecko/20050309 Netscape/6.2" + family: "Netscape" + major: '6' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:0.9.4.1) Gecko/20020314 Netscape6/6.2.2" + family: "Netscape" + major: '6' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT5.1; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4.1) Gecko/20020314 Netscape6/6.2.2" + family: "Netscape" + major: '6' + minor: '2' + patch: '2' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20011022 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20011126 Netscape6/6.2.1" + family: "Netscape" + major: '6' + minor: '2' + patch: '1' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.4) Gecko/20020508 Netscape6/6.2.3" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv 1.3) Gecko/20030313 Netscape6/6.2.3_STRS" + family: "Netscape" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20011022 Netscape6/6.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape 6.2 (Macintosh; N; PPC; ja)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040803 Netscape6/6.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.5; Windows; NT 5.0) Netscape/7" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Netscape 7" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Netscape/7.0;)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-CA; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-CMIL)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (nscd2)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; es-ES; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; mag0802; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.0.1) Gecko/20040823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-Friars!)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-LucentTPES)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-NGA)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-N_O_K_I_A)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0rc2) Gecko/20020512 Netscape/7.0b1" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0rc2) Gecko/20020618 Netscape/7.0b1" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0 (BDP)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0 (BDP),gzip(gfe) (via translate.google.com)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-10527)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-4arcade)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-AAPT)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-FRS)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (CK-WICGR/MIT)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0 (OEM-HPQ-PRS1C03)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; pt-BR; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.0 (NSEUPD V44 14.11.2003)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; AIX 000F384A4C00; en-US; rv:1.0.1) Gecko/20030213 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux 2.4.2-2 i586; en-US; m18) Gecko/20010131 Netscape7/7.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux-2.6.4-4GB i686; en-US; m18;) Gecko/20030624 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux; en-US; rv:1.0.1) Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0rc2) Gecko/20020513 Netscape/7.0b1" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4m; en-US; rv:1.0.1) Gecko/20020920 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.1) Gecko/20020719 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.1) Gecko/20020920 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.0.1) Gecko/20020921 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.4a) Gecko/20020920 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; fr-FR; rv:1.0.1) Gecko/20020920 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4u; ja-JP; rv:1.0.1) Gecko/20020920 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; SunOS sun4us; en-US; rv:1.0.1) Gecko/20020920 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/7.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010726 Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "\"Netscape 7.0\"" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape/7.0" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Netscape/7.0 (BeOS 5; x86; NetServer; en-US) Gecko/20040604" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Netscape/7.0 [en] (Windows NT 5.1; U)" + family: "Netscape" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; ja-JP; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.01 (CK-FEL-IcD)" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01 (CK-Disanet)" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01 (CK-N_O_K_I_A)" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.01 (ax) (CK-SillyDog)" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01" + family: "Netscape" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC; ja-JP; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US; rv1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-CA; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-GB; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 (ax)" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 (CK-SillyDog)" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 (CK-DNJ702R1)" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040617 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; pt-BR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-CA; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 (ax)" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 (CK-MIT)" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 (VAUSSU03)" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02 (CK-Ifremer)" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US) Netscape7/7.02" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i386; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; de-DE; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; ja-JP; rv:1.0.2) Gecko/20030208 Netscape/7.02" + family: "Netscape" + major: '7' + minor: '02' + patch: + - user_agent_string: "Netscape 7.02" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.5; Windows NT 5.0) Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; X11; U; SunOS 5.8 sun4u) Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; ja-JP; rv:1.4) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Netscape7.1; Windows NT 5.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; rv:1.4; U) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; ja-JP; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:0.9.2) Gecko/20010726 Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; Localization; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.2) Gecko/20010726 Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; CDonDemand-Dom)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; PROMO)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) WebWasher 3.3" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; fr-FR; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; ja-JP; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; CDonDemand-Dom)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (CK-UKL)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010726 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010726 Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030603 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; CDonDemand-Dom)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) (CK-SillyDog)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; PROMO)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 StumbleUpon/1.906 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040210 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.1) Gecko/20040707 Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.2) Gecko/20010726 Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; BDP)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; CDonDemand-Dom)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) (CK-SillyDog)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax; PROMO)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Mozilla; Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041204 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr-FR; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.7) Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; ja-JP; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20040913 Mozilla/5.0 (Windows; U; Win98; en-US; Localization; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)/0.10 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.4) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 7.0; en-US; rv:1.7.3) Gecko/20040910 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; de-DE; rv:1.4) Gecko/20030619 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US) Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (CK-DNJ71R1)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.8a2) Gecko/20040527 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; fr-FR; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT; en-US; Localization; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; Windows NT 5.1; .NET CLR) Gecko/20030624 Netscape/7.1 (ax)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686) Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.4) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040418 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux-2.6.4-4GB i686; en-US; m18;) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (BDP)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031007 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040324 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; rv:1.7.3) Gecko/20040913 Netscape/7.1" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/7.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010726 Netscape7/7.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape/7.1 (compatible; Linux; X11; de_DE; U) [Firefox 0.8]" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Netscape/7.1 [de] (Windows NT 5.1; U)" + family: "Netscape" + major: '7' + minor: '1' + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 5.5; Windows NT 5.0; PPC Mac OS X; en-us) Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 [en] (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050204 Netscape/7.2 (PowerBook)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b) Gecko/20050208 Netscape/7.2 (PowerBook)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031007 Netscape/7.2e6/6.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (OpenBSD; en-US) Gecko/20030624 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; en-GB; rv:1.7.2) Gecko/20040804 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; Localization; rv:1.4) Gecko/20030624 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; nl-NL; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win 9x 4.90; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.2) Gecko/20010726 Netscape7/7.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax) Mnenhy/0.6.0.104" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; sk-SK; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.5) Gecko/20031007 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax [RLP])" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (Donzilla/0.2)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (Donzilla/0.6a)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (Donzilla/0.6a2)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 StumbleUpon/1.995 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040625 Netscape/7.2 (as)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040625 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.5) Gecko/20031007 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6 (Compatible with Netscape/7.2)) Gecko/20041027 Debian/1.6-5.1.0.45.lindows0.69" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040805 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.6) Gecko/20050306 Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Netscape 7.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Netscape/7.2" + family: "Netscape" + major: '7' + minor: '2' + patch: + - user_agent_string: "Netscape 7.2 (X11; I; Linux 2.4.18 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.2) Gecko/20050208 Netscape/7.20" + family: "Netscape" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040206 Netscape/7.3 (ax)" + family: "Netscape" + major: '7' + minor: '3' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.6) Gecko/20050225 Netscape/8.0" + family: "Netscape" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win98; en-US; Localization; rv1.4) Gecko20030624 Netscape7.1 (ax)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; NetVisualize b202)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/2.0 (compatible; NEWT ActiveX; Win32)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Nintendo64/1.0 (SuperMarioOS with Cray-II Y-MP Emulation)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Nintendo64/1.7 (SuperMarioOS with Sun 15K Y-MP Emulation)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NoctBrowser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Nokia 6600" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3100/1.0 (04.01) Profile/MIDP-1.0 Configuration/CLDC-1.0" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3200/1.0 (4.18) Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3200/1.0 () Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3220/2.0 (03.30) Profile/MIDP-2.0 Configuration/CLDC-1.1 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3410" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3510i/1.0 (04.01) Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3510i/1.0 (04.01) Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Link/5.1.1.5a (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3510i/1.0 (04.44) Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3510i/1.0 (05.30) Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3650" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3650/1.0 (4.13) SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3650/1.0 (4.17) SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3650/1.0 SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3650/1.0 SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia3650/1.0 SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Link/5.1.2.7 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6010/1.0 (8.18) Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6100" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6100/1.0 (05.16)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6100/1.0 (05.16) Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Link/1.1 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6100/1.0 (05.16) Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Link/mainline (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6600" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6600/1.0 (3.42.1) SymbianOS/7.0s Series60/2.0 Profile/MIDP-2.0 Configuration/CLDC-1.0" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6600/1.0 (3.42.1) SymbianOS/7.0s Series60/2.0 Profile/MIDP-2.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6600/1.0 (4.09.1) SymbianOS/7.0s Series60/2.0 Profile/MIDP-2.0 Configuration/CLDC-1.0" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6600/1.0 (4.09.1) SymbianOS/7.0s Series60/2.0 Profile/MIDP-2.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6600/1.0 SymbianOS" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6610/1.0 (5.63) Profile/MIDP-1.0 Configuration/CLDC-1.0" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6610I/1.0 (3.10) Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6610I/1.0 (3.10) Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Link/5.1.2.7 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6630" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6630/1.0 (3.45.113) SymbianOS/8.0 Series60/2.6 Profile/MIDP-2.0 Configuration/CLDC-1.1 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia6800" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia7250/1.0 (3.12) Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia7250/1.0 (3.14)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia7610/2.0 (3.0417.0ch) Symbian" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia7650" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "Nokia7650/1.0 SymbianOS/6.1 Series60/0.9 Profile/MIDP-1.0 Configuration/CLDC-1.0 (Google WAP Proxy/1.0)" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "NokiaN-Gage/1.0 (4.03) SymbianOS/6.1 Series60/0.9 Profile/MIDP-1.0 Configuration/CLDC-1.0" + family: "Nokia Services (WAP) Browser" + major: + minor: + patch: + - user_agent_string: "NP/0.1 (NP; http://www.nameprotect.com; npbot@nameprotect.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.01 (compatible; NPT 0.0 beta)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.01-beta (Nutch; http://www.nutch.org/docs/en/bot.html; nutch-agent@lists.sourceforge.net)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.03-dev (Nutch; http://www.nutch.org/docs/bot.html; nutch-agent@lists.sourceforge.net)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.03-dev (Nutch; http://www.nutch.org/docs/en/bot.html; nutch-agent@lists.sourceforge.net)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.06-dev (bot; http://www.nebel.de:8080/en/bot.html; nutch-agent@nebel.de)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.06-dev (bot; http://www.nebel.de/bot.html; nutch-agent@nebel.de)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.06-dev (Nutch; http://www.nutch.org/docs/en/bot.html; jagdeepssandhu@hotmail.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.06-dev (Nutch; http://www.nutch.org/docs/en/bot.html; nutch-agent@lists.sourceforge.net)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchCVS/0.06-dev (Nutch; http://www.s14g.com/en/search.html; travelbot@s14g.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NutchOSUOSL/0.05-dev (Nutch; http://www.nutch.org/docs/en/bot.html; nutch-agent@lists.sourceforge.net)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Nutscrape/1.0 (CP/M; 8-bit)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Nutscrape/9.0 (CP/M; 8-bit)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SEC-SGHC225-C225UVDH1-NW.Browser3.01 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "NWSpider 0.9" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ObjectsSearch/0.01 (ObjectsSearch; http://www.ObjectsSearch.com/bot.html; support@thesoftwareobjects.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ObjectsSearch/0.06 (ObjectsSearch; http://www.ObjectsSearch.com/bot.html; support@thesoftwareobjects.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ObjectsSearch/0.07 (ObjectsSearch; http://www.ObjectsSearch.com/bot.html; support@thesoftwareobjects.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (compatible; OffByOne; Windows 2000)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (compatible; OffByOne; Windows 2000) Webster Pro V3.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (compatible; OffByOne; Windows 2000) Webster Pro V3.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (compatible; OffByOne; Windows 98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (compatible; OffByOne; Windows 98) Webster Pro V3.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.7 (compatible; OffByOne; Windows NT 4.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.5 (compatible; OmniWeb/4.1.1-v423; Mac_PowerPC)" + family: "OmniWeb" + major: '4' + minor: '1' + patch: '1' + - user_agent_string: "Mozilla/4.5 (compatible; OmniWeb/4.3-v435; Mac_PowerPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Opera" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Opera/ (X11; Linux i686; U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (BeOS R4.5;US) Opera 3.60 [en]" + family: "Opera" + major: '3' + minor: '60' + patch: + - user_agent_string: "Mozilla/3.0 (Windows 3.10;US) Opera 3.62 [en]" + family: "Opera" + major: '3' + minor: '62' + patch: + - user_agent_string: "Mozilla/4.71 (Windows 3.10; US) Opera 3.62 [en]" + family: "Opera" + major: '3' + minor: '62' + patch: + - user_agent_string: "Mozilla/4.71 (Windows 3.10;US) Opera 3.62 [en]" + family: "Opera" + major: '3' + minor: '62' + patch: + - user_agent_string: "Mozilla/4.71 (Windows 98;US) Opera 3.62 [en]" + family: "Opera" + major: '3' + minor: '62' + patch: + - user_agent_string: "Mozilla/4.72 (Windows 98;US) Opera 4.0 Beta 3 [en]" + family: "Opera" + major: '4' + minor: '0' + patch: + - user_agent_string: "Opera/4.02 (Windows 98; U) [en]" + family: "Opera" + major: '4' + minor: '02' + patch: + - user_agent_string: "Opera/4.03 (Windows NT 4.0; U)" + family: "Opera" + major: '4' + minor: '03' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh;US;PPC) Opera 5.0 [en]" + family: "Opera" + major: '5' + minor: '0' + patch: + - user_agent_string: "Opera/5.01 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '5' + minor: '01' + patch: + - user_agent_string: "Opera/5.02 (alpha 06; AmigaOS) [en]" + family: "Opera" + major: '5' + minor: '02' + patch: + - user_agent_string: "Opera/5.02 (Windows 98; U) [en]" + family: "Opera" + major: '5' + minor: '02' + patch: + - user_agent_string: "Opera/5.02 (Windows 98; U) [en]" + family: "Opera" + major: '5' + minor: '02' + patch: + - user_agent_string: "Opera/5.02 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '5' + minor: '02' + patch: + - user_agent_string: "Opera/5.02 (X11; U; Linux i686; en-US)" + family: "Opera" + major: '5' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 5.12 [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 5.12 [es]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95) Opera 5.12 [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 5.12 [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows ME) Opera 5.12 [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.1) Opera 5.12 [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 5.12 [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 5.12 [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Opera/5.12 (Windows 2000; U) [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Opera/5.12 (Windows 98; U) [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Opera/5.12 (Windows NT 4.0; U) [fr]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Opera/5.12 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '5' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.18-4GB i686) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.18-4 i686) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Linux) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC) Opera 6.0 [ja]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Symbian OS; Series 90) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 95) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows ME; U) Opera 6.0 [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Opera/6.00 (Windows 98; U) [en]" + family: "Opera" + major: '6' + minor: '00' + patch: + - user_agent_string: "Opera/6.0 (Macintosh; PPC Mac OS X; U) [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Opera/6.0 (Windows 2000; U) [de]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Opera/6.0 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Opera/6.0 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Opera/6.0 (Windows 98; U) [en]" + family: "Opera" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.01 [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.01 [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.01 [es]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows ME) Opera 6.01 [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 4.0) Opera 6.01 [en] WebWasher 3.3" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.01 [de]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.01 [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.01 [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.01 [es]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.78 (Windows 2000; U) Opera 6.01 [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/5.0 (Windows XP; U) Opera 6.01 [en]\"" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Opera/6.01 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Opera/6.01 (Windows ME; U) [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Opera/6.01 (Windows XP; U) [en]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Opera/6.01 (Windows XP; U) [ru]" + family: "Opera" + major: '6' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.02 [en]" + family: "Opera" + major: '6' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS) Opera 6.02 [en]" + family: "Opera" + major: '6' + minor: '02' + patch: + - user_agent_string: "Mozilla/5.0 (Linux 2.4.26 i586; U) Opera 6.02 [en]" + family: "Opera" + major: '6' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.24 i686) Opera 6.03 [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Linux) Opera 6.03 [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.03 [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.03 [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Opera/6.03 (Linux 2.4.19-64GB-SMP i686; U) [de]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Opera/6.03 (Linux 2.4.19 i686; U) [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Opera/6.03 (OpenBSD 3.2 i386; U) [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Opera/6.03 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Opera/6.03 (Windows 98; U) [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Opera/6.03 (Windows ME; U) [ja]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Opera/6.03 (Windows XP; U) [en]" + family: "Opera" + major: '6' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.04 [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.04 [en-GB]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.04 [en-GB]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows ME) Opera 6.04 [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.04 [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 6.04 [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Opera/6.04 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Opera/6.04 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Opera/6.04 (Windows 2000; U) [en-GB]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Opera/6.04 (Windows 98; U) [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Opera/6.04 (Windows 98; U) [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Opera/6.04 (Windows 98; U) [en-GB]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Opera/6.04 (Windows XP; U) [en]" + family: "Opera" + major: '6' + minor: '04' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.05 [de]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.05 [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.05 [it]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.05 ~ [~ [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.05 [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.05 [es]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.05 OCV2 [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 4.0) Opera 6.05 [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.05 [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.05 [hu]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 2000; U) Opera 6.05 [de]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/5.0 (Windows XP; U) Opera 6.05 [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Opera/6.05 (Windows 2000; U) [de]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Opera/6.05 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Opera/6.05 (Windows 98; U) [de]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Opera/6.05 (Windows 98; U) [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Opera/6.05 (Windows 98; U) [en] WebWasher 3.0" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Opera/6.05 (Windows XP; U) [de]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Opera/6.05 (Windows XP; U) [en]" + family: "Opera" + major: '6' + minor: '05' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.06 [de]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.06 [en]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.06 [bg]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.06 [en]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 6.06 [en] (www.proxomitron.de)" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.06 [en]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 2000; U) Opera 6.06 [en]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Opera/6.06 (Windows 2000; U) [en]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Opera/6.06 (Windows 98; U) [de]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Opera/6.06 (Windows 98; U) [en]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Opera/6.06 (Windows 98; U) [en] (www.proxomitron.de)" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Opera/6.06 (Windows XP; U) [en]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Opera/6.06 (Windows XP; U) [ja]" + family: "Opera" + major: '6' + minor: '06' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.2 i386) Opera 6.1 [en]" + family: "Opera" + major: '6' + minor: '1' + patch: + - user_agent_string: "Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS; Nokia 6600;423) Opera 6.10 [de]" + family: "Opera" + major: '6' + minor: '10' + patch: + - user_agent_string: "Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS; Nokia 7650;424) Opera 6.10 [de]" + family: "Opera" + major: '6' + minor: '10' + patch: + - user_agent_string: "Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS; Series 60;424) Opera 6.10 [en]" + family: "Opera" + major: '6' + minor: '10' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; FreeBSD 4.4-RELEASE i386) Opera 6.11 [en]" + family: "Opera" + major: '6' + minor: '11' + patch: + - user_agent_string: "Mozilla/5.0 (UNIX; U) Opera 6.11 [en]" + family: "Opera" + major: '6' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; FreeBSD 5.3-RC2 i386) Opera 6.12 [en]" + family: "Opera" + major: '6' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; Linux 2.4.22 i686) Opera 6.12 [en]" + family: "Opera" + major: '6' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; UNIX) Opera 6.12 [en]" + family: "Opera" + major: '6' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.78 (FreeBSD 5.0-RELEASE-p7 i386; U) Opera 6.12 [en]" + family: "Opera" + major: '6' + minor: '12' + patch: + - user_agent_string: "Opera/6.12 (FreeBSD 4.8-RELEASE i386; U) [en]" + family: "Opera" + major: '6' + minor: '12' + patch: + - user_agent_string: "Opera/6.12 (UNIX; U) [en]" + family: "Opera" + major: '6' + minor: '12' + patch: + - user_agent_string: "Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS; Nokia 6600;451) Opera 6.20 [en]" + family: "Opera" + major: '6' + minor: '20' + patch: + - user_agent_string: "Opera/7 (Windows 98; U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Opera/7.x (compatible; Konqueror/2.2.2; Linux 2.8.4-rc1; X11; i686)" + family: "Konqueror" + major: '2' + minor: '2' + patch: '2' + - user_agent_string: "Opera/7.x (Windows NT 5.1; U) [hr]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0(DDIPOCKET;KYOCERA/AH-K3001V/1.1.17.65.000000/0.1/C100) Opera 7.0" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows 2000) Opera 7.0 [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows 98) Opera 7.0 [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.0) Opera 7.0 [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.0 [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows XP) Opera 7.0 [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 Opera/7.0 (X11; U; Linux i686; de-DE; rv:1.6) Gecko/20040114" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 2000; U) Opera 7.0 [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Opera/7.00 (Windows NT 5.0; U)" + family: "Opera" + major: '7' + minor: '00' + patch: + - user_agent_string: "Opera/7.0 (Windows 2000; U) [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Opera/7.0 (Windows 2000; U) [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Opera/7.0 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows 98) Opera 7.01 [en]" + family: "Opera" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows 98) Opera 7.01 [ru]" + family: "Opera" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows ME) Opera 7.01 [en]" + family: "Opera" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.0) Opera 7.01 [en]" + family: "Opera" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.01 [en]" + family: "Opera" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.01 [ru]" + family: "Opera" + major: '7' + minor: '01' + patch: + - user_agent_string: "Opera/7.01 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '01' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows 98) Opera 7.02 [en]" + family: "Opera" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows ME) Opera 7.02 [en]" + family: "Opera" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.0) Opera 7.02 [en]" + family: "Opera" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.02 [en]" + family: "Opera" + major: '7' + minor: '02' + patch: + - user_agent_string: "Opera/7.02 Bork-edition (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '02' + patch: + - user_agent_string: "Opera/7.02 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '02' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows 98) Opera 7.03 [en]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.0) Opera 7.03 [en]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.0) Opera 7.03 [ja]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.03 [en]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.03 [ru]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Opera/7.03 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Opera/7.03 (Windows NT 5.0; U) [de]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Opera/7.03 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Opera/7.03 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Opera/7.03 (Windows NT 5.0; U) [nl]" + family: "Opera" + major: '7' + minor: '03' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.10 [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.10 [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.10 [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Opera/7.10 (Linux 2.4.20 i686; U) [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Opera/7.10 (Windows ME; U) [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Opera/7.10 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Opera/7.10 (Windows NT 5.0; U) [en] (www.proxomitron.de)" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Opera/7.10 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Opera/7.10 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '10' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Linux 2.4.18-bf2.4 i686) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Linux 2.4.20-8 i686) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Linux 2.4.26 i686) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Linux 2.4.2 i386) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Linux 2.6.6 i686) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.11 [es]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.11 [de]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.11 [es-ES]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.11 [pl]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.11 [ru]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/5.0 (Linux 2.4.20-openmosix-3 i686; U) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.11 [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Linux 2.4.18-xfs i686; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Linux 2.4.20-gentoo-r1 i686; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Linux 2.6.3-4mdk i686; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.0; U) [es]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.0; U) [it]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.0; U) [pl]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.0; U) [ru]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.1; U) [es]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Opera/7.11 (Windows NT 5.2; U) [en]" + family: "Opera" + major: '7' + minor: '11' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 95) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.20 [ja]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.20 [ru]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.20 [ja]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.20 [ru]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.20 [de]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.20 [sk]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.20 [ja]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.20 [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Opera/7.20 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Opera/7.20 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Opera/7.20 (Windows NT 5.1; U) [røv]" + family: "Opera" + major: '7' + minor: '20' + patch: + - user_agent_string: "Mozilla/3.0 (Windows 98; U) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.21 [pl]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.21 [fi]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.21 [de]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.21 [pl]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.21 [ru]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.21 [zh-cn]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i586) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.21 [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows 98; U) [de]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows NT 5.0; U) [it]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows NT 5.1; U) [fi]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Opera/7.21 (Windows NT 5.2; U) [en]" + family: "Opera" + major: '7' + minor: '21' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.22 [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.22 [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.22 [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.22 [fr]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.22 [pl]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.22 [de]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.22 [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.22 [es-ES]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.22 [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.22 [fr]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.22 [de]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Opera/7.22 (Windows NT 5.0; U) [de] WebWasher 3.3" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Opera/7.22 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Opera/7.22 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Opera/7.22 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Opera/7.22 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '22' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Linux) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.23 [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.23 [en-GB]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.23 [es-ES]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.23 [es-LA]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.23 [hu]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.23 [nl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.23 [en] WebWasher 3.3" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.23 [es-LA]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.23 [pl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.23 [ru]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.23 [fr]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [en-GB]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [es-ES]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [fr]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [it]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [ja]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [nb]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [pl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [ru]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.23 [sv]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [cs]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [en-GB]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [es-ES]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [es-LA]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [fr]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [it]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [ja]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [nb]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [nl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [pl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [pt-BR]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [ru]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [sv]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [zh-cn]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.23 [zh-tw] WebWasher 3.3" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.23 [pl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.23 [ru]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.23 [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.23 [es-ES]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.23 [ru]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; SunOS sun4u) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; SunOS sun4u) Opera 7.23 [ja]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 4.0; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.0; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.78 (X11; FreeBSD i386; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Opera 7.23; Windows NT 5.1)" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 7.23 [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows ME; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.23 [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.23 [et]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (X11; FreeBSD i386; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.23 [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.23 [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (compatible; MSIE 6.0; X11; Linux i586) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Linux 2.4.24-ck1 i686; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows 98; U) [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows ME; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 4.0; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U)" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [en-GB]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [es-ES]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [es-LA]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [pl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [ru]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.0; U) [tr]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [cs]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [da]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [en-GB]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [es]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [es-LA]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [fi]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [fr]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [ja]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [ru]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [sv]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [tr]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.1; U) [zh-tw]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (Windows NT 5.2; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; FreeBSD i386; U) [bg]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; Linux i386; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; Linux i686; U) [de]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; Linux i686; U) [en-GB]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; Linux i686; U) [es-ES]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; Linux i686; U) [fi]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; Linux i686; U) [sv]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Opera/7.23 (X11; SunOS sun4u; U) [en]" + family: "Opera" + major: '7' + minor: '23' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Qt embedded; Linux armv5tel; 640x480) Opera 7.30 [en]" + family: "Opera" + major: '7' + minor: '30' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Opera 7.30; Irax)" + family: "Opera" + major: '7' + minor: '30' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.0; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/3.0 (X11; SunOS sun4u; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Mac_PowerPC) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 2000; Opera 7.50 [en])" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.50 [ru]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.50 [ru]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.50 [sv]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.50 [de]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.50 [IT]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.50 [pl]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.50 [ru]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.50 [de] (www.proxomitron.de)" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.50 [es-ES]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; SunOS sun4u) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.78 (Windows 98; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.0; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/4.78 (X11; Linux i686; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.50 [ru]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.50 [ru]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/5.0 (X11; FreeBSD i386; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.50 [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.50 [es-LA]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Macintosh; U; PPC Mac OS X 10.3.3; en-US; rv:1.1 ) via HTTP/1.0 offshore.unitedbanks.org/" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows 95; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows 98; U) [en-US]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.0; U) [cs]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.0; U) [pl]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.0; U) [ru]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.1; U) [en-GB]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (Windows NT 5.2; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (X11; FreeBSD i386; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Opera/7.50 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '50' + patch: + - user_agent_string: "Mozilla/3.0 (X11; Linux i686; U) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.23; Mac_PowerPC) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.51 [cs]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.51 [ru]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.51 [de]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux ppc) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.78 (X11; Linux i686; U) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/5.0 (Windows ME; U) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.51 [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Linux) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Mac_PowerPC; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows 95; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows 98; U) [de]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows ME; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows NT 4.0; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows NT 5.0; U) [de]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows NT 5.1; U) [fr]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (X11; Linux i686; U) [de]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (X11; Linux i686; U) [fi]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Opera/7.51 (X11; SunOS sun4u; U) [en]" + family: "Opera" + major: '7' + minor: '51' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.52 [pl]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.52 [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.52 [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.52 [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.52 [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.52 [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/4.78 (X11; Linux i686; U) Opera 7.52 [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.52 [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Macintosh; PPC Mac OS X; U) [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.0; U) [en] WebWasher 3.3" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.1; U) [nb]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (Windows NT 5.2; U) [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Opera/7.52 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '52' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.53 [da]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.53 [ja]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.53 [de]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.53 [es-ES]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.53 [ja]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.0; U) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.53 [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows NT 5.0; U) [de]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows NT 5.0; U) [ja]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows NT 5.1; U) [ja]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (Windows XP; U) [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Opera/7.53 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '53' + patch: + - user_agent_string: "Mozilla/3.0 (Windows 98; U) Opera 7.54 [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.0; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.1; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.1; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.1; U) Opera 7.54 [es-ES]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.1; U) Opera 7.54 [sv]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.1; U) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.23; Mac_PowerPC) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.23; Mac_PowerPC) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 95) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.54 [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.54 [fr]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.54 [nb]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.54 [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98) Opera 7.54u1 [nl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME) Opera 7.54u1 [hu]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 4.0) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [es-ES]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [fi]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [fr]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [IT]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [ja]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54 [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54u1 [fr]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.54u1 [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [bg]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [cs]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [da]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [de],gzip(gfe) (via translate.google.com)" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [es-ES]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [et]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [fi]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [fr]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [hu]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [it]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [IT]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [nb]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [nl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [pt-BR]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54u1 [ja]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54u1 [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.54 [ru]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.54 [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera 7.54 [it]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; SunOS sun4u) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/4.78 (X11; Linux i686; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; PPC Mac OS X; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows 98; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows ME; U) Opera 7.54 [ja]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.54 [it]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.54u1 [en] WebWasher 3.0" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.54 [ca]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.54 [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.54 [sv]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.54u1 [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.54u1 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (X11; FreeBSD i386; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U) Opera 7.54 [fr]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux x86_64; U) Opera 7.54 [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Amiga) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (AmigaOS 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (FreeBSD; U)" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Linux 2.4.18-xfs i686; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Linux) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Macintosh; PPC Mac OS X; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera 7.54 (Macintosh; U; PPC Mac OS X v10.4 Tiger ) via HTTP/1.0 deep.space.star-travel.org/" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows 98; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows ME; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 4.0; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 4.0; U) [en] WebWasher 2.2.1" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.0; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.0; U) [ja]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.1; U) [hu]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.1; U) [ja]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.1; U) [pt-BR]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows NT 5.2; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54u1 (Windows; U)" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Unix; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows 95; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows 98; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows 98; U) [es-ES]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows 98; U) [hu]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows 98; U) [nl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows 98; U) [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows ME; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows ME; U) [es-ES]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 4.0; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 4.0; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 4.0; U) [es-ar]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [fi]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [fr]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U; have a nice day :) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U; have a nice day;) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [ja]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.0; U) [sv]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1)" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [cs]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [es-ES]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [fr]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [hu]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [it]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [IT]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [nb]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [nl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [ru]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows NT 5.1; U) [sv]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (Windows; U)" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; FreeBSD i386; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i386; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i586; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i686; U)" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i686; U) [cs]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i686; U) [de]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i686; U) [nl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i686; U) [pl]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; Linux i686; U) [sv]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; SunOS sun4u; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; SunOS sun4u; U) [en]" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Opera/7.54 (X11; U; Linux i686; fr-FR; rv:1.5)" + family: "Opera" + major: '7' + minor: '54' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.1; U) Opera 7.60 [de] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/3.0 (Windows NT 5.1; U) Opera 7.60 [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; en) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; en) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; es) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.60 [en]" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.60 [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.60 [nl] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; pl) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; en) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; IT) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.60 [de] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.78 (Windows NT 5.1; U) Opera 7.60 [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U) Opera 7.60 [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U; pl) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U; en) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.60 [de] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U) Opera 7.60 [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U; pl) Opera 7.60" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera 7.60 (FreeBSD i686; U) [en] via HTTP/1.0 foot.fetish-expert.org/" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera 7.60 (Linux 2.4.10-4GB i686; U)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera 7.60 (Linux 2.4.8-26mdk i686; U) [en] FreeSurf tmfweb.nl v1.1 via HTTP/1.0 vienna.unitedworldcouncil.org/" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 preview 4 (Mac OS X 10.3)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows 98; U; pl)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera 7.60 (Windows NT 4.0; U) [en] via HTTP/1.0 l33t0-HaX0r.hiddenip.com/" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.0; U; en)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.0; U; ja)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.0; U; ja),gzip(gfe) (via translate.google.com)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.0; U; pl)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.1; U; de)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.1; U) [de] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.1; U; en)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.1; U) [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.1; U) [pl]" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.1; U) [pl] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.2; U; en)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.2; U) [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (Windows NT 5.2; U) [en] (IBM EVV/3.0/EAK01AG9/LE)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera 7.60 (X11; Linux i386; U) [en] via HTTP/1.0 evil-uncle.trojanchecker.com/" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (X11; Linux i686; U; en)" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Opera/7.60 (X11; Linux i686; U) [en]" + family: "Opera" + major: '7' + minor: '60' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Mac_PowerPC Mac OS X; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows ME; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; de) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; en) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; cs) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; de) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; hu) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; en) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; IT) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686; pl) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux ppc; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.0; U; ru) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/5.0 (Windows NT 5.1; U; en) Opera 8.00" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Mozilla/5.0 (X11; Linux i686; U; en) Opera 8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.00 (Windows 98; U; de)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.0; U)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.0; U; de)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.0; U; en)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.0; U; pl)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.1; U; bg)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.1; U; cs)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.1; U; de)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.1; U; en)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.1; U; es)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.1; U; Mockingbird)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows NT 5.2; U; en)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.00 (Windows; U)" + family: "Opera" + major: '8' + minor: '00' + patch: + - user_agent_string: "Opera/8.0 (Macintosh; PPC Mac OS X; U; en)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (Windows 98; U; en)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (Windows ME; U; en)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (Windows NT 5.0; U; en)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (Windows NT 5.1; U; de)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (Windows NT 5.1; U; en)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (Windows NT 5.1; U; pl)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (Windows NT 5.2; U; en)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (X11; Linux i686; U; en)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Opera/8.0 (X11; Linux i686; U; pt-BR)" + family: "Opera" + major: '8' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Opera 8.4; Windows ME; Maxthon; .NET CLR 1.1.4322)" + family: "Opera" + major: '8' + minor: '4' + patch: + - user_agent_string: "Operah" + family: "Other" + major: + minor: + patch: + - user_agent_string: "OZ Browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "P3P Client" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PenguinFear (compatible; windows ce;; Windows NT 5.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PHILIPS-Fisio311/2.1 UP/4.1.19m" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PHP/4.2.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PHP/4.2.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PhpDig/PHPDIG_VERSION (+http://www.phpdig.net/robot.php)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PHP version tracker" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (compatible; MSIE 6.0; Pike HTTP client) Pike/7.6.25" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "PinkSock/1.0 (eComStation 1.2; en-CA; rv:0.4.9) PinkSock/20040416" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PinkSock/1.1 [en] (X11; U; SunOS 5.9 i86)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PinkSock/1.2 [en_CA] (OpenBeOS 0.2 i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PinkSock/1.3 [en_CA] (X11; U; SunOS 5.10 i86)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PinkSock/1.4 [en_CA] (16-bit; U; DR-DOS 7.22)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "PinkSock/1.5 [en_CA] (X11R6.7.0; U; FreeBSD 4.10-RELEASE)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "pipeLiner/0.10 (PipeLine Spider; http://www.pipeline-search.com/webmaster.html)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "POE-Component-Client-HTTP/0.510 (perl; N; POE; en; rv:0.510)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Popdexter/1.0 (http://www.popdex.com/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "portalmmm/2.0_M341i(c10;TB)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Powermarks/3.5; Windows 95/98/2000/NT)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Privoxy/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Privoxy/3.0 (Anonymous)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Program Shareware 1.0.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Progressive Download" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Proxomitron (www.proxomitron.de)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "puf/0.93.2a (Linux 2.4.20-19.9; i686)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Python-urllib/1.15" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Python-urllib/2.0a1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Python-urllib/2.0a1, Dowser/0.26 (http://dowser.sourceforge.net)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Qarp-1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ReadAheadWebBrowserHost" + family: "Other" + major: + minor: + patch: + - user_agent_string: "RealDownload/4.0.0.40" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Reaper/2.07 (+http://www.sitesearch.ca/reaper)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "RPT-HTTPClient/0.3-3E" + family: "Other" + major: + minor: + patch: + - user_agent_string: "RT-browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SA/0.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Safari" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/01 (KHTML, like Gecko) Safari/01" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; cs-cz) AppleWebKit/103u (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/103u (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (macintosh; U; PPC mac OS X; en) AppleWebKit/103u (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/103u (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/103u (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/103u (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/106.2 (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/103u (KHTML, like Gecko) Safari/100" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/103u (KHTML, like Gecko) Safari/100.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/106.2 (KHTML, like Gecko) Safari/100.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/106.2 (KHTML, like Gecko) Safari/100.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-es) AppleWebKit/106.2 (KHTML, like Gecko) Safari/100.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Safari 1.2 (Macintosh; U; PPC Mac OS X; en-us)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/124 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/146.1 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/124 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/185 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/124 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-au) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-es) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fi-fi) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; is-is) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/124 (KHTML, like Gecko) Safari/125.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; el-gr) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-es) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; da-dk) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-at) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-au) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-au) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-ca) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-ca) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-es) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-es) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-ca) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; he-il) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; is-is) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; no-no) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/125.5.7 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; th-th) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; zh-tw) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; zh-tw) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (000000000; 0; 000 000 00 0; 00) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.2.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es-es) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; is-is) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ru-ru) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.4.2 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; is-is) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/125.5 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; no-no) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; pt-pt) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/125.4 (KHTML, like Gecko) Safari/125.9" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/175 (KHTML, like Gecko) Safari/1.3" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/146.1 (KHTML, like Gecko) Safari/146" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/146 (KHTML, like Gecko) Safari/146" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/146.1 (KHTML, like Gecko) Safari/146" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/146.1 (KHTML, like Gecko) Safari/146" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es) AppleWebKit/146.1 (KHTML, like Gecko) Safari/146" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/146.1 (KHTML, like Gecko) Safari/146" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/146.1 (KHTML, like Gecko) Safari/146" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/164 (KHTML, like Gecko) Safari/164" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/168 (KHTML, like Gecko) Safari/168" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/168 (KHTML, like Gecko) Safari/168" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/168 (KHTML, like Gecko) Safari/168" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/168 (KHTML, like Gecko) Safari/168" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/168 (KHTML, like Gecko) Safari/168" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/172 (KHTML, like Gecko) Safari/172" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/176 (KHTML, like Gecko) Safari/176" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/179 (KHTML, like Gecko) Safari/179" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/185 (KHTML, like Gecko) Safari/185" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/401 (KHTML, like Gecko) Safari/401" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/403 (KHTML, like Gecko) Safari/403" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/405 (KHTML, like Gecko) Safari/405" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/412 (KHTML, like Gecko) Safari/412" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/48 (like Gecko) Safari/48" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/64 (KHTML, like Gecko) Safari/64" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/73 (KHTML, like Gecko) Safari/73" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/85 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/85 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/85 (KHTML, like Gecko) Safari/85" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Windows; U; Win16; en-US; rv:1.7) Safari/85.5" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.6" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.6" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.6" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.6" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-au) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-gb) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; it-it) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sv-se) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.7" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-au) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/225 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; es) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fr-fr) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-au) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; nl-nl) AppleWebKit/85.8.2 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; sa) AppleWebKit/85.8.5 (KHTML, like Gecko) Safari/85.8.1" + family: "Safari" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppeWebKit/XX (KHTML, like Gecko) Safari/YY" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/XX (KHTML, like Gecko) Safari/YY" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SafariBookmarkChecker/1.27 (+http://www.coriolis.ch/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.0; SaferSurf; DigExt)" + family: "IE" + major: '5' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.5; SaferSurf; DigExt)" + family: "IE" + major: '5' + minor: '5' + patch: + - user_agent_string: "Satan 666 (7th level of Hell)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "savvybot/0.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Search-Channel" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SecretBrowser/007" + family: "Other" + major: + minor: + patch: + - user_agent_string: "S.E.K Tron (AmigaOS; alpha/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "S.E.K Tron (AmigaOS; alpha/06; AmigaOS 3.5; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "S.E.K Tron (AmigaOS; alpha/06; AmigaOS; .NET CLR 1.1.4322)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "S.E.K Tron (AmigaOS; alpha/06; Win98)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "S.E.K-Tron Systems" + family: "Other" + major: + minor: + patch: + - user_agent_string: "S.E.K-Tron Systems(compatible; MSIE 6.0; Matrix; SEK-Tron Systems; Windows NT 5.0)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "SEK Tron (AmigaOS; alpha/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "S.E.K-Tron Systems(compatible; MSIE 6.0; Matrix; SEK-Tron Systems; AmigaOS)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "S.E.K-Tron Systems(SEK-Tron; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SHARP-TQ-GX10" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SHARP-TQ-GX30" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Shockwave Flash" + family: "Other" + major: + minor: + patch: + - user_agent_string: "ShowLinks/1.0 libwww/5.4.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SIE-S55/16" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Simpy/1.1 (Simpy; http://www.simpy.com/?ref=bot; feedback at simpy dot com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SISLink" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SiteBar/3.2.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 6.0; Slackware)" + family: "IE" + major: '6' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; SmartPhone; Symbian OS/1.1.0) NetFront/3.1" + family: "NetFront" + major: '3' + minor: '1' + patch: + - user_agent_string: "Smurf Power" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Snoopy v1.01" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Snowstorm/0.1.0 (windows; U; SnowStep0.6.0; en-us) Gecko/20201231" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Solar Conflict (www.solarconflict.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "sony ericsson" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonP800/" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonP900/" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonP900/ UP.Link/5.1.2.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT230/R101 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT306/R101 UP.Link/1.1 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT616" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SonyEricssonT68/R502 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Sopheus Project/0.01 (Nutch; http://www.thenetplanet.com; info@thenetplanet.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SpaceBison/0.01 [fu] (Win67; X; Lolzor)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SpaceBison/0.01 [fu] (Win67; X; ShonenKnife)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Space Bison/0.02 [fu] (Win67; X; SK)" + family: "Space Bison" + major: '0' + minor: '02' + patch: + - user_agent_string: "Space Bison/0.69 [fu] (Win72; incompatible)" + family: "Space Bison" + major: '0' + minor: '69' + patch: + - user_agent_string: "SpiderMan 3.0.1-2-11-111 (CP/M;8-bit)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SquidClamAV_Redirector 1.6" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Squid-Prefetch" + family: "Other" + major: + minor: + patch: + - user_agent_string: "StackRambler/2.0 (MSIE incompatible)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "StarDownloader/1.44" + family: "Other" + major: + minor: + patch: + - user_agent_string: "StarDownloader/1.52" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Steeler/2.0 (http://www.tkl.iis.u-tokyo.ac.jp/~crawler/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; SuperCleaner 2.81; Windows NT 5.1)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Supergrass (GNU/Windows; U) [sr]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SuperMarioBrowser/3.0 [en] (NintendoOS 0.4.27)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SuperMarioBrowser/3.0 (WarioOS; U; WarioWare 2.1.4; en-US)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "SymbianOS/6.1 Series60/1.2 Profile/MIDP-" + family: "Nokia OSS Browser" + major: '1' + minor: '2' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; Synapse)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Teleport Pro/1.29" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Teleport Pro/1.29.1590" + family: "Other" + major: + minor: + patch: + - user_agent_string: "TheBlacksheepbrowser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "theConcept/1.0 (Macintosh)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "theConcept/1.1 (Macintosh)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Toaster/2.0 (X11; U; BeOS i786; en, de; rv:7.8.9) Gecko/20250223 Toaster/2.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Tutorial Crawler 1.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "TygoProwler (http://www.tygo.com/)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "UP.Browser/3.1.02-SC01 UP.Link/5.0.2.9 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '3' + minor: '1' + patch: '02' + - user_agent_string: "OWG1 UP/4.1.20a UP.Browser/4.1.20a-XXXX UP.Link/5.1.2.12 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '4' + minor: '1' + patch: '20' + - user_agent_string: "QC2135 UP.Browser/4.1.22b UP.Link/4.2.1.8 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '4' + minor: '1' + patch: '22' + - user_agent_string: "MOT-85/01.04 UP.Browser/4.1.26m.737 UP.Link/5.1.2.12 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '4' + minor: '1' + patch: '26' + - user_agent_string: "MOT-A-0A/00.06 UP.Browser/4.1.27a1 UP.Link/4.2.3.5h" + family: "UP.Browser" + major: '4' + minor: '1' + patch: '27' + - user_agent_string: "MOT-A-2D/00.02 UP.Browser/4.1.27a1 UP.Link/5.1.2.12 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '4' + minor: '1' + patch: '27' + - user_agent_string: "MOT-A-86/00.00 UP.Browser/4.1.27a1 UP.Link/4.2.3.5h (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '4' + minor: '1' + patch: '27' + - user_agent_string: "MOT-A-86/00.00 UP.Browser/4.1.27a1 UP.Link/5.1.2.12 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '4' + minor: '1' + patch: '27' + - user_agent_string: "Motorola-T33/1.5.1a UP.Browser/5.0.1.7.c.2 (GUI) (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '5' + minor: '0' + patch: '1' + - user_agent_string: "Alcatel-BG3/1.0 UP.Browser/5.0.3.1.2 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '5' + minor: '0' + patch: '3' + - user_agent_string: "KDDI/CA23/UP. Browser/6.0.2.254 (GUI) MMP/1.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Panasonic-G60/1.0 UP.Browser/6.1.0.7 MMP/1.0 UP.Browser/6.1.0.7 (GUI) MMP/1.0 UP.Link/5.1.1a (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SAGEM-myX-5m/1.0 UP.Browser/6.1.0.6.1.c.3 (GUI) MMP/1.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SAMSUNG-SGH-E700/BSI UP.Browser/6.1.0.6 (GUI) MMP/1.0" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SAMSUNG-SGH-E700/BSI UP.Browser/6.1.0.6 (GUI) MMP/1.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SAMSUNG-SGH-E700-OLYMPIC2004/1.0 UP.Browser/6.1.0.6 (GUI) MMP/1.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SAMSUNG-SGH-X600/K3 UP.Browser/6.1.0.6 (GUI) MMP/1.0" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SIE-C60/12 UP.Browser/6.1.0.5.c.6 (GUI) MMP/1.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SIE-M55/11 Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Browser/6.1.0.7.3 (GUI) MMP/1.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SIE-MC60/10 Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Browser/6.1.0.7.3 (GUI) MMP/1.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SIE-MC60/10 Profile/MIDP-1.0 Configuration/CLDC-1.0 UP.Browser/6.1.0.7.3 (GUI) MMP/1.0 UP.Link/5.1.1.5a" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SIE-S55/11 UP.Browser/6.1.0.5.c.2 (GUI) MMP/1.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "SIE-S55/20 UP.Browser/6.1.0.5.c.6 (GUI) MMP/1.0 UP.Link/1.1 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "UP.Browser/6.1.0.1.140 (Google CHTML Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '1' + patch: '0' + - user_agent_string: "KDDI-HI32 UP.Browser/6.2.0.5 (GUI) MMP/2.0" + family: "UP.Browser" + major: '6' + minor: '2' + patch: '0' + - user_agent_string: "SHARP-TQ-GX20/1.0 UP.Browser/6.2.0.1.185 (GUI) MMP/2.0" + family: "UP.Browser" + major: '6' + minor: '2' + patch: '0' + - user_agent_string: "OPWV-SDK/62 UP.Browser/6.2.2.1.208 (GUI) MMP/2.0" + family: "UP.Browser" + major: '6' + minor: '2' + patch: '2' + - user_agent_string: "VM4050/132.037 UP.Browser/6.2.2.4.e.1.100 (GUI) MMP/2.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" + family: "UP.Browser" + major: '6' + minor: '2' + patch: '2' + - user_agent_string: "LGE-VX7000/1.0 UP.Browser/6.2.3.1.174 (GUI) MMP/2.0 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '6' + minor: '2' + patch: '3' + - user_agent_string: "SIE-CX65/12 UP.Browser/7.0.0.1.c.3 (GUI) MMP/2.0 Profile/MIDP-2.0 Configuration/CLDC-1.1 (Google WAP Proxy/1.0)" + family: "UP.Browser" + major: '7' + minor: '0' + patch: '0' + - user_agent_string: "SIE-S65/25 UP.Browser/7.0.0.1.c.3 (GUI) MMP/2.0 Profile/MIDP-2.0 Configuration/CLDC-1.1" + family: "UP.Browser" + major: '7' + minor: '0' + patch: '0' + - user_agent_string: "SEC-SGHX427M UP.Link/1.1 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Uptimebot" + family: "Other" + major: + minor: + patch: + - user_agent_string: "UptimeBot" + family: "Other" + major: + minor: + patch: + - user_agent_string: "User-Agent: Mozilla/5.0 (Windows; U; Windows; de-DE; rv:1.7.5)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "UserAgent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7b) Gecko/20040329" + family: "Other" + major: + minor: + patch: + - user_agent_string: "User-Agent: S.E.K Tron (AmigaOS; alpha/06; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Veczilla/0.35beta (X11; U; UNICOS/mk 21164a(EV5.6) Cray T3E; en-US; m18) Gecko/20020202 Netscape6/6.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Veczilla/0.35beta (X11; U; UNICOS/mk 21164a(EV5.6) Cray T3E; en-US; m18) Gecko/20040329" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/5.5 (compatible; Voyager; AmigaOS)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "W32/Trojan.Coced.226" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Emacs-W3/4.0pre.46 URL/p4.0pre.46 (i386-suse-linux; X11)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.3" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.3.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.3.1+cvs-1.411" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.3.1+cvs-1.414" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.3.2+mee-p24-19+moe-1.5.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.4.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.4.1-m17n-20030308" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.4.2" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.5" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.5+cvs-1.916" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.5 (FreeBSD),gzip(gfe) (via translate.google.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "w3m/0.5.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WannaBe (Macintosh; PPC)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Wap" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WAP" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Web Browser" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; WebCapture 2.0; Auto; Windows)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; WebCapture 2.0; Windows)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WebCatSv" + family: "Other" + major: + minor: + patch: + - user_agent_string: "webcollage/1.114" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WebForm 1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/6.0 (compatible; WebGod 9.1; Windows NT 6.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WebHopper" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 (compatible; WebMon 1.0.10; Windows 98 SE)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WebPix 1.0 (www.netwu.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WebRescuer v0.2.4" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WebStripper/2.20" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WebStripper/2.58" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/3.0 WebTV/1.2 (compatible; MSIE 2.0)" + family: "IE" + major: '2' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 4.0; WebTV/2.6)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 WebTV/2.6 (compatible; MSIE 4.0)" + family: "IE" + major: '4' + minor: '0' + patch: + - user_agent_string: "WebZIP/4.1 (http://www.spidersoft.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "wget 1.1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Wget/1.8.2 modified" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Wget/1.9+cvs-stable (Red Hat modified)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 5.00; Window 98)" + family: "IE" + major: '5' + minor: '00' + patch: + - user_agent_string: "WinHTTP Example/1.0" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WinWAP-PRO/3.1 (3.1.5.190) UP.Link/5.1.2.5 (Google WAP Proxy/1.0)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WM2003/1 (Windows CE 3.0; U) [en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WordPress/1.2.1 PHP/4.3.9-1" + family: "Other" + major: + minor: + patch: + - user_agent_string: "WorldWideWeb-X/3.2 (+Web Directory)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Wotbox/0.7-alpha (bot@wotbox.com; http://www.wotbox.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Wotbox/alpha0.6 (bot@wotbox.com; http://www.wotbox.com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "www.WebSearch.com.au" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 9.0b; Xbox-OS2) Obsidian" + family: "IE" + major: '9' + minor: '0' + patch: + - user_agent_string: "Mozilla/4.0 (compatible; MSIE 7.0b; Xbox-OS2) Obsidian" + family: "IE" + major: '7' + minor: '0' + patch: + - user_agent_string: "XBoX 64 (NVidea GForce 3 Architecture)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Xtreme Browser/0.14 (Linux; U) [i386-en]" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Yahoo-MMAudVid/1.0 (mms dash mmaudvidcrawler dash support at yahoo dash inc dot com)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "Yandex/1.01.001 (compatible; Win16; I)" + family: "Other" + major: + minor: + patch: + - user_agent_string: "YottaShopping_Bot/4.12 (+http://www.yottashopping.com) Shopping Search Engine" + family: "Other" + major: + minor: + patch: diff --git a/node_modules/useragent/test/fixtures/static.custom.yaml b/node_modules/useragent/test/fixtures/static.custom.yaml new file mode 100644 index 0000000..bacf1a0 --- /dev/null +++ b/node_modules/useragent/test/fixtures/static.custom.yaml @@ -0,0 +1,13 @@ +test_cases: + + - user_agent_string: 'curl/7.12.1 (i686-redhat-linux-gnu) libcurl/7.12.1 OpenSSL/0.9.7a zlib/1.2.1.2 libidn/0.5.6' + family: 'cURL' + major: '7' + minor: '12' + patch: '1' + + - user_agent_string: 'Wget/1.10.1 (Red Hat modified)' + family: 'Wget' + major: '1' + minor: '10' + patch: '1' diff --git a/node_modules/useragent/test/fixtures/testcases.yaml b/node_modules/useragent/test/fixtures/testcases.yaml new file mode 100644 index 0000000..d60c886 --- /dev/null +++ b/node_modules/useragent/test/fixtures/testcases.yaml @@ -0,0 +1,389 @@ +test_cases: + + - user_agent_string: 'Mozilla/5.0 (X11i; Linux; C) AppleWebKikt/533.3 (KHTML, like Gecko) QtCarBrowser Safari/533.3' + family: 'QtCarBrowser' + major: '1' + minor: + patch: + + - user_agent_string: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/537.8+ (KHTML, like Gecko) Version/6.0 Safari/536.25' + family: 'WebKit Nightly' + major: '537' + minor: '8' + patch: + + - user_agent_string: 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534+ (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22' + family: 'WebKit Nightly' + major: '534' + minor: + patch: + + - user_agent_string: 'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)' + family: 'FacebookBot' + major: '1' + minor: '1' + patch: + + - user_agent_string: 'Pingdom.com_bot_version_1.4_(http://www.pingdom.com/)' + family: 'PingdomBot' + major: '1' + minor: '4' + patch: + + - user_agent_string: 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534+ (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22' + family: 'WebKit Nightly' + major: '534' + minor: + patch: + + - user_agent_string: 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1+ (KHTML, like Gecko) Version/5.1.1 Safari/534.51.22' + family: 'WebKit Nightly' + major: '537' + minor: '1' + patch: + + - user_agent_string: 'Mozilla/5.0 (Linux x86_64) AppleWebKit/534.26+ WebKitGTK+/1.4.1 luakit/f3a2dbe' + family: 'LuaKit' + major: + minor: + patch: + + - user_agent_string: 'Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20110408 conkeror/0.9.3' + family: 'Conkeror' + major: '0' + minor: '9' + patch: '3' + + - user_agent_string: 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.16) Gecko/20110302 Conkeror/0.9.2 (Debian-0.9.2+git100804-1)' + family: 'Conkeror' + major: '0' + minor: '9' + patch: '2' + + + - user_agent_string: 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.17) Gecko/20110414 Lightning/1.0b3pre Thunderbird/3.1.10' + family: 'Lightning' + major: '1' + minor: '0' + patch: 'b3pre' + + - user_agent_string: 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.17) Gecko/20110414 Thunderbird/3.1.10 ThunderBrowse/3.3.5' + family: 'ThunderBrowse' + major: '3' + minor: '3' + patch: '5' + + - user_agent_string: 'Mozilla/5.0 (Windows; U; en-US) AppleWebKit/531.9 (KHTML, like Gecko) AdobeAIR/2.5.1' + family: 'AdobeAIR' + major: '2' + minor: '5' + patch: '1' + + - user_agent_string: 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)' + family: 'Googlebot' + major: '2' + minor: '1' + patch: + + - user_agent_string: 'Mozilla/5.0 YottaaMonitor;' + family: 'YottaaMonitor' + major: + minor: + patch: + + - user_agent_string: 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) RockMelt/0.8.34.841 Chrome/6.0.472.63 Safari/534.3' + family: 'RockMelt' + major: '0' + minor: '8' + patch: '34' + + - user_agent_string: 'Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20110417 IceCat/4.0' + family: 'IceCat' + major: '4' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/5.0 (X11; U; Linux i686; nl-NL) AppleWebKit/534.3 (KHTML, like Gecko) WeTab-Browser Safari/534.3' + family: 'WeTab' + major: + minor: + patch: + + - user_agent_string: 'Mozilla/4.0 (compatible; Linux 2.6.10) NetFront/3.3 Kindle/1.0 (screen 600x800)' + family: 'Kindle' + major: '1' + minor: '0' + patch: + + - user_agent_string: 'Opera/9.80 (Android 3.2; Linux; Opera Tablet/ADR-1106291546; U; en) Presto/2.8.149 Version/11.10' + family: 'Opera Tablet' + major: '11' + minor: '10' + patch: + + - user_agent_string: 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534+ (KHTML, like Gecko) FireWeb/1.0.0.0' + family: 'FireWeb' + major: '1' + minor: '0' + patch: '0' + + - user_agent_string: 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Comodo_Dragon/4.1.1.11 Chrome/4.1.249.1042 Safari/532.5' + family: 'Comodo Dragon' + major: '4' + minor: '1' + patch: '1' + + - user_agent_string: 'Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_2 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8H7 Safari/6533.18.5' + family: 'Mobile Safari' + major: '5' + minor: '0' + patch: '2' + + - user_agent_string: 'Mozilla/5.0 (Linux; U; Android 3.0.1; en-us; GT-P7510 Build/HRI83) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' + family: 'Android' + major: '3' + minor: '0' + patch: '1' + + - user_agent_string: 'Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.0; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/233.58 Safari/534.6 TouchPad/1.0' + family: 'webOS TouchPad' + major: '1' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 7.0; Windows Phone OS 7.0; Trident/3.1; IEMobile/7.0; SAMSUNG; SGH-i917)' + family: 'IE Mobile' + major: '7' + minor: '0' + patch: + + + - user_agent_string: 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-us) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Safari/530.17 Skyfire/2.0' + family: 'Skyfire' + major: '2' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/5.0 (PlayBook; U; RIM Tablet OS 1.0.0; en-US) AppleWebKit/534.8+ (KHTML, like Gecko) Version/0.0.1 Safari/534.8+' + family: 'Blackberry WebKit' + major: '1' + minor: '0' + patch: '0' + + - user_agent_string: 'Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.648.133 Chrome/10.0.648.133 Safari/534.16' + family: 'Chromium' + major: '10' + minor: '0' + patch: '648' + + - user_agent_string: 'Mozilla/5.0 (Windows NT 5.1; rv:2.0) Gecko/20110407 Firefox/4.0.3 PaleMoon/4.0.3' + family: 'Pale Moon (Firefox Variant)' + major: '4' + minor: '0' + patch: '3' + + - user_agent_string: 'Opera/9.80 (Series 60; Opera Mini/6.24455/25.677; U; fr) Presto/2.5.25 Version/10.54' + family: 'Opera Mini' + major: '6' + minor: '24455' + patch: + + - user_agent_string: 'Mozilla/5.0 (X11; Linux i686 (x86_64); rv:2.0b4) Gecko/20100818 Firefox/4.0b4' + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: 'b4' + + - user_agent_string: 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.12) Gecko/20101027 Ubuntu/10.04 (lucid) Firefox/3.6.12' + family: 'Firefox' + major: '3' + minor: '6' + patch: '12' + + - user_agent_string: 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.1pre) Gecko/20090717 Ubuntu/9.04 (jaunty) Shiretoko/3.5.1pre' + family: 'Firefox (Shiretoko)' + major: '3' + minor: '5' + patch: '1pre' + + - user_agent_string: 'Mozilla/5.0 (X11; Linux x86_64; rv:2.0b8pre) Gecko/20101031 Firefox-4.0/4.0b8pre' + family: 'Firefox Beta' + major: '4' + minor: '0' + patch: 'b8pre' + + - user_agent_string: 'Mozilla/5.0 (X11; U; BSD Four; en-US) AppleWebKit/533.3 (KHTML, like Gecko) rekonq Safari/533.3' + family: 'Rekonq' + major: + minor: + patch: + + - user_agent_string: 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.34 (KHTML, like Gecko) rekonq/1.0 Safari/534.34' + family: 'Rekonq' + major: '1' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/5.0 (X11; U; Linux; de-DE) AppleWebKit/527 (KHTML, like Gecko, Safari/419.3) konqueror/4.3.1' + family: 'Konqueror' + major: '4' + minor: '3' + patch: '1' + + - user_agent_string: 'SomethingWeNeverKnewExisted' + family: 'Other' + major: + minor: + patch: + + - user_agent_string: 'Midori/0.2 (X11; Linux; U; en-us) WebKit/531.2 ' + family: 'Midori' + major: '0' + minor: '2' + patch: + + - user_agent_string: 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.3a1) Gecko/20100208 MozillaDeveloperPreview/3.7a1 (.NET CLR 3.5.30729)' + family: 'MozillaDeveloperPreview' + major: '3' + minor: '7' + patch: 'a1' + + - user_agent_string: 'Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.5.24 Version/10.53' + family: 'Opera' + major: '10' + minor: '53' + patch: + + - user_agent_string: 'Opera/9.80 (S60; SymbOS; Opera Mobi/275; U; es-ES) Presto/2.4.13 Version/10.00' + family: 'Opera Mobile' + major: '10' + minor: '00' + patch: + + - user_agent_string: 'Mozilla/5.0 (webOS/1.2; U; en-US) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Desktop/1.0' + family: 'webOSBrowser' + major: '1' + minor: '2' + patch: + + - user_agent_string: 'Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B367 Safari/531.21.10' + family: 'Mobile Safari' + major: '4' + minor: '0' + patch: '4' + + - user_agent_string: 'Mozilla/5.0 (SAMSUNG; SAMSUNG-GT-S8500/S8500XXJEE; U; Bada/1.0; nl-nl) AppleWebKit/533.1 (KHTML, like Gecko) Dolfin/2.0 Mobile WVGA SMM-MMS/1.2.0 OPN-B' + family: 'Dolfin' + major: '2' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; BOLT/2.101) AppleWebKit/530 (KHTML, like Gecko) Version/4.0 Safari/530.17' + family: 'BOLT' + major: '2' + minor: '101' + patch: + + # Safari + - user_agent_string: 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/418.8 (KHTML, like Gecko) Safari/419.3' + family: 'Safari' + major: + minor: + patch: + + - user_agent_string: 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-us) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5' + family: 'Safari' + major: '5' + minor: '0' + patch: '2' + + # BlackBerry devices + - user_agent_string: 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en-GB) AppleWebKit/534.1+ (KHTML, like Gecko) Version/6.0.0.141 Mobile Safari/534.1+' + family: 'Blackberry WebKit' + major: '6' + minor: '0' + patch: '0' + + - user_agent_string: 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en-US) AppleWebKit/534.1 (KHTML, like Gecko) Version/6.0.0.91 Mobile Safari/534.1 ' + family: 'Blackberry WebKit' + major: '6' + minor: '0' + patch: '0' + + # Chrome frame + - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; chromeframe; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; Sleipnir 2.8.5)3.0.30729)' + js_ua: "{'js_user_agent_string': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.1 (KHTML, like Gecko) Chrome/2.0.169.1 Safari/530.1'}" + family: 'Chrome Frame (Sleipnir 2)' + major: '2' + minor: '0' + patch: '169' + + - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; chromeframe; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729)' + js_ua: "{'js_user_agent_string': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.1 (KHTML, like Gecko) Chrome/2.0.169.1 Safari/530.1'}" + family: 'Chrome Frame (IE 8)' + major: '2' + minor: '0' + patch: '169' + + # Chrome Frame installed but not enabled + - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6; chromeframe; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)' + js_ua: "{'js_user_agent_string': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; chromeframe; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)'}" + family: 'IE' + major: '8' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6; .NET CLR 2.0.50727; .NET CLR 1.1.4322)' + js_ua: "{'js_user_agent_string': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 1.1.4322)', 'js_user_agent_family': 'IE Platform Preview', 'js_user_agent_v1': '9', 'js_user_agent_v2': '0', 'js_user_agent_v3': '1'}" + family: 'IE Platform Preview' + major: '9' + minor: '0' + patch: '1' + + - user_agent_string: 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us; Silk/1.1.0-80) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 Silk-Accelerated=true' + family: 'Silk' + major: '1' + minor: '1' + patch: '0-80' + +# - user_agent_string: 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; XBLWP7; ZuneWP7)' +# family: 'IE Mobile' +# major: '9' +# minor: '0' +# patch: + + - user_agent_string: 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; SGH-i917)' + family: 'IE Mobile' + major: '9' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; SGH-i917)' + family: 'IE Mobile' + major: '9' + minor: '0' + patch: + + - user_agent_string: 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; chromeframe/11.0.660.0)' + family: 'Chrome Frame' + major: '11' + minor: '0' + patch: '660' + + - user_agent_string: 'PyAMF/0.6.1' + family: 'PyAMF' + major: '0' + minor: '6' + patch: '1' + + - user_agent_string: 'python-requests/0.14 CPython/2.6 Linux/2.6-43-server' + family: 'Python Requests' + major: '0' + minor: '14' + patch: + + - user_agent_string: 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0)' + family: 'IE' + major: '10' + minor: '0' + patch: diff --git a/node_modules/useragent/test/mocha.opts b/node_modules/useragent/test/mocha.opts new file mode 100644 index 0000000..bf0875d --- /dev/null +++ b/node_modules/useragent/test/mocha.opts @@ -0,0 +1,4 @@ +--reporter spec +--ui bdd +--require should +--growl diff --git a/node_modules/useragent/test/parser.qa.js b/node_modules/useragent/test/parser.qa.js new file mode 100644 index 0000000..fda5434 --- /dev/null +++ b/node_modules/useragent/test/parser.qa.js @@ -0,0 +1,45 @@ +var useragent = require('../') + , should = require('should') + , yaml = require('yamlparser') + , fs = require('fs'); + +// run over the testcases, some might fail, some might not. This is just qu +// test to see if we can parse without errors, and with a reasonable amount +// of errors. +[ + 'testcases.yaml' + , 'static.custom.yaml' + , 'firefoxes.yaml' + , 'pgts.yaml' +].forEach(function (filename) { + var testcases = fs.readFileSync(__dirname +'/fixtures/' + filename).toString() + , parsedyaml = yaml.eval(testcases); + + testcases = parsedyaml.test_cases; + testcases.forEach(function (test) { + // we are unable to parse these tests atm because invalid JSON is used to + // store the useragents + if (typeof test.user_agent_string !== 'string') return; + + // these tests suck as the test files are broken, enable this to have about + // 40 more failing tests + if (test.family.match(/googlebot|avant/i)) return; + + // attempt to parse the shizzle js based stuff + var js_ua; + if (test.js_ua) { + js_ua = (Function('return ' + test.js_ua)()).js_user_agent_string; + } + + exports[filename + ': ' + test.user_agent_string] = function () { + var agent = useragent.parse(test.user_agent_string, js_ua); + + agent.family.should.equal(test.family); + // we need to test if v1 is a string, because the yamlparser transforms + // empty v1: statements to {} + agent.major.should.equal(typeof test.major == 'string' ? test.major : '0'); + agent.minor.should.equal(typeof test.minor == 'string' ? test.minor : '0'); + agent.patch.should.equal(typeof test.patch == 'string' ? test.patch : '0'); + } + }); +}); diff --git a/node_modules/useragent/test/parser.test.js b/node_modules/useragent/test/parser.test.js new file mode 100644 index 0000000..ab6473f --- /dev/null +++ b/node_modules/useragent/test/parser.test.js @@ -0,0 +1,214 @@ +describe('useragent', function () { + 'use strict'; + + var useragent = require('../') + , ua = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.24 Safari/535.2"; + + it('should expose the current version number', function () { + useragent.version.should.match(/^\d+\.\d+\.\d+$/); + }); + + it('should expose the Agent interface', function () { + useragent.Agent.should.be.a('function'); + }); + + it('should expose the OperatingSystem interface', function () { + useragent.OperatingSystem.should.be.a('function'); + }); + + it('should expose the Device interface', function () { + useragent.Device.should.be.a('function'); + }); + + it('should expose the dictionary lookup', function () { + useragent.lookup.should.be.a('function'); + }); + + it('should expose the parser', function () { + useragent.parse.should.be.a('function'); + }); + + it('should expose the useragent tester', function () { + useragent.is.should.be.a('function'); + }); + + describe('#parse', function () { + it('correctly transforms everything to the correct instances', function () { + var agent = useragent.parse(ua); + + agent.should.be.an.instanceOf(useragent.Agent); + agent.os.should.be.an.instanceOf(useragent.OperatingSystem); + agent.device.should.be.an.instanceOf(useragent.Device); + }); + + it('correctly parsers the operating system', function () { + var os = useragent.parse(ua).os; + + os.toString().should.equal('Mac OS X 10.7.1'); + os.toVersion().should.equal('10.7.1'); + JSON.stringify(os).should.equal('{"family":"Mac OS X","major":"10","minor":"7","patch":"1"}'); + + os.major.should.equal('10'); + os.minor.should.equal('7'); + os.patch.should.equal('1'); + }); + + it('should not throw errors when no useragent is given', function () { + var agent = useragent.parse(); + + agent.family.should.equal('Other'); + agent.major.should.equal('0'); + agent.minor.should.equal('0'); + agent.patch.should.equal('0'); + + agent.os.toString().should.equal('Other'); + agent.toVersion().should.equal('0.0.0'); + agent.toString().should.equal('Other 0.0.0 / Other'); + agent.toAgent().should.equal('Other 0.0.0'); + JSON.stringify(agent).should.equal('{"family":"Other","major":"0","minor":"0","patch":"0","device":{"family":"Other"},"os":{"family":"Other"}}'); + }); + + it('should not throw errors on empty strings and default to unkown', function () { + var agent = useragent.parse(''); + + agent.family.should.equal('Other'); + agent.major.should.equal('0'); + agent.minor.should.equal('0'); + agent.patch.should.equal('0'); + + agent.os.toString().should.equal('Other'); + agent.toVersion().should.equal('0.0.0'); + agent.toString().should.equal('Other 0.0.0 / Other'); + agent.toAgent().should.equal('Other 0.0.0'); + JSON.stringify(agent).should.equal('{"family":"Other","major":"0","minor":"0","patch":"0","device":{"family":"Other"},"os":{"family":"Other"}}'); + }); + + it('should correctly parse chromes user agent', function () { + var agent = useragent.parse(ua); + + agent.family.should.equal('Chrome'); + agent.major.should.equal('15'); + agent.minor.should.equal('0'); + agent.patch.should.equal('874'); + + agent.os.toString().should.equal('Mac OS X 10.7.1'); + agent.toVersion().should.equal('15.0.874'); + agent.toString().should.equal('Chrome 15.0.874 / Mac OS X 10.7.1'); + agent.toAgent().should.equal('Chrome 15.0.874'); + JSON.stringify(agent).should.equal('{"family":"Chrome","major":"15","minor":"0","patch":"874","device":{"family":"Other"},"os":{"family":"Mac OS X","major":"10","minor":"7","patch":"1"}}'); + }); + }); + + describe('#fromJSON', function () { + it('should re-generate the Agent instance', function () { + var agent = useragent.parse(ua) + , string = JSON.stringify(agent) + , agent2 = useragent.fromJSON(string); + + agent2.family.should.equal(agent.family); + agent2.major.should.equal(agent.major); + agent2.minor.should.equal(agent.minor); + agent2.patch.should.equal(agent.patch); + + agent2.device.family.should.equal(agent.device.family); + + agent2.os.family.should.equal(agent.os.family); + agent2.os.major.should.equal(agent.os.major); + agent2.os.minor.should.equal(agent.os.minor); + agent2.os.patch.should.equal(agent.os.patch); + }); + + it('should also work with legacy JSON', function () { + var agent = useragent.fromJSON('{"family":"Chrome","major":"15","minor":"0","patch":"874","os":"Mac OS X"}'); + + agent.family.should.equal('Chrome'); + agent.major.should.equal('15'); + agent.minor.should.equal('0'); + agent.patch.should.equal('874'); + + agent.device.family.should.equal('Other'); + + agent.os.family.should.equal('Mac OS X'); + }); + }); + + describe('#is', function () { + var chrome = ua + , firefox = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:8.0) Gecko/20100101 Firefox/8.0' + , ie = 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; yie8)' + , opera = 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; de) Opera 11.51' + , safari = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; da-dk) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1' + , ipod = 'Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; ja-jp) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5'; + + it('should not throw errors when called without arguments', function () { + useragent.is(); + useragent.is(''); + }); + + it('should correctly detect google chrome', function () { + useragent.is(chrome).chrome.should.equal(true); + useragent.is(chrome).webkit.should.equal(true); + useragent.is(chrome).safari.should.equal(false); + useragent.is(chrome).firefox.should.equal(false); + useragent.is(chrome).mozilla.should.equal(false); + useragent.is(chrome).ie.should.equal(false); + useragent.is(chrome).opera.should.equal(false); + useragent.is(chrome).mobile_safari.should.equal(false); + }); + + it('should correctly detect firefox', function () { + useragent.is(firefox).chrome.should.equal(false); + useragent.is(firefox).webkit.should.equal(false); + useragent.is(firefox).safari.should.equal(false); + useragent.is(firefox).firefox.should.equal(true); + useragent.is(firefox).mozilla.should.equal(true); + useragent.is(firefox).ie.should.equal(false); + useragent.is(firefox).opera.should.equal(false); + useragent.is(firefox).mobile_safari.should.equal(false); + }); + + it('should correctly detect internet explorer', function () { + useragent.is(ie).chrome.should.equal(false); + useragent.is(ie).webkit.should.equal(false); + useragent.is(ie).safari.should.equal(false); + useragent.is(ie).firefox.should.equal(false); + useragent.is(ie).mozilla.should.equal(false); + useragent.is(ie).ie.should.equal(true); + useragent.is(ie).opera.should.equal(false); + useragent.is(ie).mobile_safari.should.equal(false); + }); + + it('should correctly detect opera', function () { + useragent.is(opera).chrome.should.equal(false); + useragent.is(opera).webkit.should.equal(false); + useragent.is(opera).safari.should.equal(false); + useragent.is(opera).firefox.should.equal(false); + useragent.is(opera).mozilla.should.equal(false); + useragent.is(opera).ie.should.equal(false); + useragent.is(opera).opera.should.equal(true); + useragent.is(opera).mobile_safari.should.equal(false); + }); + + it('should correctly detect safari', function () { + useragent.is(safari).chrome.should.equal(false); + useragent.is(safari).webkit.should.equal(true); + useragent.is(safari).safari.should.equal(true); + useragent.is(safari).firefox.should.equal(false); + useragent.is(safari).mozilla.should.equal(false); + useragent.is(safari).ie.should.equal(false); + useragent.is(safari).opera.should.equal(false); + useragent.is(safari).mobile_safari.should.equal(false); + }); + + it('should correctly detect safari-mobile', function () { + useragent.is(ipod).chrome.should.equal(false); + useragent.is(ipod).webkit.should.equal(true); + useragent.is(ipod).safari.should.equal(true); + useragent.is(ipod).firefox.should.equal(false); + useragent.is(ipod).mozilla.should.equal(false); + useragent.is(ipod).ie.should.equal(false); + useragent.is(ipod).opera.should.equal(false); + useragent.is(ipod).mobile_safari.should.equal(true); + }); + }); +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..266b456 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "mousewheel-data-collector", + "description": "Data collection for the mouse wheel", + "version": "0.0.1", + "main": "app.js", + "scripts": { + "start": "node app.js" + }, + "private": true, + "dependencies": { + "express": "3.4.x", + "jade": "0.35.x", + "stylus": "0.40.x", + "nib": "1.0.x", + "useragent": "2.0.x", + "mongoose": "3.8.x" + } +} diff --git a/public/css/bootstrap-theme.min.css b/public/css/bootstrap-theme.min.css new file mode 100644 index 0000000..221d318 --- /dev/null +++ b/public/css/bootstrap-theme.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v3.0.1 by @fat and @mdo + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + +.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-moz-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#2d6ca2));background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-moz-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);background-repeat:repeat-x;border-color:#2b669a;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff2d6ca2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5cb85c),to(#419641));background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-moz-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);background-repeat:repeat-x;border-color:#3e8f3e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff419641',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f0ad4e),to(#eb9316));background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-moz-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);background-repeat:repeat-x;border-color:#e38d13;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffeb9316',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9534f),to(#c12e2a));background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-moz-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);background-repeat:repeat-x;border-color:#b92c28;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc12e2a',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5bc0de),to(#2aabd2));background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-moz-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);background-repeat:repeat-x;border-color:#28a4c9;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2aabd2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-gradient(linear,left 0,left 100%,from(#f5f5f5),to(#e8e8e8));background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-moz-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#357ebd));background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-moz-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.navbar-default{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#f8f8f8));background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-moz-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff8f8f8',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-gradient(linear,left 0,left 100%,from(#ebebeb),to(#f3f3f3));background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:-moz-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff3f3f3',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.075);box-shadow:inset 0 3px 9px rgba(0,0,0,0.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,0.25)}.navbar-inverse{background-image:-webkit-gradient(linear,left 0,left 100%,from(#3c3c3c),to(#222));background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-moz-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-gradient(linear,left 0,left 100%,from(#222),to(#282828));background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:-moz-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff282828',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.25);box-shadow:inset 0 3px 9px rgba(0,0,0,0.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05)}.alert-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#dff0d8),to(#c8e5bc));background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-moz-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;border-color:#b2dba1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffc8e5bc',GradientType=0)}.alert-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9edf7),to(#b9def0));background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-moz-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;border-color:#9acfea;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffb9def0',GradientType=0)}.alert-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fcf8e3),to(#f8efc0));background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-moz-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;border-color:#f5e79e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fff8efc0',GradientType=0)}.alert-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f2dede),to(#e7c3c3));background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-moz-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;border-color:#dca7a7;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffe7c3c3',GradientType=0)}.progress{background-image:-webkit-gradient(linear,left 0,left 100%,from(#ebebeb),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-moz-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff5f5f5',GradientType=0)}.progress-bar{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3071a9));background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-moz-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3071a9',GradientType=0)}.progress-bar-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5cb85c),to(#449d44));background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-moz-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff449d44',GradientType=0)}.progress-bar-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5bc0de),to(#31b0d5));background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-moz-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff31b0d5',GradientType=0)}.progress-bar-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f0ad4e),to(#ec971f));background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-moz-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffec971f',GradientType=0)}.progress-bar-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9534f),to(#c9302c));background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-moz-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc9302c',GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3278b3));background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-moz-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;border-color:#3278b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3278b3',GradientType=0)}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.panel-default>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f5f5f5),to(#e8e8e8));background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-moz-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#357ebd));background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-moz-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#dff0d8),to(#d0e9c6));background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-moz-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffd0e9c6',GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9edf7),to(#c4e3f3));background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-moz-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffc4e3f3',GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fcf8e3),to(#faf2cc));background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-moz-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fffaf2cc',GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f2dede),to(#ebcccc));background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-moz-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffebcccc',GradientType=0)}.well{background-image:-webkit-gradient(linear,left 0,left 100%,from(#e8e8e8),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-moz-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;border-color:#dcdcdc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1)} \ No newline at end of file diff --git a/public/css/bootstrap.min.css b/public/css/bootstrap.min.css new file mode 100644 index 0000000..871123f --- /dev/null +++ b/public/css/bootstrap.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v3.0.1 by @fat and @mdo + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + +/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-primary:hover{color:#3071a9}.text-warning{color:#c09853}.text-warning:hover{color:#a47e3c}.text-danger{color:#b94a48}.text-danger:hover{color:#953b39}.text-success{color:#468847}.text-success:hover{color:#356635}.text-info{color:#3a87ad}.text-info:hover{color:#2d6987}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small{font-size:65%}h4,h5,h6{margin-top:10px;margin-bottom:10px}h4 small,h5 small,h6 small,h4 .small,h5 .small,h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}.list-inline>li:first-child{padding-left:0}dl{margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small{display:block;line-height:1.428571429;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small,blockquote.pull-right .small{text-align:right}blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}@media(min-width:768px){.container{width:750px}.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}}@media(min-width:992px){.container{width:970px}.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}}@media(min-width:1200px){.container{width:1170px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}@media(max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:45px;line-height:45px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#c09853}.has-warning .form-control{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.has-warning .input-group-addon{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#b94a48}.has-error .form-control{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.has-error .input-group-addon{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#468847}.has-success .form-control{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.has-success .input-group-addon{color:#468847;background-color:#dff0d8;border-color:#468847}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-control-static{padding-top:7px}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-link{font-weight:normal;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1;-moz-osx-font-smoothing:grayscale}.glyphicon:empty{width:1em}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid #000;border-right:4px solid transparent;border-bottom:0 dotted;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0 dotted;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-default .caret{border-top-color:#333}.btn-primary .caret,.btn-success .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret{border-top-color:#fff}.dropup .btn-default .caret{border-bottom-color:#333}.dropup .btn-primary .caret,.dropup .btn-success .caret,.dropup .btn-warning .caret,.dropup .btn-danger .caret,.dropup .btn-info .caret{border-bottom-color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:5px 10px;padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified .btn{display:table-cell;float:none;width:1%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group.col{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:45px;line-height:45px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn:first-child>.btn{margin-right:-1px}.input-group-btn:last-child>.btn{margin-left:-1px}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .open>a .caret,.nav .open>a:hover .caret,.nav .open>a:focus .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-pills>li.active>a .caret,.nav-pills>li.active>a:hover .caret,.nav-pills>li.active>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav .caret{border-top-color:#428bca;border-bottom-color:#428bca}.nav a:hover .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:auto}.navbar-collapse .navbar-nav.navbar-left:first-child{margin-left:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:-15px}.navbar-collapse .navbar-text:last-child{margin-right:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-text{float:left;margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{margin-right:15px;margin-left:15px}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.dropdown>a:hover .caret,.navbar-default .navbar-nav>.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.open>a .caret,.navbar-default .navbar-nav>.open>a:hover .caret,.navbar-default .navbar-nav>.open>a:focus .caret{border-top-color:#555;border-bottom-color:#555}.navbar-default .navbar-nav>.dropdown>a .caret{border-top-color:#777;border-bottom-color:#777}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-nav>.dropdown>a .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .navbar-nav>.open>a .caret,.navbar-inverse .navbar-nav>.open>a:hover .caret,.navbar-inverse .navbar-nav>.open>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.btn .badge{position:relative;top:-1px}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.thumbnail{display:inline-block;display:block;height:auto;max-width:100%;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img{display:block;height:auto;max-width:100%;margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#356635}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#2d6987}.alert-warning{color:#c09853;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#a47e3c}.alert-danger{color:#b94a48;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#953b39}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive{margin-bottom:0}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-heading>.dropdown .caret{border-color:#333 transparent}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-heading>.dropdown .caret{border-color:#fff transparent}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading>.dropdown .caret{border-color:#468847 transparent}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#c09853;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading>.dropdown .caret{border-color:#c09853 transparent}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#b94a48;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading>.dropdown .caret{border-color:#b94a48 transparent}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading>.dropdown .caret{border-color:#3a87ad transparent}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;z-index:1050;width:auto;padding:10px;margin-right:auto;margin-left:auto}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{width:600px;padding-top:30px;padding-bottom:30px}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.5)),to(rgba(0,0,0,0.0001)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.0001)),to(rgba(0,0,0,0.5)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,tr.hidden-xs.hidden-md,th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,tr.hidden-sm.hidden-md,th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs,tr.hidden-md.hidden-xs,th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,tr.hidden-md.hidden-sm,th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg,tr.hidden-md.hidden-lg,th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs,tr.hidden-lg.hidden-xs,th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm,tr.hidden-lg.hidden-sm,th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md,tr.hidden-lg.hidden-md,th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}} \ No newline at end of file diff --git a/public/css/stuffs.css b/public/css/stuffs.css new file mode 100644 index 0000000..cf9c39c --- /dev/null +++ b/public/css/stuffs.css @@ -0,0 +1,12 @@ +html,body{height:100%} +.wrap{min-height:100%;height:auto;margin:0 auto -25px;padding:0 0 25px} +.collector{position:relative;padding-top:100px;padding-bottom:100px;} +.collector .instruction{font-size:14px;font-weight:bold;text-align:center;color:#999} +.collector .yourresults{position:absolute;top:10px;left:10px;right:10px;font-size:12px;color:#999;} +.collector .yourresults dl{margin:0 0 5px 0;} +.collector .yourresults dl dt,.collector .yourresults dl dd{display:block} +.collector .yourresults dl dt{float:left;clear:left;width:100px;font-weight:normal} +.collector .yourresults dl dd{float:right;clear:right} +.collector .submit{position:absolute;top:138px;left:10px;right:10px;text-align:center} +.collector .useragent{position:absolute;bottom:10px;left:10px;right:10px;font-size:12px;text-align:center;color:#999} +footer{height:25px;background-color:#f5f5f5;font-size:11px;text-align:center;padding-top:5px} diff --git a/public/css/stuffs.styl b/public/css/stuffs.styl new file mode 100644 index 0000000..19a1446 --- /dev/null +++ b/public/css/stuffs.styl @@ -0,0 +1,61 @@ +html, body + height: 100% + +.wrap + min-height: 100% + height: auto + margin: 0 auto -25px + padding: 0 0 25px + +.collector + position: relative + padding-top: 100px + padding-bottom: 100px + .instruction + font-size: 14px + font-weight: bold + text-align: center + color: #999 + .yourresults + position: absolute + top: 10px + left: 10px + right: 10px + font-size: 12px + color: #999 + dl + margin: 0 0 5px 0 + dt, dd + display: block + dt + float: left + clear: left + width: 100px + font-weight: normal + dd + float: right + clear: right + + .submit + position: absolute + top: 138px + left: 10px + right: 10px + text-align: center + + .useragent + position: absolute + bottom: 10px + left: 10px + right: 10px + font-size: 12px + text-align: center + color: #999 + + +footer + height: 25px + background-color: #f5f5f5 + font-size: 11px + text-align: center + padding-top: 5px diff --git a/public/fonts/glyphicons-halflings-regular.eot b/public/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 0000000..423bd5d Binary files /dev/null and b/public/fonts/glyphicons-halflings-regular.eot differ diff --git a/public/fonts/glyphicons-halflings-regular.svg b/public/fonts/glyphicons-halflings-regular.svg new file mode 100644 index 0000000..4469488 --- /dev/null +++ b/public/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/fonts/glyphicons-halflings-regular.ttf b/public/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000..a498ef4 Binary files /dev/null and b/public/fonts/glyphicons-halflings-regular.ttf differ diff --git a/public/fonts/glyphicons-halflings-regular.woff b/public/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 0000000..d83c539 Binary files /dev/null and b/public/fonts/glyphicons-halflings-regular.woff differ diff --git a/public/js/bootstrap.min.js b/public/js/bootstrap.min.js new file mode 100644 index 0000000..e645725 --- /dev/null +++ b/public/js/bootstrap.min.js @@ -0,0 +1,9 @@ +/*! + * Bootstrap v3.0.1 by @fat and @mdo + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + +if("undefined"==typeof jQuery)throw new Error("Bootstrap requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]}}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(window.jQuery),+function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function c(){f.trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one(a.support.transition.end,c).emulateTransitionEnd(150):c())};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("bs.alert");e||d.data("bs.alert",e=new c(this)),"string"==typeof b&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.bs.alert.data-api",b,c.prototype.close)}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d)};b.DEFAULTS={loadingText:"loading..."},b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.is("input")?"val":"html",e=c.data();a+="Text",e.resetText||c.data("resetText",c[d]()),c[d](e[a]||this.options[a]),setTimeout(function(){"loadingText"==a?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.closest('[data-toggle="buttons"]');if(a.length){var b=this.$element.find("input").prop("checked",!this.$element.hasClass("active")).trigger("change");"radio"===b.prop("type")&&a.find(".active").removeClass("active")}this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof c&&c;e||d.data("bs.button",e=new b(this,f)),"toggle"==c?e.toggle():c&&e.setState(c)})},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.bs.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle"),b.preventDefault()})}(window.jQuery),+function(a){"use strict";var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},b.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},b.prototype.getActiveIndex=function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},b.prototype.to=function(b){var c=this,d=this.getActiveIndex();return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},b.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition.end&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},b.prototype.next=function(){return this.sliding?void 0:this.slide("next")},b.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},b.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}this.sliding=!0,f&&this.pause();var j=a.Event("slide.bs.carousel",{relatedTarget:e[0],direction:g});if(!e.hasClass("active")){if(this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")})),a.support.transition&&this.$element.hasClass("slide")){if(this.$element.trigger(j),j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)}).emulateTransitionEnd(600)}else{if(this.$element.trigger(j),j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c),g="string"==typeof c?c:f.slide;e||d.data("bs.carousel",e=new b(this,f)),"number"==typeof c?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c,d=a(this),e=a(d.attr("data-target")||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),d.data()),g=d.attr("data-slide-to");g&&(f.interval=!1),e.carousel(f),(g=d.attr("data-slide-to"))&&e.data("bs.carousel").to(g),b.preventDefault()}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var b=a(this);b.carousel(b.data())})})}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0},b.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},b.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b=a.Event("show.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.$parent&&this.$parent.find("> .panel > .in");if(c&&c.length){var d=c.data("bs.collapse");if(d&&d.transitioning)return;c.collapse("hide"),d||c.data("bs.collapse",null)}var e=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[e](0),this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("in")[e]("auto"),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return f.call(this);var g=a.camelCase(["scroll",e].join("-"));this.$element.one(a.support.transition.end,a.proxy(f,this)).emulateTransitionEnd(350)[e](this.$element[0][g])}}},b.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?(this.$element[c](0).one(a.support.transition.end,a.proxy(d,this)).emulateTransitionEnd(350),void 0):d.call(this)}}},b.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);e||d.data("bs.collapse",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.bs.collapse.data-api","[data-toggle=collapse]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.collapse"),h=g?"toggle":d.data(),i=d.attr("data-parent"),j=i&&a(i);g&&g.transitioning||(j&&j.find('[data-toggle=collapse][data-parent="'+i+'"]').not(d).addClass("collapsed"),d[f.hasClass("in")?"addClass":"removeClass"]("collapsed")),f.collapse(h)})}(window.jQuery),+function(a){"use strict";function b(){a(d).remove(),a(e).each(function(b){var d=c(a(this));d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown")),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown"))})}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}var d=".dropdown-backdrop",e="[data-toggle=dropdown]",f=function(b){a(b).on("click.bs.dropdown",this.toggle)};f.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){if("ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(''}),b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),b.prototype.constructor=b,b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"html":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},b.prototype.hasContent=function(){return this.getTitle()||this.getContent()},b.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},b.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof c&&c;e||d.data("bs.popover",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(window.jQuery),+function(a){"use strict";function b(c,d){var e,f=a.proxy(this.process,this);this.$element=a(c).is("body")?a(window):a(c),this.$body=a("body"),this.$scrollElement=this.$element.on("scroll.bs.scroll-spy.data-api",f),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||(e=a(c).attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.offsets=a([]),this.targets=a([]),this.activeTarget=null,this.refresh(),this.process()}b.DEFAULTS={offset:10},b.prototype.refresh=function(){var b=this.$element[0]==window?"offset":"position";this.offsets=a([]),this.targets=a([]);var c=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#\w/.test(e)&&a(e);return f&&f.length&&[[f[b]().top+(!a.isWindow(c.$scrollElement.get(0))&&c.$scrollElement.scrollTop()),e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){c.offsets.push(this[0]),c.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,d=c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(b>=d)return g!=(a=f.last()[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parents(".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate")};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(window.jQuery),+function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.parent("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},b.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e).emulateTransitionEnd(150):e(),f.removeClass("in")};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new b(this)),"string"==typeof c&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.options=a.extend({},b.DEFAULTS,d),this.$window=a(window).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(c),this.affixed=this.unpin=null,this.checkPosition()};b.RESET="affix affix-top affix-bottom",b.DEFAULTS={offset:0},b.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},b.prototype.checkPosition=function(){if(this.$element.is(":visible")){var c=a(document).height(),d=this.$window.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top()),"function"==typeof h&&(h=f.bottom());var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=c-h?"bottom":null!=g&&g>=d?"top":!1;this.affixed!==i&&(this.unpin&&this.$element.css("top",""),this.affixed=i,this.unpin="bottom"==i?e.top-d:null,this.$element.removeClass(b.RESET).addClass("affix"+(i?"-"+i:"")),"bottom"==i&&this.$element.offset({top:document.body.offsetHeight-h-this.$element.height()}))}};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof c&&c;e||d.data("bs.affix",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(window.jQuery); \ No newline at end of file diff --git a/public/js/jquery.mousewheel.js b/public/js/jquery.mousewheel.js new file mode 100644 index 0000000..8d8d60a --- /dev/null +++ b/public/js/jquery.mousewheel.js @@ -0,0 +1,130 @@ +/*! Copyright (c) 2013 Brandon Aaron (http://brandon.aaron.sh) + * Licensed under the MIT License (LICENSE.txt). + * + * Version: 3.1.4 + * Modified to include the raw delta and lowest delta as well + * + * Requires: 1.2.2+ + */ + +(function (factory) { + if ( typeof define === 'function' && define.amd ) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS style for Browserify + module.exports = factory; + } else { + // Browser globals + factory(jQuery); + } +}(function ($) { + + var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll']; + var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll']; + var lowestDelta, lowestDeltaXY; + + if ( $.event.fixHooks ) { + for ( var i = toFix.length; i; ) { + $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks; + } + } + + $.event.special.mousewheel = { + setup: function() { + if ( this.addEventListener ) { + for ( var i = toBind.length; i; ) { + this.addEventListener( toBind[--i], handler, false ); + } + } else { + this.onmousewheel = handler; + } + }, + + teardown: function() { + if ( this.removeEventListener ) { + for ( var i = toBind.length; i; ) { + this.removeEventListener( toBind[--i], handler, false ); + } + } else { + this.onmousewheel = null; + } + } + }; + + $.fn.extend({ + mousewheel: function(fn) { + return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel'); + }, + + unmousewheel: function(fn) { + return this.unbind('mousewheel', fn); + } + }); + + + function handler(event) { + var orgEvent = event || window.event, + args = [].slice.call(arguments, 1), + delta = 0, + deltaX = 0, + deltaY = 0, + absDelta = 0, + absDeltaXY = 0, + rawDelta = 0, + fn; + event = $.event.fix(orgEvent); + event.type = 'mousewheel'; + + // Old school scrollwheel delta + if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; } + if ( orgEvent.detail ) { delta = orgEvent.detail * -1; } + + // At a minimum, setup the deltaY to be delta + deltaY = delta; + + // Firefox < 17 related to DOMMouseScroll event + if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) { + deltaY = 0; + deltaX = delta * -1; + } + + // New school wheel delta (wheel event) + if ( orgEvent.deltaY ) { + deltaY = orgEvent.deltaY * -1; + delta = deltaY; + } + if ( orgEvent.deltaX ) { + deltaX = orgEvent.deltaX; + delta = deltaX * -1; + } + + // Webkit + if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; } + if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX * -1; } + + rawDelta = delta; + + // Completely ignore if delta is 0 + // have had it happen with erratic input + if (delta === 0) { return; } + + // Look for lowest delta to normalize the delta values + absDelta = Math.abs(delta); + if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; } + absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX)); + if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; } + + // Get a whole value for the deltas + fn = delta > 0 ? 'floor' : 'ceil'; + delta = Math[fn](delta / lowestDelta); + deltaX = Math[fn](deltaX / lowestDeltaXY); + deltaY = Math[fn](deltaY / lowestDeltaXY); + + // Add event and delta to the front of the arguments + args.unshift(event, delta, deltaX, deltaY, rawDelta, lowestDelta); + + return ($.event.dispatch || $.event.handle).apply(this, args); + } + +})); diff --git a/public/js/stuffs.js b/public/js/stuffs.js new file mode 100644 index 0000000..8b24bca --- /dev/null +++ b/public/js/stuffs.js @@ -0,0 +1,108 @@ +(function() { + + var Collector = { + setup: function() { + this.$collector = $('.collector'); + this.$instruction = this.$collector.find('.instruction'); + this.$yourresults = $('.yourresults'); + this.$yourresultsmin = this.$yourresults.find('.yourresults-min'); + this.$yourresultsmax = this.$yourresults.find('.yourresults-max'); + this.$yourresultsres = this.$yourresults.find('.yourresults-res'); + this.$submit = $('.submit'); + this.$useragent = $('.useragent'); + this.data = { + useragent: this.$useragent.data('ua'), + delta: { + normalized: { + min: null, + max: null + }, + raw: { + min: null, + max: null + }, + resolution: null + } + }; + this.$collector.on('mousewheel', $.proxy(this, 'collection')); + this.$submit.on('click', '.btn', $.proxy(this, 'submitResults')); + }, + + submitResults: function(event) { + this.disableSubmit(); + $.ajax({ + type: 'POST', + data: this.data, + complete: function() { + console.log(arguments); + } + }); + console.log(event); + }, + + disableSubmit: function() { + this.$submit.find('.btn').attr('disabled', true); + }, + + enableSubmit: function() { + this.$submit.find('.btn').attr('disabled', false); + }, + + fadeIn: function() { + if (this.animating === false) return; + this.$instruction.fadeTo(500, 1, $.proxy(this, 'fadeOut')); + }, + + fadeOut: function() { + if (this.animating === false) return; + this.$instruction.stop().fadeTo(500, .40, $.proxy(this, 'fadeIn')); + }, + + startAnimating: function() { + if (this.animatingTimeout) clearTimeout(this.animatingTimeout); + this.animatingTimeout = setTimeout($.proxy(this, 'stopAnimating'), 1000); + + if (this.animating === true) return; + this.animating = true; + this.fadeOut(); + this.disableSubmit(); + }, + + stopAnimating: function() { + this.animating = false; + this.$instruction.stop().fadeTo(500, 1); + this.enableSubmit(); + }, + + updateYourResults: function() { + this.$yourresultsmin.html( this.data.delta.normalized.min + ', ' + this.data.delta.raw.min); + this.$yourresultsmax.html( this.data.delta.normalized.max + ', ' + this.data.delta.raw.max); + this.$yourresultsres.html( this.data.delta.resolution ); + }, + + collection: function(event, delta, deltaX, deltaY, rawDelta, lowestDelta) { + event.preventDefault(); + this.startAnimating(); + if (rawDelta === 0) + console.log(delta, rawDelta, lowestDelta); + var absDelta = Math.abs(delta), + absRawDelta = Math.abs(rawDelta), + min = this.data.delta.normalized.min === null ? absDelta : Math.min( absDelta, this.data.delta.normalized.min ), + max = this.data.delta.normalized.max === null ? absDelta : Math.max( absDelta, this.data.delta.normalized.max ), + rmin = this.data.delta.raw.min === null ? absRawDelta : Math.min( absRawDelta, this.data.delta.raw.min ), + rmax = this.data.delta.raw.max === null ? absRawDelta : Math.max( absRawDelta, this.data.delta.raw.max ); + this.data.delta.normalized.min = min; + this.data.delta.normalized.max = max; + this.data.delta.raw.min = rmin; + this.data.delta.raw.max = rmax; + this.data.delta.resolution = lowestDelta; + this.updateYourResults(); + } + } + + $(function() { + Collector.setup(); + window.Collector = Collector; + }); + +})(); diff --git a/views/home.jade b/views/home.jade new file mode 100644 index 0000000..b2aced6 --- /dev/null +++ b/views/home.jade @@ -0,0 +1,43 @@ +extends layout + +block content + .row + .col-lg-4.col-md-4.col-sm-4 + .collector.well.well-lg + .instruction + span Use Mouse Wheel Here + .yourresults + dl + dt Min (norm, raw): + dd.yourresults-min + dl + dt Max (norm, raw): + dd.yourresults-max + dl + dt Resolution: + dd.yourresults-res + .submit + button(type="button", class="btn btn-default btn-xs", disabled="disabled") Submit Results + .useragent("data-ua"=agent.toJSON())= agent.toString() + .col-lg-8.col-md-8.col-sm-8 + h2 Existing Results + table + thead + tr + th OS + th Browser + th Min (Norm, Raw) + th Max (Norm, Raw) + th Resolution + tbody + each rec in records + tr + td + = rec.useragent.os.family + small= ' (' + rec.useragent.os.major + '.' + rec.useragent.os.minor + '.' + rec.useragent.os.patch + ')' + td + = rec.useragent.family + small= ' (' + rec.useragent.major + '.' + rec.useragent.minor + '.' + rec.useragent.patch + ')' + td= rec.delta.normalized.min + ', ' + rec.delta.raw.min + td= rec.delta.normalized.max + ', ' + rec.delta.raw.max + td= rec.delta.resolution diff --git a/views/layout.jade b/views/layout.jade new file mode 100644 index 0000000..b215125 --- /dev/null +++ b/views/layout.jade @@ -0,0 +1,21 @@ +!!! 5 +html + title Mouse Wheel Data Collection + meta(name="viewport", content="width=device-width, initial-scale=1.0") + link(href="css/bootstrap.min.css", rel="stylesheet", media="screen") + link(href="css/stuffs.css", rel="stylesheet", media="screen") + //if lt IE 9 + script(src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js") + script(src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js") + body + .wrap + .container + header.page-header + h1 Mouse Wheel Data Collection + .content + block content + footer + © Copyright Brandon Aaron 2013. Licensed under MIT. + script(src="https://code.jquery.com/jquery.js") + script(src="js/jquery.mousewheel.js") + script(src="js/stuffs.js")
    + + + +
    +

    + W3C + +

    + +
    + + + +
    +
    + +
    + + +
    +
    + +
    + + +
    +
    +
    + +
    +
    +

    W3C Software Notice and License

    +
    +
    +

    This work (and included software, documentation such as READMEs, or other +related items) is being provided by the copyright holders under the following +license.

    +

    License

    + +

    +By obtaining, using and/or copying this work, you (the licensee) +agree that you have read, understood, and will comply with the following +terms and conditions.

    + +

    Permission to copy, modify, and distribute this software and its +documentation, with or without modification, for any purpose and without +fee or royalty is hereby granted, provided that you include the following on +ALL copies of the software and documentation or portions thereof, including +modifications:

    + +
    • The full text of this NOTICE in a location viewable to users of the + redistributed or derivative work.
    • Any pre-existing intellectual property disclaimers, notices, or terms + and conditions. If none exist, the W3C Software Short + Notice should be included (hypertext is preferred, text is permitted) + within the body of any redistributed or derivative code.
    • Notice of any changes or modifications to the files, including the date + changes were made. (We recommend you provide URIs to the location from + which the code is derived.)
    + +

    Disclaimers

    + +

    THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS +MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR +PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE +ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.

    + +

    COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR +DOCUMENTATION.

    + +

    The name and trademarks of copyright holders may NOT be used in +advertising or publicity pertaining to the software without specific, written +prior permission. Title to copyright in this software and any associated +documentation will at all times remain with copyright holders.

    + +

    Notes

    + +

    This version: http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231

    + +

    This formulation of W3C's notice and license became active on December 31 +2002. This version removes the copyright ownership notice such that this +license can be used with materials other than those owned by the W3C, +reflects that ERCIM is now a host of the W3C, includes references to this +specific dated version of the license, and removes the ambiguous grant of +"use". Otherwise, this version is the same as the previous +version and is written so as to preserve the Free +Software Foundation's assessment of GPL compatibility and OSI's certification +under the Open Source +Definition.

    +
    +
    +
    +
    + + + +